前言:
承接上文,继续进行指针和数组的练习。
Part2:指针笔试题
1.做题
均要求输出结果
笔试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; }
答案及解析:
*(a + 1): a表示首元素地址,+1得到第二个元素地址,解引用后得到 2 *(ptr - 1): ptr记录了整个数组下一位的地址,-1后得到数组最后一个元素的地址,解引用后得到5
笔试2
struct Test { int Num; char* pcName; short sDate; char cha[2]; short sBa[4]; }*p; //假设p的值为0x00100000。 如下表表达式的值分别为多少? //已知:结构体Test类型的变量大小是20个字节 int main() { printf("%p\n", p + 0x1); printf("%p\n", (unsigned long)p + 0x1); printf("%p\n", (unsigned int*)p + 0x1); return 0; }
答案及解析:
0x00100014 0x00100001 0x00100004
0x开头,表示十六进制 p + 0x1 -- p是结构体指针,+1表示加一个结构体的大小(20) 0x00100000 + 0x00000014 == 0x00100014 (unsigned long)p + 0x1) -- p强转为无符号长整型,+1就是+1 0x00100000 + 0x00000001 == 0x00100001 (unsigned int*)p + 0x1) -- p强转为整型指针,+1表示跳过一个整型 0x00100000 + 0x00000004 == 0x00100004
笔试3
// 小端 x86环境 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; }
答案及解析:
1. %x 表示以十六进制打印 2. 0x4 3. 0x02000000
int *ptr1 = (int *)(&a + 1); ptr1[-1]: 即*(ptr1 - 1),&a + 1表示整个数组的下一个位置,强转为整型指针后-1,表示向前跳过一个整型,即数组最后一个元素
int *ptr2 = (int *)((int)a + 1); *ptr2:
笔试4
int main() { int a[3][2] = { (0, 1), (2, 3), (4, 5) }; int* p = a[0]; printf("%d", p[0]); return 0; }
答案及解析:
注意逗号表达式,括号内取最后一个值 int a[3][2] = { (0, 1), (2, 3), (4, 5) }; 即{1,3,5} 理解: 1 3 5 0 0 0 a[0] 表示1的地址 p[0] 相当于*(p+0),即1
笔试5
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; }
答案及解析:
a 是二维数组名,p 是数组指针
p 与 a 指向的首元素相同
下图解释了两者的意义:
由此可以计算出 &p[4][2] - &a[4][2] 的值为 -4 ,按照整型打印就是 -4
按照地址打印,先要看 -4 在内存中是如何存储的:
即 -4 的补码形式:
11111111 11111111 11111111 11111100
换算为十六进制:
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; }
答案及解析:
1 2 3 4 5 6 7 8 9 10 int* ptr1 = (int*)(&aa + 1); 即10的下一个位置的地址 int* ptr2 = (int*)(*(aa + 1)); aa+1表示第二行的地址,解引用得到第二行数组 *(ptr1 - 1) 向前跳过一个整型,即二维数组的最后一个元素10 *(ptr2 - 1) 第二行数组向前跳过一个整型,得到第一行数组的最后一个元素5
笔试7
int main() { char* a[] = { "work","at","alibaba" }; char** pa = a; pa++; printf("%s\n", *pa); return 0; }
答案及解析:
a 是一个存贮字符指针的数组,里面有三个元素,分别指向三个字符串的首字母;
pa 是指针,它指向的数据类型是字符指针;
pa 指向第一个元素 char* a[0];
pa++,跳转到char* a[1],解引用就得到了字符串 at
笔试8
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; }
答案及解析:
这是原始状态:
**++cpp:
优先级 ** < ++
cpp++,指向空间c+2 ,一次解引用后得到空间 c+2 ,再次解引用得到 char*[2],指向P,打印出POINT;;(cpp已被改变,指向空间c+2)
*-- * ++cpp + 3
先自cpp向左操作,最后+3
cpp++,此时已指向空间c + 1 ,解引用后得到空间c+1,此时--,即空间c+1--,得到空间c,解引用后得到ENTER中第一个E的地址,最后+3,得到ENTER中第二个E的地址,打印出ER;(cpp又被改变,指向空间c + 1 )
*cpp[-2] + 3 即 **(cpp-2) + 3
cpp++,指向空间c + 3,两次解引用得到FIRST中的F的地址,+3,得到其中S的地址,打印出ST; (cpp又被改变,指向空间c + 3 )
cpp[-1][-1] + 1 即 *(*(cpp-1)-1) + 1
cpp-1后解引用,得到空间c+2,-1得到空间c+1,解引用得到NEW中N的地址,+1得到E的地址,打印出EW。
2.总结
指针+1表示跳过一个类型大小
如:整型指针+1,表示跳过一个整型的大小
一维数组名 a
a表示首元素地址,+1表示第二个元素的地址
&a表示整个数组的地址,+1表示数组末端的地址(数组外)
二维数组名aa
aa表示二维数组中一行数组的地址,+1跳过一行
aa[i] 表示二维数组中第 i 行的地址,+1跳过一行
&aa表示整个二维数组的地址,+1表示二维数组的末端(数组外)
向%s传递字符地址,从当前字符开始,打印到 \0 结束
总结:
带你做了8道笔试题,有梯度,会第8道,这一部分就掌握的很好了。
码文不易
如果你觉得这篇文章还不错并且对你有帮助,不妨支持一波哦 💗💗