首页 > 其他分享 >深入理解指针【1】--(不一样的理解!!!)

深入理解指针【1】--(不一样的理解!!!)

时间:2024-08-23 18:26:42浏览次数:10  
标签:变量 -- int 地址 理解 内存 printf 指针

本章概述

内存和地址

在讲解指针之前,我们先讲一下内存和地址,为后面的指针讲解进行铺垫。

  • 内存:对于内存,我相信大家都不陌生。我们买电脑或者手机时都会关注它本身的内存大小,电脑中常见的内存大小8G/16G/32G等。内存很珍贵,容量越大价格也越贵,它的容量可没有1T这样的说法,1T这里只有硬盘才有的容量。大家要把内存和硬盘区分开,对于区分不开的人,可点击链接:内存和硬盘的区别
  • 内存的形象化理解内存就像学校的宿舍楼一样,宿舍楼里有很多分好的房间,而且每个房间你都可以住人,或者存放东西。内存也是一样,它也是被划分了很多小的空间,这些空间就跟房间一样,它里面可存放数据。我们都知道,房间有大小,存放的东西是有限制的。内存也是一样,它里面的每个空间都是有范围的,每个空间为一个字节的容量。 总结:内存被划分为很多的单元,每个单元为一个字节的容量,内存的存储容量单位为字节。如图所示:在这里插入图片描述
    在这里我们讲一下数据存储的单位和大小
1 byte = 8 bit
1 kb = 1024 bye
1 mb = 1024 kb
1 gb = 1024 mb
1 tb = 1024 gb
1 pb = 1024 tb
  • 地址:我们讲过了,内存就像一栋宿舍楼,一栋宿舍楼里面有很多的房间(寝室),而且每个寝室都有门牌号。如图所示:在这里插入图片描述
    当我们的朋友过来找我们玩的时候,假如每个寝室没有门牌号,他就需要一个一个房间的找,只有那样做才能最终找到你。虽然那也是一种方法,但是很不高效。但当我们有了门牌号,他就可以很迅速的找到你。内存也是如此,内存被划分为很多的一个一个的小单元,每个小单元都被进行了编码,这些编码就是门牌号,就是地址,而在C语言中给起了个新名字——指针。 所以,编码== 地址 ==指针内存通过这些门牌号(指针),对里面的空间单元进行数据的访问
  • 内存地址的理解:我们都知道,CPU(中央处理器)是数据处理的中心,跟我们的大脑一样。它从内存内读取数据,进行大量的运算(处理),然后把处理后的数据 (处理后的结果)再放回内存中。如图所示:在这里插入图片描述
    对内存进行数据的访问时,就要知道每个空间单元的地址。我们都知道,我们寝室门口会标注门牌号,以便被看到。但在内存中可不是这样被标注的。计算机是由很多个硬件组成的, 比如,在计算机里面有很多的电线,电子零件等。内存的地址就是由硬件设计的,它不会像门牌号那样进行标注,是由地址总线这个硬件设计好的。如图所示:在这里插入图片描述
    在CPU与内存之间有地址总线,数据总线控制总线组成。地址总线就是一根一根电线,每根数据线连接一个比特位。我们知道每个比特位储存0或1,也就是说每根地址线会向所对应的比特位,发0或1,也就是说每根线有两种状态(结果),即0或1。所以,两根线就是四种状态(结果),三根线就是八种状态(结果)……。地址总线的个数由计算机平台决定,在32位计算机中就有32根线,就有2的32次方状态(结果),在64位计算机中就有64根线,就有2的64次方状态(结果)。一台电脑生产好后,它里面的内存地址就已经通过地址总线这个硬件设计好了。就跟我们弹钢琴一样,钢琴的每个键上面并没有标注 ,do,re,mi,……si这些音符,但是每个键都对应一个音,就是因为在生产钢琴的时候,每个键对应什么音就已经设计好了。当CPU要处理某个空间单元的数据是,它就会先通过控制总线,通知内存它要读取数据了,然后再通过地址总线,向内存发送要读取的空间单元的地址,然后内存就会根据地址找到对应的空间单元,再把里面的数据通过数据总线传给CPU总结:编码 == 地址 == 指针

