赶快来看!!!经典指针笔试题解析~

目录

(注意:这里的代码均为32位机器上实现)

❤️笔试题1:

❤️笔试题2:

❤️笔试题3:

❤️笔试题4:

❤️笔试题5:

❤️笔试题6:

❤️笔试题7:

❤️笔试题8:

最后的话:


(注意:这里的代码均为32位机器上实现)

❤️笔试题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为数组名,指向数组首元素地址;&a的值虽然也是数组首元素的地址,但是&a指向的是整个数组

二者本质的区别在于数据类型不同:

a的类型为 int*   -  即为整形指针

&a 的类型为 int(*)[5]  - 即为存放整形的数组指针

所以,我们在定义ptr的时候,要将(&a+1)强制类型转化为 int* 之后再赋值给 int* 类型的ptr;

ptr为int* 类型,-1之后只向后移动一个int*类型的大小。

因此,最终答案为:2,5

❤️笔试题2:

//已知该结构体的大小为20个字节
struct Test
{
	int Num;
	char* pcName;
	short sDate;
	char cha[2];
	short sBa[4];
}* p;//p是一个结构体指针变量

//X86环境下演示:
//假设p 的值为0x100000。 如下表表达式的值分别为多少?
//已知,结构体Test类型的变量大小是20个字节
int main()
{
	p = (struct Test*)0x100000;
	printf("%p\n", p + 0x1);
	printf("%p\n", (unsigned long)p + 0x1);
	printf("%p\n", (unsigned int*)p + 0x1);

	return 0;
}

小tips:%p  --  打印地址(不能省略0)

           %x  --  以十六进制输出 (省略前面的0)

📄解析:

已知p的类型为结构体指针类型,+1 之后跳过一整个结构体的大小,该结构体的大小为20个字节,转换为十六进制为0x14

所以,第一个printf打印的数据为 :00100014

第二个printf中将p强制类型转化为整型类型,+1 之后就是加上一个整形1

以%p打印的结果为 00100001

第三个printf中将p强制类型转化为整形指针类型,+1 之后跳过一个整型的大小,

打印的结果为 00100004

❤️笔试题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);

	//%p - 是打印地址
	//%x - 是16进制的格式打印
	return 0;
}

📄解析: 

 ptr1 的找法与笔试题1的ptr找法一致,这里就不赘述了。

ptr[-1]  等价于  *(ptr-1)  即向后移动一个int类型大小,打印结果为4

ptr2 将 a 强制类型转化为int类型,+1 之后就是a原本的地址+1,比如:a的地址为0x100001, 转化为int类型并且+1之后变为0x100002;

之后再转化回int*类型,赋值给ptr2,这时,ptr2指向的就是上图所示的位置,

这里还需要注意的是编译器的存储类型为小端存储还是大端存储,结果是不同的!!!

不了解大小端存储的可以看看这篇文章:

 大小端存储解析

小端存储:

读取到的内存输出即为2000000

大端存储:

读取到的内存输出即为00000100

❤️笔试题4:

int main()
{
	int a[3][2] = { (0, 1), (2, 3), (4, 5) };

	int* p;
	p = a[0];
	printf("%d", p[0]);

	return 0;
}

📄解析:

要注意的是a数组的定义并不是准确地初始化到每一行,要是想准确地初始化到每一行需要将每一行的数用大括号括起来

int a[3][2] = { {0, 1}, {2, 3}, {4, 5} };

而代码中用的是小括号,那就是逗号表达式了, 最终数组a中的元素就只有{1, 3, 5};

a[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是一个5*5的二维数组,p是一个指向包含4个int类型的数组指针,将a赋值给p,那么p就指向a数组第一行的起始位置

如图所示,因为p的类型为int (*)[4],所以每p+1就跳过4个int类型!

小tips:

           指针-指针 得到的是两地址间的元素个数

 &p[4][2] - &a[4][2]  中间有4个元素,所以得到的是 -4 

%p打印:

 

 所以得到的是 fffffffc

%d打印:

就是 -4

❤️笔试题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 就跳过一整个数组

aa 表示数组第一行的地址, +1 就跳过一行 *(aa+1) 等价于 aa[1]

因为两者均为数组指针,所以要强制类型转化为 int* ,分别赋值给 ptr1 、ptr2;

 ptr1、ptr2均为int*类型,-1 之后向前移动一个int类型的大小

所以,答案为 10,5

❤️笔试题7:

#include <stdio.h>

int main()
{
	char* a[] = { "work","at","alibaba" };
	char** pa = a;
	pa++;
	printf("%s\n", *pa);
	return 0;
}

📄解析:

a数组为char*类型,存放了三个字符串的首字母的地址char** pa = a,则pa指向的是 a数组的第一个元素的地址,即'w'的地址;pa+1 就指向数组的下一个元素,即'a'的地址;

所以,最终结果为 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;
}

📄解析:

这题与上一题相似,解法相同:

第一个printf:前置++,这时cpp指向cp[1],再两次解引用,得到的就是"POINT"

第二个printf: 这里要考虑优先级,再一次前置++这时cpp指向cp[2],解引用后得到c[1]的地                              址,再前置--,得到c[0]的地址,解引用后得到'E'的地址,再+3,向后移动三位找                            到第二个'E'的地址,打印字符串,结果为 "ER"

第三个printf:*cpp[-2] 等价于 **(cpp-2),cpp-2之后指向cp[0]但是这里并没有改变cpp的值!                         两次解引用后得到'F'的地址,再+3,向后移动三位找到'S'的地址,打印字符串,结                         果为 "ST"

第四个printf:cpp[-1][-1] 等价于 *(*(cpp-1)-1),cpp-1 之后指向cp[1]这里也没有改变cpp的值

                      解引用后得到c[2]的地址,再-1 之后得到c[1]的地址,解引用后得到'N'的地址,                              再+1,得到'E'的地址, 打印字符串,结果为"EW"

最后的话:

看完这些笔试题,我相信你一定会对这部分的知识理解地更加深刻的,后续还会发布大量优质文章,希望大家多多支持,我们一起努力!!!

  • 17
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 13
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蒲公英的吴

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值