1. 指针是什么
1.指针是内存中一个最小单元的编号
2.指针变量,即存放地址的指针
如int类型占4个字节,对应四个地址,取首个地址存放
指针就是地址,平常说的指针是指针变量
内存地址图
那么最小单元是多大呢?
在32位平台下,假设有32根地址线,每条线通过产生高/低电压传输信号1/0,那么一共有2^32个地址。人们规定一个地址标识一个字节,那么我们可以给4G的空间进行编址。(2^32Byte == 2^32/1024KB == 2^32/1024/1024MB == 2^32/1024/1024/1024GB == 4GB)
32/64位,这里的位指的是CPU生成的一个地址由多少个bit位组成(32/64个0/1组成的 二进制序列)。以32位为例:假设一个地址为0x0012ff40,0x表示十六进制,2个16进制位为一个字节,即这个地址占4个字节。64位的地址,一个16进制位就为一个字节,即占8个字节。
所以指针变量所占空间和机器系统位数有关
32/64位平台是4/8个字节
2. 指针和指针类型
一个疑问
在相同系统中,既然指针所占内存大小都一样,为什么还要规定那么多类型呢?
下面尝试用int类型和char类型指针分别处理int类型数据
定义一个整型变量a储存一个4个字节的数字,用两种类型的指针使它的值改变为0,看看结果如何
#include<stdio.h> int main() { int a = 0x0012ff40; int* pa = &a; //char* pa = &a; *pa = 0; return 0; }
结果与我们预想的一样,这个4个字节的数字被改变成了0
换成char类型指针进行同样的操作是否会得到同样的结果呢?
#include<stdio.h> int main() { int a = 0x0012ff40; int* pa = &a; //char* pa = &a; *pa = 0; return 0; }
结果从0x12ff40变成了0x12ff00,只改变了两个数字,也就是改变了一个字节,这与char类型变量所占内存的大小是对应的
由此我们得到结论:
指针类型即看待内存的视角,指向int的指针,操作数据的最小单位就是4个字节;指向char类型的指针,操作数据的最小单位就是1个字节。
指针类型决定着指针被解引用时访问的权限,也就是它决定指针移动的单位距离,这便是指针类型不同存在的意义。
3. 指针运算
指针+- 整数
指针-指针
指针的关系运算
3.1 指针+-整数
指针+-整数,如
int a = 0; int* pa = &a; *pa++;
这里++的优先级大于*,所以地址先移动,然后再解引用。通过使用括号或者其他形式实现对地址不同的操作
3.2 指针 - 指针
下面我将a的首地址赋给pa,然后将pa的值+3,打印两个地址之差
#include<stdio.h> int main() { int a[5] = { 0 }; int* pa = a; pa += 3; printf("%d\n", pa - a); return 0; }
地址之差不是地址,而是之间元素的个数
严格地讲,只要当指针指向指向同一空间时,指针之差的绝对值==指针之间元素个素
3.3 指针关系运算
指针是能够进行比较的,也就是说地址是有大小关系的
for(int* pa = &a; pa < &b; pa++) { exp }
标准规定:允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较,但是不允许与指向第一个元素之前的那个内存位置的指针进行比较。
如何理解?
int a[20] = {0}; for(int * pa = &a[19]; pa >= &a[0]; pa--) { exp }
4. 指针和数组
指针和数组不是一回事
数组是一块连续的内存,它存放一组相同类型的变量
指针是存放地址的变量(大多数情况而言)
但我们可以通过操作指针访问数组
#include <stdio.h> int main() { int arr[] = {1,2,3,4,5,6,7,8,9,0}; int *p = arr; //指针存放数组首元素的地址 int sz = sizeof(arr)/sizeof(arr[0]); for(int i=0; i<sz; i++) { printf("&arr[%d] = %p <====> p+%d = %p\n", i, &arr[i], i, p+i); } return 0; }
一个易混点:
数组首元素地址和数组名的地址
通过打印地址+1,发现数组名+1后,地址加了一整个数组的地址
5. 二级指针
指针存放地址,它是变量,变量也有地址,那用什么存放指针的地址呢?这就是二级指针。
如何理解*
int* pa = &a; int* * ppa = &pa;
紧挨着变量名的*表示它是指针,其他*与类型名视作整体,表示指向对象的类型
二级指针的解引用
如何理解?
一个抽屉放着另外一个抽屉的钥匙,两层解引用即访问内层内存。
int a = 1; int* pa = &a; int* * ppa = &pa; //解引用 *(ppa)
6. 指针数组
指针数组即存放地址的数组。
int* arr3[5];
ex1
int a = 0,…; int* b[10] = {&a…};
ex2
它可以模拟实现二维数组