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)

 

相减得到偏移量,4int类型的元素。所以答案为-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");