1.指针(变量)的类型
把指针声明语句里的指针名字去掉,剩下的部分就是这个指针的类型。这是指针本身所具有的类型。
(1)int*ptr; //指针的类型是 int*
(2) char*ptr;//指针的类型是 char*
(3) int**ptr;//指针的类型是 int**
(4) int(*ptr)[3];//指针的类型是 int(*)[3]
(5) int*(*ptr)[4];//指针的类型是 int*(*)[4]
2.指针所指向的类型
把指针声明语句中的指针名字和名字左边的指针声明符*去掉,剩下的就是指针所指向的类型。例如:
(1)int*ptr; //指针所指向的类型是int
(2)char*ptr; //指针所指向的的类型是 char
(3)int**ptr; //指针所指向的的类型是 int*
(4)int(*ptr)[3]; //指针所指向的的类型是 int()[3]
(5)int*(*ptr)[4]; //指针所指向的的类型是 int*()[4]
3.指针的值(指针所指向的内存地址)
指针的值是指针本身存储的数值,这个值将被编译器当作一个地址,而不是一个一般的数值。说一个指针指向了某块内存区域,则该指针的值就是这块内存区域的首地址。
每遇到一个指针,都应该问问:这个指针的类型是什么?指针指的类型是什么?该指针指向了哪里?
4.指针本身所占据的内存区
指针本身占了多大的内存?你只要用函数sizeof(指针的类型)测一下就知道了。在 32 位平台里,指针本身占据了 4 个字节的长度。
指针本身占据的内存这个概念在判断一个指针表达式(后面会解释)是否是左值时很有用。
5.分析(理解)指针
完全理解一个复杂类型其实也不难,一个类型里会出现很多运算符,他们也像普通的表达式一样,有优先级,其优先级和运算优先级一样,所以:从变量名处起,根据运算符优先级结合,一步一步分析。
int *p; // 一个返回整型数据的指针。P先与*结合,说明P是一个指针;再与int结合,说明指针所指向的内容为int型。
int p[3]; // 一个由整型数据组成的数组。P先与[]结合,说明P是一个数组;与int结合,说明数组里的元素是整型的。
int *p[3]; // 一个由返回整型数据的指针所组成的数组。P先与[]结合,所以P是一个数组;再与*结合,说明数组里的元素是指针类型;与int结合,说明指针所指向的内容类型是整型的。
int (*p)[3]; // 一个指向由整型数据组成的数组的指针。P先与*结合,说明P是一个指针;再与[]结合("()"只是为了改变优先级),说明指针所指向的内容是一个数组;与int结合,说明数组里的元素是整型。
int **p; // P是一个指针(它指向一个指向int数据的指针)。
int p(int); // 一个函数申明。P先与()结合,说明P是一个函数;然后进入()里分析,说明该函数有一个整型变量的参数;然后再与外面的int结合,说明函数的返回值是一个整型数据。
int (*p)(int); // 一个指向有一个整型参数且返回类型为整型的函数的指针。P先与*结合,说明P是一个指针;与()结合,说明指针指向的是一个函数;……
int *(*p(int))[3]; // 一个参数为一个整数且返回一个指向由整型指针变量组成的数组的指针变量的函数。P先与()结合,说明P是一个函数;然后进入()里面,与int结合,说明函数有一个整型变量参数;然后再与外面的*结合,说明函数返回的是一个指针;然后到最外面一层,先与[]结合,说明返回的指针指向的是一个数组,然后再与*结合,说明数组里的元素是指针,再与int结合,说明指针指向的内容是整型数据。