1.第五题
#include<stdio.h>
int main()
{
int a[5][5];
int(*p)[4];
p = a;
printf( "%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);
return 0;
}
输出结果为FFFFFFFC,-4
分析:int (*p)[4];的意思为创建一个int类型的指针数组(数组空间为4)。p=a;的意思是将数组a[0]整行的地址(和a[0][0]的地址一样)赋值给指针p。
p[4][2]在编译时执行的是*(*(p+4)+2)语句,*(p+4)的意思是对p指向的地址加4个int [4]类型(指针p的类型)的字节数,得到从a[3][1]到a[3][4]这一串的地址,再解引用得到a[3][1]的地址。
*(*(p+4)+2)的意思是对a[3][1]的地址加上两个int类型(谁的地址就加谁的类型,此时加的是a[3][1]的类型)的字节数,得到a[3][3]的地址,再解引用得到a[3][3]的内容。所以,&p[4][2]就是对a[3][3]取地址。
&p[4][2] - &a[4][2]就等于 &p[3][3] - &a[4][2],地址相减得到的是元素个数,低地址减高地址为负数,所以是-4。%p是用地址格式打印,因此要打印16进制的补码(具体变化看下图)。
2.第六题
#include<stdio.h>
int main()
{
int aa[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int* ptr1 = (int*)(&aa + 1);
int* ptr2 = (int*)(*(aa + 1));
printf("%d,%d", *(ptr1 - 1), *(ptr2 - 1));
return 0;
}
输出结果为:10,5
分析:
(1) (&aa+1)表示取出aa整个数组的地址,加上1个int [2][5]类型的字节数(2*5*4=40),
得到aa[1][4]后四个字节的地址。(int*)(&aa+1)表示将aa[1][4]后四个字节的地址强制类型转化为int*型。prt1得到的是aa[1][4]后四个字节的地址,*(prt1-1)就aa[1][4]后四个字节的地址减去1个int型的字节数,得到aa[1][4]的地址,再解引用得到a[1][4]中的值(10)。
(1) (*(aa+1))表示先将aa[0]整行的首地址加上1个int [5]类型的字节数(5*4=20),得到aa[1]整行首地址,再解引用得到a[1][0]的地址。(int*)(*(aa+1))表示将a[1][0]的地址强制类型转化为int*型。prt2得到的是a[1][0]的地址,*(prt2-1)就aa[1][0]的地址减去1个int型的字节数,得到aa[0][4]的地址,再解引用得到a[0][4]中的值(5)。
3.第七题
#include <stdio.h>
int main()
{
char* a[] = { "work","at","alibaba" };
char** pa = a;
pa++;
printf("%s\n", *pa);
return 0;
}
输出结果为:at
分析: pa=a表示将a数组的首地址(a[0]的地址)赋给二级指针pa。pa++表示将指针pa指向a[0]的地址加上1个char型的字节数,得到a[1]的地址,重新赋给指针p。*pa就是对a[1]地址解引用得到"at"字符数组的首地址("a"的地址)。%s打印字符串,所以输出at。
4.第八题
int main()
{
char *c[] = {"ENTER","NEW","POINT","FIRST"};
char**cp[] = {c+3,c+2,c+1,c};
char***cpp = cp;
printf("%s\n", **++cpp);
printf("%s\n", *--*++cpp+3);
printf("%s\n", *cpp[-2]+3);
printf("%s\n", cpp[-1][-1]+1);
return 0;
}
输出结果为:
POINT
ER
ST
EW
分析:
(1)**++cpp表示先对cpp指针指向的地址加1个char类型的字节数,得到cp[1]的地址,重新赋给指针cpp。解引用得到cp[1]的内容,就是c[2]的地址。再对c[2]的地址解引用,得到"POINT"的首地址("P"的地址)。
(2)*-- * ++cpp + 3表示先对cpp指针指向的地址加1个char类型的字节数,得到cp[2]的地址,重新赋给指针cpp。解引用得到cp[2]的内容,就是c[1]的地址。对c[1]的地址减去1个char类型的字节数,得到c[0]的地址,重新赋给cp[2]。再对c[0]的地址解引用,得到"ENTER"的首地址("E"的地址),加三得到"E"的地址。
(3)*cpp[-2] + 3表示先对cpp指向的地址减去2个char类型的字节数,得到cp[0]的地址,解引用得到cp[0]的内容,也就是c[3]的地址。再对c[3]的地址解引用得到"FIRST"的首地址("F"的地址)。最后加上3个char类型的字节数,得到"S"的地址。
(4) cpp[-1][-1] + 1表示先对cpp指向的地址减去1个char类型的字节数,得到cp[1]的地址,解引用得到cp[1]的内容,也就是c[3]的地址。再对c[3]的地址减去1个char类型的字节数,得到c[2]的地址,解引用得到c[2]的内容,也就是"NEW"的首地址("N"的地址)。最后加上1个char类型的字节数,得到"E"的地址。