前言:上期我们介绍了sizeof与strlen的辨析以及sizeof,strlen相关的一些笔试题,这期我们主要来讲指针运算相关的一些笔试题,以此来巩固我们之前所学的指针运算!
文章目录
- 一,指针笔试题
- 1,题目一
- 2,题目二
- 3,题目三
- 4,题目四
- 5,题目五
- 6,题目六
- 7,题目七
一,指针笔试题
我们直接上题目:
1,题目一
下面程序运行的结果是什么?
#include <stdio.h>
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
和&a
:
a
为数组首元素的地址;&a
为整个元素的地址;&a+1
跳过整个数组指向最后一个元素的末尾。
上面程序int*ptr = (int *)(&a + 1);
就是将数组最后一个地址强转为(int *)类型
赋给ptr
所以当我们打印*(a + 1)
打印的就是第二个元素 2!
打印*(ptr - 1)
时,由于ptr存放的是最后一个元素末尾的地址再-1就找到了最后一个元素的地址 解引用拿到最后一个元素 5!
答案如下:
2,题目二
下面程序运行的结果是什么?
//在X86环境下
//假设结构体的⼤⼩是20个字节
//程序输出的结果是啥?
struct Test { int Num; char *pcName; short sDate; char cha[2]; short sBa[4];
}*p = (struct Test*)0x100000;
int main()
{ printf("%p\n", p + 0x1); printf("%p\n", (unsigned long)p + 0x1); printf("%p\n", (unsigned int*)p + 0x1); return 0;
}
分析如下:
一, 首先看
0x100000
被强转成了结构体指针类型p
,而且题目也告诉我们在X86环境下假设结构体的大小是20个字节。
p+0x1
就相当于偏移了一个结构体的大小即20字节 二20字节转为16进制是0x14
所以p+0x1==0x100014
二,第二个打印的内容是将p强制类型转换为
unsigned long类型
我们知道在X86环境下long
类型的数据是占4个字节的。
- 所以
unsigned long)p + 0x1
就相当于p偏移一个unsigned long
类型的大小 所以unsigned long)p + 0x1
结果为0x100004
吗?注意这里有坑 :
(unsigned long)p
是将p转换成了整数啊!p此时已经不是指针了,所以不是指针加一而是整数加1! 而整数加1就是直接加一 所以结果为0x100001
三,第三个打印的内容是将
p
强转为unsigned int*
的类型,这时的p
就是指针了,指针加一跳过一个unsigned int*
类型该类型的大小为4个字节 所以结果为0x100004
注意%p是C语言中用来格式化和打印指针变量的格式化符号。当你想打印一个指针变量的地址时,可以使用%p来输出该变量的地址值。
通过以上的分析我们首先要明白指针加一到底跳过多少字节?这取决于指针的类型,其实就是指针指向了什么类型的数据。
答案如下:
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;
}
分析如下:
这道题也有陷阱,题目考察的知识点就是对数组名的理解。但是如果我们没有认真看题而是直接去看
p[0]
打印的结果,这时我们就会认为结果是0,因为p[0]==a[0]
为第一行第一个元素所以是0。但结果是错的为什么呢?
- 我们看到数组初始化用的是()小圆括号。
- 圆括号里边有逗号所以考的是逗号表达式
所以数组其实是这样的:
回到题目我们就可以从数组直接看出答案为1
答案如下:
4,题目四
下面程序运行的结果是什么?
//假设环境是x86环境,程序输出的结果是啥?
#include <stdio.h>
int main()
{ int a[5][5]; //需要完整对应就需要一个int(*)[5]的数组指针int(*p)[4]; p = a; printf( "%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]); return 0;
}
分析如下:
由上图我们需要知道2个点:
- 指针-指针的前提是两个指针指向同一个空间
- 指针-指针得到的结果的绝对值是两个指针之间的元素个数 并且小地址-大地址会得到负数
我们知道&p[4][2]-&a[]4[2]==-4
那么问题来了 -4以%p
和%d
的形式打印的结果分别是什么呢?- 以%d形式打印 结果就为 -4
- 以%p的形式打印就要注意了 前面说过
%p
是用来打印地址的 打印-4时会直接将内存中的值当作地址打印 而地址中存放的是16进制数 而-4的16进制数为0xFFFFFFFC
如果对于进制转换还不是很了解的话可以去看我之前写的进制转换这篇文章;传送门:进制转换
答案如下:
5,题目五
#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;
}
分析如下:
首先我们先将数组画出来:
本题主要注意区分aa与&aa,aa为二维数组首元素的地址而二维数组首元素为第一行的地址+1会跳过一行指向的第一行最后一个元素的末尾;&aa拿到的是整个二维数组的地址 +1会跳过一个二维数组 指向的是二维数组最后一个元素的末尾。
通过上面的分析我们不难得出答案是10和5
答案如下:
6,题目六
#include <stdio.h>
int main()
{ char *a[] = {"work","at","alibaba"}; char**pa = a; pa++; printf("%s\n", *pa); return 0;
}
分析如下:
这一题是一个关于二级指针的题,首先
a
是一个指针数组,*pa=a
拿到了a数组的首地址"work
",这其实相当于一个指针数组存放了三个类型为char*
的字符串常量我们画图演示:
pa++就跳过了一个元素指向了"at"这个常量字符串 所以打印的结果就是"at"。
答案如下:
7,题目七
#include <stdio.h>
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;
}
分析如下:
要解决这道题首先要把图给画好:
好了这就是一些有关指针运算相关的练习了,如果有问题欢迎指出与我讨论。
感谢能够看到这里的读者,如果我的文章能够帮到你那我甚是荣幸,文章有任何问题都欢迎指出!制作不易还望给一个免费的三连,你们的支持就是我最大的动力!