指针的应用

指针在计算机科学中具有广泛的应用。以下是一些常见的应用场景:

  • 内存管理:指针可用于动态分配释放内存。通过指针,可以在运行时分配和管理内存,使程序更加灵活和高效。

  • 数据结构:指针是实现各种数据结构(如链表、树、图等)的基本工具。通过指针,可以在内存中动态创建操作数据结构,实现高效的数据访问和操作。

  • 函数指针:函数指针是指向函数的指针变量,可用于在运行时动态选择和调用不同的函数。函数指针广泛用于实现回调机制事件处理动态加载等场景。

  • 数组访问:通过指针,可以直接访问和操作数组元素,提高数组访问的效率。

  • 字符串处理:指针可用于字符串的操作,如拷贝、连接、比较等。通过指针,可以对字符串进行高效的处理和操作。

  • 系统级编程:在操作系统底层编程中,指针是必不可少的工具。通过指针,可以直接访问硬件、进行内存映射、优化性能等。

  • 动态数据结构指针可用于实现动态数据结构,如动态栈、堆等。通过指针,可以在运行时分配和释放动态数据结构,提高程序的灵活性和效率

指针变量和地址

在了解完什么是内存,什么是指针(地址)后,我们回归C语言中。在以前的文章中,我们有讲过——变量的创建本质就是向内存申请空间。既然申请了空间,那就肯定有地址,所以怎样获取我们的变量地址呢?

  • &取地址操作符: 这个符号咱们前面也见过了,格式 :& 变量。进行代码展示:
创建一个变量,并用 & 取出变量的地址。
#define  _CRT_SECURE_NO_WARNINGS	1
#include <stdio.h>
int main()
{
	int a = 10;
	printf("%p\n", &a);
	return 0;
}

结果运行图:
在这里插入图片描述

  • 指针变量:前面,咱们讲过数据类型,比如,int , char ……指针变量也是个变量是专门用来存放指针(地址)的变量。竟然是变量,那就有数据类型,那么指针变量的数据类型是什么样的呢? 就是在数据类型后面加个* 比如,int * , char *,……。进行代码展示:
//  格式  : 数据类型  *  变量名  ;
int a = 10 ;
int * p = &a ;			//p里面存放的就是 a 的地址
#define  _CRT_SECURE_NO_WARNINGS	1
#include <stdio.h>
int main()
{
	int a = 10;
	int* p = &a;
	printf("%p\n",p );
	return 0;
}

结果运算图:在这里插入图片描述
有个东西忘了告诉大家了——对于地址的打印用占位符%p。从结果运行图中能看出来,指针存放的就是变量的地址。同理,比如,char *……。大家可以自行试试。

  • 指针变量的大小:前面,我们有讲过,数据类型是有大小的,也就是因为有了大小,才会申请不同的空间。对于空间大小的测量,我们用sizeof测量(前面有讲过),进行代码展示:
#define  _CRT_SECURE_NO_WARNINGS	1
#include <stdio.h>
int main()
{
	printf("%d\n", sizeof(int*));
	printf("%d\n", sizeof(char*));
	printf("%d\n", sizeof(float*));
	printf("%d\n", sizeof(double*));
	return 0;
}

