习题1
int main() { int arr[5] = { 1, 2, 3, 4, 5 }; int *ptr = (int *)(&arr + 1); printf( "%d,%d", *(arr + 1), *(ptr - 1)); return 0; }
问:程序的结果是什么?
分析:ptr是一个整型指针变量。&arr取出的是整个数组的地址,(&arr+1)跳过的距离是整个数组,类型是数组指针,再强制类型转换成整型指针存放到ptr这个指针变量中。
画图理解:
*(arr+1):arr是数组首元素的地址,+1找到下一个元素的地址,解引用操作访问到的结果也就是2。
*(ptr - 1):ptr变量存放的地址指向的位置是整个数组后面的位置,(ptr-1)解引用操作访问到的结果是5。
答案:2 , 5
习题2
int main() { int a[4] = { 1, 2, 3, 16 }; int *ptr1 = (int *)(&a + 1); int *ptr2 = (int *)((int)a + 1); printf( "%x,%x",ptr1[-1], *ptr2); return 0; }
问:程序的结果是什么?
分析:
1、%p:打印void* 类型,十六进制的形式,按位全部打印出来,不够的补0。
2、%x:打印的是 int 型,无符号十六进制整数(字母小写,不会补零)。
3、&a取出的是整个数组的地址,&a+1跳过的是整个数组,强制类型转换存储后存储到指针变量ptr1中。
4、a代表首元素地址,强制类型转换成int类型,((int)a+1)表示地址向后移动一个字节。
在强制类型转换成(int*)类型的指针存放到指针变量ptr2中。
综上所述:
%x打印ptr1[-1]:10(十六进制)。
%x打印*ptr2: 2000000。
假设%p打印(int*)ptr1[-1],结果为:00000010。
习题3
#include <stdio.h> int main() { int a[3][2] = { (0, 1), (2, 3), (4, 5) }; int *p; p = a[0]; printf( "%d", p[0]); return 0; }
问:程序的结果是什么?
分析:逗号表达式从左向右依次执行。整个表达式的结果是最后一个表达式的结果。
所以数组中的数据其实是:
int a[3][2] = { 1, 3, 5};
遍历数组后打印的结果如图。
二维数组可以看做是特殊的一维数组,既想象成一维数组中的各个元素仍然是一维数组。
所以就可以把a[0]看成访问这个一维数组中的第一个元素,只不过这个元素也是一个一维数组。这样一来p[0]其实就等价于a[0][0]。答案:1。
习题4
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; }
问:程序的结果是什么?
分析:int (*p)[4];是数组指针,数组a的首元素地址赋值给数组指针变量p 。
把他们放在一起就会出现空间错位的情况:
指针-指针:表示两个指针指向的内存位置之间相隔多少个元素(是元素,不是字节数)。
%p打印void* 类型,十六进制的形式,按位全部打印出来,不够的补0。
-4的二进制序列原码:10000000 00000000 00000000 00000100
反码:1111 1111 1111 1111 1111 1111 1111 1011
补码:1111 1111 1111 1111 1111 1111 1111 1100
答案:十六进制表示FF FF FF FC
%d打印一个有符号的整型数据:&p[4][2] - &a[4][2],两个地址相隔4个元素,又因为低地址-高地址,所以答案为:-4。
习题5
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; }
问:程序的结果是什么?
分析:1、&aa取出整个数组的地址,&aa+1跳过整个数组,强制类型转换成(int*)存储在指针变量ptr1中,*(ptr-1)的结果为:10。
2、aa是数组首元素的地址,*(aa+1)等价于aa[1],也就是数组的第二个元素,这个元素又是一个一维数组,指向这个元素的首元素地址。
3、*(pt2-1)的结果为:5
答案:10,5
习题6
int main() { char *a[] = {"work","at","alibaba"}; char**pa = a; pa++; printf("%s\n", *pa); return 0; }
问:程序的结果是什么?
分析:a是指针数组,三个元素是字符串,二级指针变量pa存放a数组首元素的地址,pa++指向数组的第二个元素。
答案:at
习题7
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; }
问:程序的结果是什么?
分析: 指针数组c存放四个字符串,指针数组cp存放c数组首元素变换后的几个地址。指针变量cpp存放指针数组cp的首元素地址。
备注:无论是前自增还是后自增,“变量的值”都已经增加了。
**++cpp:(++前缀自增操作符的优先级大于*间接访问操作符),cpp先自增指向c+2的地址,*cpp找到字符串POINT的地址,**cpp访问到字符串POINT。答案:POINT
*--*++cpp+3:(++的优先级最高--次之,然后*间接访问操作符,最后是+(加法)),
上一步中cpp自增过,所以这里cpp存的是c+2的地址。++自增后指向c+1的地址,--*++cpp也就是--(c+1),解引用得到c的首元素地址,最后一步“ENTER”的地址+3。答案:ER
*cpp[-2]+3:*cpp[-2]等价于*(cpp-2),找到pc的首元素地址,*找到字符串“FIRST”的首元素地址,最后一步这个地址+3。答案:ST
cpp[-1][-1]+1:cpp[-1][-1] +1 等价于(*(cpp-1)-1) + 1,cpp-1找到c+2元素的位置,*操作找到字符串NEW的首元素地址,这个地址最后+1。答案:EW