指针,看似是一个令人头疼的问题,静下心来慢慢学习。指针这个主题,分成了几个的板块,比较多,耐心看完,一定会有收获啦!慢慢来,总是需要一个循序渐进的过程。
目录
一、什么是指针
把指针想象成是一个房间号,简单的想一下,在一个风和日丽的早晨,你去了一家偌大的宾馆,你第一次去,找不到对应的房间,而那些房间从外面看起来,真的就是一摸一样。而这个时候,你该怎么办呢?宾馆的房间号在这时候是不是就起作用了。
而内存呢,也是类似于这样的,将内存空间切割为一个个小的内存单元,并对其进行编号。其编号就是地址,也称为指针。
1、指针就是地址,是内存中一个最小单元的编号
2、口语中的指针其实指的是指针变量,是用来存放内存地址的变量
3、指针变量里面存放的是地址,而通过这个地址,就可以找到一个内存单元
4、指针的大小:在32位平台是4个字节,64位平台是8个字节(x86-->32位环境,x64-->64位环境)
理解过程:内存空间是如何管理的?
(1)、切割成内存单元,每个内存单元为1个byte(字节)
(2)、给每个内存单元进行编号(编号的意义:能够快速找到指定的内存单元),把内存单元的编号称为地址
(3)、指针就是地址,地址就是编号,即:指针就是内存单元的编号
分析如下代码:
#include<stdio.h>
int main()
{
int a = 0;
int* p = &a;
return 0;
}
上述代码的理解:
(1)、a是整型变量,占用4个字节的内存空间,如图:
注:(A、内存单元的编号,是当程序执行时,直接有硬件生成的,所以每一次运行,其编号都是不一样的。
(B、&a——就是通过取地址操作操作符,取出a的地址,所以,&a就是代表a的编号,即:&a就是a的地址
(2)、int* p=a;
p是一个指针变量,用来存放地址的(用来存放指针的),而通过这个地址,就可以找到相应的一个内存单元。
注:再次强调,口语中会说,p就是一个指针,实际上指的是p是一个指针变量,而指针变量就是一个变量,用来存放地址的一个变量。
分析如下代码:
int main()
{
int* p = NULL;
char* l = NULL;
double* d = NULL;
//printf("%d\n", sizeof(p));
//printf("%d\n", sizeof(int*));
//printf("%d\n", sizeof(char*));
//printf("%d\n", sizeof(double*));
printf("%zu\n", sizeof(p));
printf("%zu\n", sizeof(int*));
printf("%zuh\n", sizeof(char*));
printf("%zu\n", sizeof(double*));
return 0;
}
我这里用的在x64的环境下,所以输出都是8。在这里有一个小小的细节,我们没有使用%d的形式打印,而是zu,原因:sizeof返回值的类型为无符号整型-->unsigned int---->所以上面用%d打印会有警告。在这里也再次验证了,指针的大小只与平台有关。
二、指针和指针类型
指针类型的意义:
结合下面代码分析:
代码1:
#include<stdio.h>
int main()
{
int a = 0x11223344;
int* pa = &a;
*pa = 0;//改变了4个字节
printf("%d\n", *pa);
return 0;
}
分析:
1、0x开头的是十六进制数,两个十六进制数代表一个字节,因为一个十六进制位能翻译为4个二进制位,2个就是8个二进制位,8个二进制数就是一个字节,因此2个十六进制数对应1个字节。
2、存放0x11223344需要4个字节,而int a刚好就是4个字节的空间。在调试中,去内存里面查看&a,就可以观察到,已经存放进去了,至于为什么是倒着存进去的,这里先不深究。
3、当调试走到*pa=0;时观察内存&a的值就变成了如下:
是将4个字节都改变成了00
代码2:
#include<stdio.h>
int main()
{
int a=0x11223344;
char* pc1 = &a;//int* 和char* 类型不兼容
char* pc = (char*)&a;//所以在这里要进行强制类型转换
*pa = 0;//只改变了一个字节,因为是char* 类型的
printf("%d\n", *pc);
return 0;
}
分析:
1、在调试中,去内存里面查看&a,就可以观察到,已经存放进去了。(每次程序运行时,分配的地址都是随机的,所以这里的&a的地址编码和代码1中的编码不同)
2、char*是可以存放int*的地址,差异在于取出使用时会有差异
3、当调试走到*pa=0后,在走一步,会发现如下结果:
在这里只改变了第一个字节的值
结论1:
结合代码1、2,我们发现,指针变量类型的不同不会影响指针所占空间的大小。
指针类型决定了指针在被解引用的时候访问几个字节。
如果是int*的指针,解引用访问4个字节
如果是char*的指针,解引用访问1个字节
推广:
如果是double*的指针,解引用访问8个字节
代码2:
#include<stdio.h>
int main()
{
int a = 0x11223344;
int* pa = &a;
char* pc = (char*)&a;
printf("pa =%p\n", pa);
printf("pc =%p\n", pc);
printf("\npa =%p\n", pa);
printf("pa+1=%p\n", pa + 1);
printf("\npc =%p\n", pc);
printf("pc+1=%p\n", pc + 1);
return 0;
}
运行结果:
分析:
1、char*是可以存放int*的地址的
2、计算pa+1是加了4个字节,而计算pc+1时,加了1个字节
结论2:
指针的类型决定了指针+-1操作时,跳过几个字节
决定了指针的步长
误区:
虽然float*和int*的权限看似一样,但并不意味着 float*和 int*能通用
因为不同的类型,看待数据的视角不同。int* 看待的是整型的数据,而float*看待的是浮点型的数据。例:
代码:
int main()
{
int a = 0;
int* pi = &a;//pi解引用访问4个字节,pi+1也是跳过4个字节
float* pf = &a;//pf解引用访问4个字节,pf+1也是跳过4个字节
*pi = 100;
return 0;
}
打开调试,查看内存中&a,如下:
100的十六进制就是64
代码:
int main()
{
int a = 0;
int* pi = &a;//pi解引用访问4个字节,pi+1也是跳过4个字节
float* pf = &a;//pf解引用访问4个字节,pf+1也是跳过4个字节
//*pi = 100;
*pf = 100;
return 0;
}
打开调试,查看内存中&a,如下:
int*以整型数据存储方式去存储的 , float* 是以浮点数据存储方式去存储的 ,二者在存储时其规则是不同的,所以存储时的值会有差异,所以,二者是不能混用的。
指针这个主题会持续更新的喔,慢慢看。
如有不对的地方,还望大佬指出!