结果运行图:在这里插入图片描述
从结果运行图来看,不知道你有没有感到惊讶。不同的指针变量,它们的空间大小竟然相同!!!是不是感到很惊讶——它们占有的空间相同。我们先说结论:指针变量的大小与它的类型无关,只与所在的计算机平台有关,即,32位平台上占有4个字节,64位平台上占有8个字节。 接下来,我们进行解释:前面,我们讲过了地址总线,它的数据线数有计算机平台决定,它的每一根线都对应一个bit位,一个字节有8个bit,所以在32位的平台下就对应4个字节,在64位平台下对应8个字节。肯定有人有疑问——既然都一样,那为什么还要规定那么多指针数据类型呢?规定一个不就行了吗?。对于这个问题的解答,我们就要知道指针变量的真正含义,我们接下来讲。

  • 指针变量的解读:我们以整形指针变量为例子,比如,int a = 10 ;int * p = &a *号就说明了 p是个指针变量int 就说明了p所指变量a 里面的数据类型是个整形,指针变量存放的是地址,我们通过地址找到变量a里面的数据,就可以对其内容进行更改(就像根据门牌号找到了对应的房间,我们可拿或放入东西)。总结:指针变量就是通过地址找到对应的变量数据。如图所示:在这里插入图片描述
    接下来,我们通过代码进行展示:
// 创建一个变量,不通过直接更改内容,用指针进行更改。
#define  _CRT_SECURE_NO_WARNINGS	1
#include <stdio.h>
int main()
{
	int a = 10;
	printf("更改前a=%d\n", a);
	int* p = &a;
	*p = 30;
	printf("更改后a=%d\n", a);
	return 0;
}

结果运行图:在这里插入图片描述

  • 解引用操作符*就是解引用操作符p里面存放的是地址,我们通过*这个操作符对p里面的地址解读(通过 *和p里面的地址就找到了a里面的数据,就可以进行更改)。也就是说, * p==10。进行代码展示:
#define  _CRT_SECURE_NO_WARNINGS	1
#include <stdio.h>
int main()
{
	int a = 10;
	int* p = &a;
	printf("a=%d\n", *p);
	return 0;
}

结果运行图:在这里插入图片描述
补充个知识点,地址的表示是十六进制,对于代码的研究具有可观性(后面就会体会到)地址的十六位进制表示,总共有8位活32位(由计算机平台决定),比如,0X00AFF9F4。因为在32位平台上,总共有32根线,一个十六进制位,可由4个bit位表示,所以只要8个十六进制位就OK了,依此推理64位平台。读到这里,我想有些人肯定有疑惑——对a的值进行更改,我们完全可以直接写成a = 30 ;为什么还费事的要用指针呢?其实,对于某个变量进行值的更改,通过直接更改是一种手段,通过指针进行更改是另一种手段。这两东西就相当于我们的工具,工具多了,我们解决问题的方法就多了。其实,通过指针进行变量的更改是很方便的,这个特征我们以后就会感受到的。

指针变量类型的意义

前面,我们已经讲过了,指针变量的大小与指针变量类型无关,只与计算机平台有关。这里我们就来讲一下,为什么要有那么多指针变量。这里我们直接说结论:指针变量的类型决定了能访问的空间大小。比如,int * 能访问4个字节空间,char *能访问1个字节空间。进行代码展示:

#define  _CRT_SECURE_NO_WARNINGS	1
#include <stdio.h>
int main()
{
	int a = 0x11223344;
	int* p = &a;
	*p = 0;
	printf("%d\n", a);
	return 0;
}

结果运行图:在这里插入图片描述

  • 指针变量+ -整数指针变量是能+ -整数的,想不到吧。我们直接上代码:
#define  _CRT_SECURE_NO_WARNINGS	1
#include<stdio.h>
int main()
{
	int a = 10;
	int* p = &a;
	char* pc = (char*)&a;
	printf("  p=%p\n", p);
	printf("p+1=%p\n", p+1);

	printf("  pc=%p\n", pc);
	printf("pc+1=%p\n", pc + 1);

	return 0;
}

结果运行图:在这里插入图片描述
从结果运行图中,我们可以看出来,int *的指针变量对应的p当p+1时,地址就加了4个字节,char *的指针变量对应的pc,当pc+1时,地址就加了1个字节所以不同的指针变量类型,对应着指针变量加减时,在地址上加减多少个字节指针变量不只是可以加减1,可以加减任意数字。地址加多少就等于数字乘以对应的变量类型对应的字节

const修饰指针-1

