深入了解指针11. 内存和地址内存是计算机上CPU中央处理器读取数据和存放数据的地方在日常购置电脑中我们可以看到有不同种类的内存如8GB、16GB、32GB等但如何高效地管理这些内存呢这就关系到内存的划分了内存被划分成一个个的内存单元每个内存单元的大小取1个字节。计算机中常见的单位补充一个比特位可以存储一个2进制的位1或者0其中每个内存单元相当于一间学生宿舍⼀个字节空间里面能放8个比特位就好比同学们住的八人间每个⼈是⼀个比特位。每个内存单元也都有一个编号这个编号就相当于宿舍的门牌号有了这个内存单元的编号CPU就可以快速找内存中找到所寻的内存空间。生后中我们把门牌号叫做地址在计算机中我们也把内存单元的编号称为地址。C语言中给地址起了新的名字指针。有这样的理解内存单元的编号 地址 指针2. 指针变量和地址2.1 取地址操作符是单目地址操作符我们在C语言中使用取出变量在内存中的起始地址。语法变量名即可得到该变量的内存地址。**2.2 指针变量和解引用操作符*2.2.1 指针变量当我们通过取地址操作符获得一个地址一串16进制的数值如0x006FFD70这个地址有时候是需要存储起来方便后面的程序使用。如何存储呢那我们就需要用到指针变量了。例如#includestdio.hintmain(){inta10;int*paa;//取出a的地址并存储到指针变量pa中return0;}指针变量也是一种变量这种变量就是用来存放地址的存放在指针变量中的值都会理解为地址。2.2.2 拆解指针类型看到2.2.1程序中的pa的类型int *inta10;int*paa;这里的pa左边写的是int **是在说明pa是指针变量而前面int是在说明pa指向的是整型int类型的对象。同样的如果有一个char类型的变量ch我们用char*来存放ch的地址charchw;pcch;2.2.3 解引用操作符在前面已经了解了如何取地址如何使用指针变量存地址既然指针能存那它肯定有被使用的时候那我们该如何使用呢这时候就要用到解引用操作符*。在生活中当外卖员拿到了地址指针就可以通过地址指针找到地址指针指向的地方对象。使用例子如下#includestdio.hintmain(){inta100;int*paa;*pa0;return0;}上面的代码中第七行使用了解引用操作符*pa的意思就是通过pa中存放的地址找到指向的空间pa其实就是a变量了所以pa0这个操作符是把a改成了0.2.3 指针变量的大小先在两个不同的平台32位和64位下运行下面这段代码#includestdio.h//指针变量的大小取决于地址的大小//32位平台下地址是32个bit位即4个字节//64位平台下地址是64个bit位即8个字节intmain(){printf(%zd\n,sizeof(char*));printf(%zd\n,sizeof(short*));printf(%zd\n,sizeof(int*));printf(%zd\n,sizeof(double*));return0;}x86环境下的输出结果x64环境下的输出结果结论32位平台下地址是32个bit位指针变量大小是4个字节64位平台下地址是64个bit位指针变量大小是8个字节指针变量的大小和类型是无关的只要指针类型的变量在相同的平台下大小都是相同的3. 指针变量类型的意义3.1 指针的解引用对比下面两段代码通过在调试过程中观察内存的变化。代码1#includestdio.hintmain(){intn0x11223344;int*pin;*pi0;return0;}代码2#includestdio.hintmain(){intn0x11223344;char*pi(char*)n;*pi0;return0;}调试后可以看到代码1会将n的4个字节全部改为0但是代码2只是将n的第⼀个字节改为0。**结论**指针的类型决定了对指针解引用的时候有多大的权限⼀次能操作几个字节。比如char*的指针解引⽤就只能访问⼀个字节而int*的指针的解引用就能访问四个字节。3.2 指针±整数先通过下面程序的调试观察地址的变化#includestdio.hintmain(){intn10;char*pc(char*)n;int*pin;printf(%p\n,n);printf(%p\n,pc);printf(%p\n,pc1);printf(%p\n,pi);printf(%p\n,pi1);return0;}代码的运行结果如下我们可以看出char*类型的指针变量1跳过1个字节int*类型的指针变量1跳过了4个字节。这就是指针变量的类型差异带来的变化。指针1其实跳过1个指针指向的元素。指针可以1那也可以-1。3.3 void指针*在指针类型中有⼀种特殊的类型是void *类型的可以理解为无具体类型的指针或者叫泛型指针这种类型的指针可以用来接受任意类型地址。但是也有局限性void *类型的不能直接进行指针的±整数和解引用的运算。举例#includestdio.hintmain(){inta10;void*paa;void*pca;*pa10;*pc0;return0;}VS编译代码的结果这里我们可以看到void*类型的指针可以接收不同类型的地址但是无法直接进行指针运算。那void*类型的指针到底有什么用呢一般void*类型的指针是使用在函数参数的部分用来接收不同类型数据的地址这样的设计可以实现泛型编程的效果使得⼀个函数来处理多种类型的数据。4. 指针运算指针的基本运算有三种分别是指针±整数指针-指针指针的关系运算4.1 指针±整数因为数组在内存中是连续存放的只要知道第⼀个元素的地址顺藤摸瓜就能找到后⾯的所有元素。intarr[10]{1,2,3,4,5,6,7,8,9,10};#includestdio.h//指针-整数intmain(){intarr[10]{1,2,3,4,5,6,7,8,9,10};int*parr[0];inti0;intszsizeof(arr)/sizeof(arr[0]);for(i0;isz;i){printf(%d ,*(pi));//pi 这里就是指针整数}return0;}输出结果为4.2 指针-指针//指针-指针#includestdio.hintmy_strlen(char*s){char*ps;while(*p!\0)p;returnp-s;}intmain(){printf(%d\n,my_strlen(abc));return0;}输出结果为4.3 指针的关系运算//指针的关系运算#includestdio.hintmain(){intarr[10]{1,2,3,4,5,6,7,8,9,10};int*parr[0];intszsizeof(arr)/sizeof(arr[0]);while(parrsz)//指针的大小比较{printf(%d ,*p);p;}return0;}输出结果为