int main()
{
int a[4]={1,2,3,4};
int *ptr1=(int *)(&a+1); // &a得到的是数组的首地址,+1偏移一个数组大小,之后强转成int*类型指针
int *ptr2=(int *)((int)a+1); // 先强转成int型变量,再+1,之后强转成int*类型指针
printf("%x,%x",ptr1[-1],*ptr2);
// ptr1[-1]:*(ptr1-1) , 指针指向下一个数组中的1,然后向前偏移sizeof(int)字节,指针指向4,
ptr2指向第二个字节,*ptr2为第二个字节开始的连续4个字节内的内容。
return 0;
}
二维数组
int a[5][5]; // 数组里存放数组
int (*p)[4]; // 指向拥有4个元素的数组的指针
p = a;
问&p[4][2] - &a[4][2]的值为多少?
a[0][0] 偏移4*sizeof(a[0])得到a[4][0],再偏移2*sizeof(int)得到a[4][2],
所以&a[4][2] = &a[0][0] + 4*sizeof(a[0]) + 2*sizeof(int);
p指向一个有4个元素数组,p[4] = p + 4, 也就是偏移了4*(4*sizeof(int)),4个数组的大小,p[4][2]偏移了2*sizeof(int),p被初始化为a[0][0];
所以,&p[4][2] = &a[0][0] + 4*(4*sizeof(int)) + 2*sizeof(int);
相减得到偏移量,4个int类型的元素。所以答案为-4
数组参数 | 等效的指针参数 |
数组的数组:char a[3][4] | 数组的指针:char (*p)[10] |
指针数组: char *a[5] | 指针的指针:char **p |
这里需要注意的是:C 语言中,当一维数组作为函数参数的时候,编译器总是把它解析
成一个指向其首元素首地址的指针。这条规则并不是递归的,也就是说只有一维数组才是
如此,当数组超过一维时,将第一维改写为指向数组首元素首地址的指针之后,后面的维
再也不可改写。比如:a[3][4][5]作为参数时可以被改写为(*p)[4][5]。
函数指针:
Eg1:
void Function()
{
printf("Call Function!\n");
}
intmain()
{
void (*p)();
*(int*)&p=(int)Function; // 表示将函数的入口地址赋值给指针变量p。
(*p) ();
return 0;
}
Eg2:
(*(void(*) ())0)();
第一步:void(*) (),可以明白这是一个函数指针类型。这个函数没有参数,没有返回值。
第二步:(void(*) ())0,这是将0 强制转换为函数指针类型,0 是一个地址,也就是说一
个函数存在首地址为0 的一段区域内。
第三步:(*(void(*) ())0),这是取0 地址开始的一段内存里面的内容,其内容就是保存
在首地址为0 的一段区域内的函数。
第四步:(*(void(*) ())0)(),这是函数调用。
Eg3:
(*(char**(*) (char **,char **))0) ( char **,char **);
第一步:char**(*)(char**, char**),是一个函数指针,这个函数参数为char**,返回值也为char**;
第二步:(char**(*) (char **,char **))0,将0强转为函数指针类型,也就是说这个函数指针指向首地址为0的一段区域内。
第三步:*(char**(*) (char **,char **))0,取0地址开始的一段内存里卖弄的内容,其内容就是保存在首地址为0的一段区域内的函数。
第四步:(*(char**(*) (char **,char **))0) ( char **,char **); 这是函数调用。
函数指针数组:
定义:char * (*pf[3])(char * p);
使用: pf[0] = fun1; // 可以直接用函数名
pf[1] = &fun2; // 可以用函数名加上取地址符
pf[2] = &fun3;
pf[0]("fun1");
pf[0]("fun2");
pf[0]("fun3");