const的单词意思:常量,常属性在普通常量中(除了指针变量):被const修饰的变量是无法进行更改的,被const修饰的变量被称为常变量在C语言中,被const修饰的变量本质还是变量,只不过语法上规定它不可以进行更改,就跟常量似的但在C++中,被const修饰的变量,它的本质就被改变了,就变成了常量。进行代码展示:

#define  _CRT_SECURE_NO_WARNINGS	1
#include <stdio.h>
int main()
{
	int a = 10;
	  a = 30;
	printf("%d\n", a);
	return 0;
}

结果运行图:在这里插入图片描述
代码展示2:

#define  _CRT_SECURE_NO_WARNINGS	1
#include <stdio.h>
int main()
{
	const int a = 10;
	  a = 30;
	printf("%d\n", a);
	return 0;
}

结果运行图:在这里插入图片描述
在C语言中,const修饰的普通变量的特性是可以用变长数组来验证的。进行展示:

#define  _CRT_SECURE_NO_WARNINGS	1
#include <stdio.h>
int main()
{
	int a = 10;
	int arr[a];
	return 0;
}

结果运行图:在这里插入图片描述
代码展示2;

#define  _CRT_SECURE_NO_WARNINGS	1
#include <stdio.h>
int main()
{
	const int a = 10;
	int arr[a];
	return 0;
}

结果运行图:在这里插入图片描述

void * 指针变量

前面,我们讲过了,每个数据的变量类型都有相对应的指针变量类型。我们自己写代码,我们大概率不会乱用指针变量,或者我们自己清楚自己用了什么指针变量。但当我们接过来别人的代码后,对于别人所使用的指针变量类型可能不太清楚,这个时候就可以用 void *这个指针变量来接收。void 就是空,无的意思对于什么样的指针变量类型都能接收。进行代码展示:

#define  _CRT_SECURE_NO_WARNINGS	1
#include <stdio.h>
int main()
{
	int a = 10;
	char* d = "abbb";
	void* p = &a;
	void* b = &d;
	return 0;
}

结果运行图:在这里插入图片描述
大家要注意下,void * 所修饰的指针变量是不能直接被 *操作的。因为,void *什么指针变量类型都接收,所以它不能确定你要哪个,必须进行类型转换才能进行*。进行代码展示:

#define  _CRT_SECURE_NO_WARNINGS	1
#include <stdio.h>
int main()
{
	int a = 10;
	void* p = &a;
	*p = 40;
	printf("%d\n", a);
	return 0;
}

结果运行图:在这里插入图片描述
代码展示2:

#define  _CRT_SECURE_NO_WARNINGS	1
#include <stdio.h>
int main()
{
	int a = 10;
	void* p = &a;
	*(int*)p = 40;
	printf("%d\n", a);
	return 0;
}

结果运行图:在这里插入图片描述

每章的彩蛋时刻!!!

https://www.bilibili.com/video/BV1LU4y1S7Ni/?spm_id_from=333.337.search-card.all.click&vd_source=7d0d6d43e38f977d947fffdf92c1dfad在这里插入图片描述
每章一句“在任何一个你没有察觉的时刻,包括现在,通过行动去改变命运的机会,一直都在。”感谢你能看到这里,点赞+关注+收藏是对我的最大鼓励,咱们下期见!!!

标签:变量,--,int,地址,理解,内存,printf,指针
From: https://blog.csdn.net/2401_83009236/article/details/141354096

