【c语言进阶】指针面试习题 - - 让你进一步了解,指针运算!!!

在这里插入图片描述

实例一

大家请看,如下代码的运行结果是什么?

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是取出整个数组的地址,而&a+1,就使指针ptr指向了a这个数组最后一个地址的后一个地址
然后执行,(a+1)a并不是单独放在sizeof里,也不是和&取地址符连用,所以,这里的a表示的使数组首元素的地址,而a+1就表示的是数组第二个元素。
接着执行
(ptr-1),ptr此时指向的是数组a中元素5后面的地址,而ptr-1,又使其指向了5这个地址。
图解如下:
在这里插入图片描述
运行结果如下:
在这里插入图片描述

实例二

看完第一题大家感觉这么样呢?
快来挑战第二题吧。

struct Test
{
	int Num;
	char* pcName;
	short sDate;
	char cha[2];
	short sBa[4];
}*p;//此处结构体的大小为20.
int main()
{
	p = (struct Test*)0x00100000;//假设 p 的地址为此。
	printf("%p\n", p + 0x1);
	printf("%p\n", (unsigned long)p + 0x1);
	printf("%p\n", (unsigned int*)p + 0x1);
	return 0;
}

本题解答:
第一个pirntf是结构体指针类型,p+1跳过的是一个Test这个结构体的大小,
第二个printf是无符号数的长整型,其实就是一个数,所以p+1就是+1;
第三个printf是无符号整形指针类型,p+1,就是跳过一个整型指针的大小,而小编这里用的是32位操作系统,所以int*的大小为4个字节。
运行结果如下:
在这里插入图片描述
要注意这里是16进制哦!!!

实例三

看完一二题是不是感觉,坑不少啊
本题的坑也不小哦!!!

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;
}

ptr1在上面(实例一)讲过了,在这里就不过多赘述了
本题的重点是ptr2中的强制类型转化
首先,a表示的是首元素的地址,接着对其进行强制类型转化为(int)类型,就是把指针看作了一个数(其实是a的首地址),
再+1就是给这个数+1,
后再将其强制类型转化为整型指针。
下来执行ptr1[-1],就是 *(ptr1 - 1)和 ptr2;
图解如下:
(小编使用的是小端操作)在这里插入图片描述
大家也可以将(int)a+1 理解为 (char
)a+1;
运行结果如下:
在这里插入图片描述

实例四

快来感受一下第四题的坑吧。

int main()
{
	int a[3][2] = { (0, 1), (2, 3), (4, 5) };
	int* p;
	p = a[0];
	printf("%d", p[0]);
	return 0;
}

本题其实并不难,就在于坑点为小括号并不是大括号哦,逗号操作符(还记得吗?)
逗号操作符是将最后一个数赋给左值,所以,数组a中的值为{1,3,5,0,0,0}
运行结果如下:
在这里插入图片描述

实例五

本题没有坑,纯纯就是一个难题
快来感受一下吧

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是一个指向有4个整型空间的数组。
图解如下:
在这里插入图片描述
结果如下:
在这里插入图片描述
这里的FFFFFFFC是-4按照地址的方式输出的,不懂得可以看看小编《内存中的储存》这个章节,有详细讲解
后面的-4是因为前面减后面,所以为负数。

实例六

本题其实上面也讲过,和实例一相差不大,只不过是二维数组而已。
快来感受一下。

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是让ptr1这个指针指向10地址的下一个地址处。
而aa则表示的是首元素的地址,(上面讲过,二维数组的首地址是第一行的地址)
所以aa+1是跳过了第一行,指向了6这个元素的地址。
最后再让这两个指针的地址减一个整型,
所以ptr1指向了10元素的地址,ptr2指向了5元素的地址
运行结果如下:
在这里插入图片描述

实例七

大家请认真研究这道题,有助于对压轴题的解答。

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

本题两个指针的初始状态
在这里插入图片描述
接着执行pa++,使原本指向‘w’地址的cp指针,指向了’a‘这个地址。
最后打印cp这个指针。
图解如下:
在这里插入图片描述
执行结果如下:
在这里插入图片描述

实例八

这个例题比较难,请大家认真分析。
提示:本题一定要注意自增自减符!!!!!

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,使指向c+3空间的cpp指向c+2这个空间
后连续执行两个**解引用操作符,
图解如下:
在这里插入图片描述
输出结果如下:
在这里插入图片描述

接着我们执行第二个printf
还是因为前置++的优先级高于其他操作符,所以先使指向c+2空间的cpp指针,指向c+1的空间,接着执行*解引用操作符,找到c+1指向的空间,
再执行前置–操作符,使指向‘N’地址的指针c,指向’E‘,接着对其解引用操作,找到’E‘所在的地址,
最后执行+3运算,就是将指针向后移动三个char字节的长度,最终指向’E‘
图解如下:
在这里插入图片描述

结果如下:
在这里插入图片描述

接着我们执行第三个printf
因为【】的优先级高于 * 解引用操作符,所以会先执行【-2】(这里解释一下【-2】解释 :*(cpp-2) ,并且需要注意的是,这里并不是自增自减操作符,所以只是临时找到那个值)
第二个printf结束后,此时的cpp指针指向的是c+1这个空间,所以执行 cpp【-2】只是找到 c+3 这个空间里的地址,而cpp指针依然指向的是 c+1这个空间,
接着对其进行 * 解引用操作,找到 ’ F‘的地址,
最后执行 +3运算,找到’S‘的地址。
图解如下:
在这里插入图片描述

运行结果如下:
在这里插入图片描述

接着我们执行最后一个printf
先执行第一个【-1】,找到c+2空间里的地址,
后执行下一个【-1】,找到’N‘的地址,
最后运算+1操作符,找到’E‘的地址。
图解如下:
在这里插入图片描述

结果如下:
在这里插入图片描述
最后,这道题很难,希望大家仔细研究。
会让你的指针,如火纯情。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值