1、关于指针的声明
int *p;
int* p;
int * p;
int*p;
以上4种声明方式都是正确的,编译器不会在乎中间有多少个空格。
至于到底是选择哪种书写方式,只取决于代码的书写风格和侧重点。
同时声明多个指针可能会遇到错误:
int* p, p1; //p1可能不是指针,在后续的调用中会发生混乱
坚持一次只声明一个指针并在声明时顺便初始化,困扰我们的混淆之源就会随风逝去。
2、int*p是整型指针?
指针类型就是指针类型,没有“整型指针”这种说法。
' * '可以看作是指针类型的类型关键字,' *p '就是定义了一个指针p,数据所在的内存地址会被赋值给p,随后p就可以访问该地址的内容。但是访问长度是多少?以什么格式访问还不清楚。于是在' *p '前面加上int,就是告诉指针p,以int的格式访问,数据长度是32位等等。
所以,int * p;就是说,定义了一个指针p,指向一个int型数据。一旦p被赋值后,p存储的就是内存地址,而*p就是该地址所存放的内容。
3、指针赋值问题
正常情况下:
int a;
int * p = &a;
等价于:
int a;
int * p;
p = &a; //将a的地址赋值给p,而不是*p
因为p是指针,不能直接将a赋值给p,否则编译器会报错(a是数组除外):
int*p = a; //[Error] invalid conversion from 'int' to 'int*' [-fpermissive]
p = a; //[Error] invalid conversion from 'int' to 'int*' [-fpermissive]
但在有些实际应用中,我们需要将特定的内存地址直接赋值给指针。比如将数据unsigned char data通过I2C写入地址为0x40000110的MCU寄存器中:
unsigned char *reg = NULL; //创建一个指针
reg = (unsigned char *)0x40000110;
*reg = data;
由于直接将地址赋值给指针reg会报错,赋值的时候需要将0x40000110强制转换为指针所声明类型,即在地址前加上(unsigned char *)。
4、指针的打印
p是指针类型,存的是a的地址;*p表示a的内容
int a = 0;
int * p = &a; //p是指针类型,存的是a的地址;*p表示a的内容
printf("p指向的内存地址是%p,该地址存放的内容是%d", p, *p); //打印p指向的地址应使用说明符%p
5、空指针
空指针通常默认指向0,但在不同的系统中不一定。无法读取数据。
6、void * p
这个不一定是空指针。此时的p可以指向某个地址,但并没有告诉程序用何种方式来解释这片内存,无法直接进行读取内容操作。必须先转成其他类型的指针才能把内容解释出来。