相关文章

  • 你每天的销售数据日报需要多少时间处理?如果有办法能30秒出报表,你怎么选?
    每天的销量数据的获取对于品牌连锁企业来说,是商品管理部门、营运部门同事或者企业领导每天早上的必做事情之一。因此,对于如何准确,快速,低代价的获取销量信息,是一门艺术。据观察了解,目前来说各企业获取每日销量数据的方式参差不齐,大致来说主要分为两类:①、每日销量由各门店手工......
  • [Paper Reading] Egocentric Whole-Body Motion Capture with FisheyeViT and Diffusi
    EgocentricWhole-BodyMotionCapturewithFisheyeViTandDiffusion-BasedMotionRefinementlink时间:CVPR2024机构:马普所&SaarlandInformaticsCampus&Google&UniversityofPennsylvaniaTL;DR使用第一人称RGB单目鱼眼相机进行全身动捕的算法,融合了FisheyeVit&3......
  • 代码实现WordPress主动推送及自动推送至百度搜索收录
    站长们辛辛苦苦写的文章,无非就是让百度收录,也可以帮助人,也可以给自己站或者帮人优化的站带来流量,今天就来发一篇关于wordprss主动推送给百度的方法;使用方法,U8格式放在wp当前模板functions.php里即可12345678910111213141516171819202122232425262......
  • Docker安装Nginx
    第一步:拉取镜像可指定版本,也可不写,则为默认最新版本第二步:拷贝配置文件首先运行容器dockerrun-d--namenginx-p8082:8082nginx然后复制配置文件到宿主机文件夹,此处的宿主文件夹为自己手动创建,即为D:/usr/nginx/conf#将容器nginx.conf文件复制到宿主机dock......
  • 回归预测|基于卷积神经网络-长短期记忆网络-自注意力机制的数据回归预测Python程序 多
    回归预测|基于卷积神经网络-长短期记忆网络-自注意力机制的数据回归预测Python程序多特征输入单输出CNN-LSTM-Attention文章目录前言回归预测|基于卷积神经网络-长短期记忆网络-自注意力机制的数据回归预测Python程序多特征输入单输出CNN-LSTM-Attention一、CNN-......
  • 回归预测|基于北方苍鹰优化-卷积神经网络-双向长短期记忆网络-自注意力机制的数据回归
    **回归预测|基于北方苍鹰优化-卷积神经网络-双向长短期记忆网络-自注意力机制的数据回归预测Matlab程序多特征输入单输出含基础模型NGO-CNN-BiLSTM-Attention**文章目录前言回归预测|基于北方苍鹰优化-卷积神经网络-双向长短期记忆网络-自注意力机制的数据回归预测M......
  • 回归预测|基于NGO-TCN-BiGRU-Attention的数据预测Matlab程序 多特征输入单输出 含基础
    回归预测|基于NGO-TCN-BiGRU-Attention的数据预测Matlab程序多特征输入单输出含基础模型文章目录前言回归预测|基于NGO-TCN-BiGRU-Attention的数据预测Matlab程序多特征输入单输出含基础模型一、NGO-TCN-BiGRU-Attention模型NGO-TCN-BiGRU-Attention模型详细流......
  • STM32常用下载程序方式
    常用下载程序的两种方式:、通过下载工具(FlyMCU)将hex文件下载到FLASH存储区。、使用烧写器将xxx.axf文件下载到存储区。(KEIL5经过烧写器配置后,直接点击download)有的朋友肯定好奇说:FLASH存储区存的都是最“干净”的二进制数据,hex文件还有那么多描述信息呢。答案:hex文件当然不是......
  • 【ARM 芯片 安全与攻击 5.2.1 -- 侧信道与隐蔽信道的区别】
    文章目录侧信道与隐蔽信道的区别侧信道攻击(Side-channelAttack)侧信道攻击简介侧信道攻击使用方法侧信道攻击示例隐蔽信道(CovertChannel)隐蔽信道简介隐蔽信道使用方法代码示例侧信道的应用隐蔽信道的应用Summary侧信道与隐蔽信道的区......
  • STM32/ARM-M系列 如何用C语言指针操作寄存器 上篇
    1、操作外设实际上就是操作寄存器使用STM32进行编程,我们一般是用官方提供的库函数(HAL库)来操作各种外设。本质上,每个外设都有自己的一组外设寄存器,操作外设就是操作各种外设寄存器。HAL库的各个库函数就是对他们的寄存器操作的高度抽象后的封装。打开stm32f10x的数据手册的地址......