上一篇的题目不知感觉如何,感觉良好的话,就进入下面的内容
注:这次的题目会更难
那就开始吧
1.
int main() { int a[5] = { 1, 2, 3, 4, 5 }; int *ptr = (int *)(&a + 1); printf( "%d,%d", *(a + 1), *(ptr - 1)); return 0; }
问上述代码的结果是什么
还是逐个来分析
数组名是首元素的地址+1后解引用就是a[1]
&a是取出整个数组的地址,+1后便来到数组末尾,如图:
所以ptr指向数组末尾
故ptr-1后来到a[4]的起始位置
解引用后结果为5
输出结果为2 5
2.
struct Test { int Num; char *pcName; short sDate; char cha[2]; short sBa[4]; }*p; //假设p 的值为0x100000。 如下表表达式的值分别为多少? //已知,结构体Test类型的变量大小是20个字节 int main() { printf("%pn", p + 0x1); printf("%pn", (unsigned long)p + 0x1); printf("%pn", (unsigned int*)p + 0x1); return 0; }
这题考查指针+1后是增加多少个字节
p+0x1,因为p是指针,结构体大小为20,所以p+1是加20个字节,换成十六进制就是14
结果就是0x100014
将p强制转换成unsigned long后,+1就是数学上的+1计算了,结果是0x100001
p强制转换成unsigned int*,int是4个字节,+1就是加4个字节,结果是0x100004
3.
int main() { int a[4] = { 1, 2, 3, 4 }; int *ptr1 = (int *)(&a + 1); int *ptr2 = (int *)((int)a + 1); printf( "%x,%x", ptr1[-1], *ptr2); return 0; }
这题比较复杂
&a+1是数组末尾,ptr[-1]等效于*(ptr-1),结果是4
(int)a+1,因为a的类型被强制转换,所以+1就是数学上的a+1,转换成int*后来到a[0]的第二个字节,这里涉及到大小端的问题,假设是小端存储,ptr2取到的4个字节如下:
将其转换成十六进制结果就是2000000
4.
int main() { int a[3][2] = { (0, 1), (2, 3), (4, 5) }; int *p; p = a[0]; printf( "%d", p[0]); return 0; }
这题不复杂,结果如下
5.
int main() { int a[5][5]; int(*p)[4]; p = a; printf("%p,%dn", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]); return 0; }
数组a是5行5列的二维数组,p是数组指针,但p指向的数组一列只能有4个元素,所以&p[4][2]和&a[4][2]的位置是不同的
指针和指针相减,结果为二者之间的相隔的元素的个数,因为是小地址减大地址,所以是-4
第二个值就是-4
第一个值因为是以%p的形式打印,地址是不会有负数的,所以打印的是-4的补码,以十六进制的形式打印,结果是FFFFFFFC
6.
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; }
&aa+1是数组末尾地址,-1后是数组最后一个元素地址,结果是10
aa+1是aa[1]的首地址,-1后是aa[0][4]的地址,结果是5
7.
int main() { char* a[] = { "work","at","home" }; char** pa = a; pa++; printf("%sn", *pa); return 0; }
pa存储的是数组首元素的地址,++后指向第二个元素,结果是"at"
8.
int main() { char* c[] = { "ENTER","NEW","POINT","FIRST" }; char** cp[] = { c + 3,c + 2,c + 1,c }; char*** cpp = cp; printf("%sn", **++cpp); printf("%sn", *-- * ++cpp + 3); printf("%sn", *cpp[-2] + 3); printf("%sn", cpp[-1][-1] + 1); return 0; }
这一题一定要把他们之间的关系理清,否则你做不出来
初始指向关系如下:
**++cpp:前置++优先级高于*,所以cpp先进行++,++后指向c+2然后解引用来到数组c中第三个char*,内容为字符串"POINT"的首地址,再次解引用就是字符串“POINT”
*-- * ++cpp + 3:经过**++cpp后,cpp指向c+2,如图:
这里 *** 作符先后顺序要清楚,前缀++优先级高于+,所以先算++,来到c+1的位置,然后进行解引用得数组c中的c[1],*--c[1]+3,之后算--得c[0],*c[0]+3,解引用c[0]来到字符串“ENTER”首字符的位置,+3后是字符“E”的位置,所以结果是"ER"
*cpp[-2] + 3:上述两步 *** 作后cpp在c+1的位置
*cpp[-2]就是*(cpp-2) ,cpp-2来到c+3位置,解引用后是数组c中第四个char*,内容为字符串“FIRST”首字符地址,+3后是字符“S”的位置,结果是“ST”
printf("%sn", cpp[-1][-1] + 1):上一步中没有++和-- *** 作,所以cpp位置不变,cpp[-1][-1]等效于*(*(cpp-1)-1),cpp-1来到c+2位置,解引用后数组c第三个char*,再次-1后是第二个char*位置,再次解引用来到字符串“NEW”首字符位置,+1后便是字符“E”的位置,所以结果是“EW”
结果如下图:
指针的习题到这就结束了,关于指针进阶的内容也基本上结束了,关于C语言的内容后面会继续更新
完
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)