1、什么是指针?
通俗来讲——指针就是变量,用来储存地址的变量。
2、指针数组 & 数组指针
指针数组:它是一个数组,数组里面每个元素都是指针,数组的大小由它元素的个数决定。
数组指针:它是一个指针,它指向一个数组,指针的大小永远都是4字节 。
(1)int *p1[10]
p1是指针数组,里面有10个元素,每个元素都是地址;
(2)int (*p2)[10]
p2是数组指针,这个指针指向一个有10个整型元素的数组。
两者区分:
①我们要知道“[ ]”的优先级比“ * ”的优先级高,p1先与“[ ]”先集合,这就构成了数组的结构,数组名是p1,里面存的元素的类型是 int *
②p2先和“ * ”结合,构成指针结构,指针名为p2,int和[10]共同表示指针的类型,p2指向的是具有10个整型元素的数组。
3、a和&a的区别
int main()
{
char a[5] = { 'a', 'b', 'c', 'd', 'e' };
char(*p1)[5] = &a;
char(*p2)[5] = a;
return 0;
}
p1和p2哪个是数组指针?
此处p1和p2都是数组指针,但最好采用p1这种写法。 因为a是代表数组首元素的地址,而&a才是代表整个数组的地址,两者的值是一样的,但所代表的意义是完全不同的。
4、地址强转
下面代码输出结果是多少?
int main()
{
int a[4] = { 1, 2, 3, 4 };
int *p1 = (int *)(&a + 1);
int *p2 = (int *)((int)a + 1);
printf("%x, %x", p1[-1], *p2);
return 0;
}
p1:把 &a+1的值强制转换成 int * 再赋值给p1,此时p1指向数组a尾元素的下一个int型元素。p1[-1]可以理解成 *(p1 - 1)。表示p1往前移动sizeof(int)个字节,所以输出0x4。
p2:(int)a + 1表示把a强转成整型数据,再加1则(int)a + 1就是元素a[0]的第二个字节的地址,然后再把这个地址强转为int * 类型赋值给p2,那*p2的值就是从元素a[0]的第二个字节开始的连续4字节的内容。
那么这连续4个字节内容是什么呢?这里就要区分大小端了,小端模式返回0x2000000;大端模式返回0x100。
注:
所谓的大端模式,就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。
所谓的小端模式,就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。
5、函数指针
函数指针还是一个指针,它指向的是一个函数,这个指针变量里存的是一个函数的地址。
char * ( *fun)(char *p1, char *p2);
这里定义了一个函数指针,指针名为fun,指向函数fun,这个函数的返回值类型是 char *,参数是char *p1, char *p2。
函数指针数组:
char * ( *pf)(char *p)这里定义了一个函数指针 pf,既然如此那把这个指针放到数组里,这就形成了一个函数指针数组:
char * ( * pf[10])(char *p)
①数组名:pf
②数组元素:10个指向函数的指针。
③每个指针指向一个函数
④函数的返回类型为指向字符的指针,参数为一个指向字符的指针。
函数指针数组的用途:转移表
函数指针数组指针:
函数指针数组指针就是一个指针, 这个指针指向一个数组,这个数组里存的是指向函数的指针。
char * ( * (*pf)[10]) (char * p)
①这里定义了一个函数指针数组指针,指针变量名是pf。
②指针指向一个有10个元素的数组。
③数组里存的都是指向函数的指针。
④ 这些指针每个都指向一些函数。
⑤指向的函数的返回值类型为指向字符的指针,参数为一个指向字符的指针。
记忆方法:
函数指针数组指针数组指针。
我们从右往左分析:
①指针:*pf
②数组指针:(* pf)[5]
③指针数组指针:(* (* pf) )[5]
④数组指针数组指针:( (* (* pf) )[5])[3]
⑤指针数组指针数组指针:( * ( (* (* pf) )[5]) )[3]
⑥函数指针数组指针数组指针:void * ( ( * ( (* (* pf) )[5]) )[3] ) ( )
分析(*(void(*)())0)()
①void(*)() 是一个函数指针类型,这个函数无参数,无返回值。
②(void(*)())0 把0强转成函数指针类型,0是一个函数的首地址。
③(*(void(*)())0) 把地址为0的函数取出来。
④(*(void(*)())0)(),函数调用。
网友评论