指针的类型声明
在声明指针时,必须要用到*
符号来标记。比如:int * p
,char *p[2][3]
,int (*p)[3]
,这些指针的类型该如何理解?
首先,声明语句的写法:type *name
,type是指针所指向数据的类型,name是指针自身的名字。
其次,声明语句中各符号的优先级:()>[]>*
。
因此,我们逐个分析:
int *p,p是一个指向int类型数据的指针。
char *p[2][3],由于[]优先级高于*,所以p是一个2*3的数组,数组中每一个元素都是char *类型的。
int (*p)[3],由于()优先级最高,所以p是一个指针,指向了int[3]型的数据。
指针的运算规则
首先要理解指针的本质:指针就是一个地址。因此当p是一个指针的时候,假设p的地址为0xfffff0,且指向int型数据,那么p+1就不是0xfffff1,而是0xfffff0+sizeof(int)=0xfffff4。
也就是说,对于一个type *p
的指针,p + k = (void*)p + k * sizeof(type)
,也就是说,指针的运算是以sizeof(type)为步长的。而减法同理,p1-p2 = ((void*)p1-(void*)p2)/sizeof(type)
。
指针的引用和解引用
关于指针共有两种操作,引用和解引用,运算符分别为*
和&
,*p
就是把p这个指针指向的内容拿出来,&i
就是把i
这个变量的地址给出来。因此对于某个变量,比如int i;
,就有*&*&...*&i == i
。
综合例题
有 A 的定义:int A[3][2] = {{1,2},{3,3},{2,1}};
那么 A[2]的值为:
A. &A+16 B. A+16 C. *A+4 D. *A+2
分析:
设A的地址为x,则A[2]即为x+16,下面只用考虑哪个满足即可。
A. 令p=&A,则p的类型是int (*)[3][2]
,p指向的数据类型为一个3*2的数组int [3][2]
,因此运算的步长为sizeof(int[3][2])
,另外,A作为一个数组,A的地址就是A的第一个元素的位置,同时也是A本身。故&A+16=x+16*(3*2*4)
,显然错误。
B. 令p=A,则p的类型是int [3][2]
,p是一个数组,且这个数组中每一个元素都是一个数组,所以A+16=x+16*sizeof(A[0])
,显然错误。
C. *A
就是A[0]
,类型为int [2]
,因此*A+4=x+4*sizeof(int)=x+4*4
,对。
D. 分析过程同C,错误。