欢迎来到 Claffic 的博客 💞💞💞 👉 专栏:《C生万物 | 先来学C》👈
前言:
承接上文,继续进行指针和数组的练习。
目录
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;
}
答案及解析:
%x 表示以十六进制打印
0x4
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道,这一部分就掌握的很好了。
码文不易
如果你觉得这篇文章还不错并且对你有帮助,不妨支持一波哦 💗💗