指针和数组笔试题深度解析(下)

本文通过一系列的C语言指针笔试题,详细解析了指针与数组、结构体之间的关系,包括指针的加减运算、强制类型转换以及多维数组和结构体指针的使用。通过实例分析,帮助读者深入理解指针在内存布局和地址计算中的应用。
摘要由CSDN通过智能技术生成

前言

上期我们介绍了strlen、sizeof的各种用法,本期带大家来学习指针类的笔试题。大家也要多多思考才行。

指针笔试题

首先我们来了解两点:

%p是打印地址
%x是以16进制形式打印

题一

#include<stdio.h>
int main()
{                 //程序的结果是什么?
	int a[5] = { 1, 2, 3, 4, 5 };
	int *prt = (int *)(&a + 1);
	printf( "%d,%d", *(a + 1), *(prt - 1));
	return 0;
}

输出:2,5
分析:
我们知道 &a+1 里 &a 取出的是整个数组地址(&a的类型是 int(*)[5] ,该类型大小为5个字节长度) +1 是跳过整个数组,指向的位置如图:
在这里插入图片描述
前面加个 (int *) 是强制类型转换的意思,将 int( * )[5] 类型强制转换为 int 类型,那么该类型的变量加一减一所跳过长度就是4字节(上期有讲过指针变量加一减一步长)
因此,prt - 1 所指向的位置如下图:
在这里插入图片描述
解引用就得到 5 ,
(a + 1)==>a[1] ,也就是2.

题二

我们来看一道关于结构体指针的例题:

#include<stdio.h>
struct Test
{
	int Num;
	char* pcName;
	short sDate;
	char cha[2];
	short sBa[4];
}*p;
//假设 p 的值为0x100000。 如下表表达式的值分别为多少?
//已知,结构体Test类型的变量大小是20个字节
int main()
{
	p = (struct Test*)0x100000;    //因为0x100000的类型是int型,所以要强制类型转换
	printf("%p\n", p + 0x1);
	printf("%p\n", (unsigned long)p + 0x1);
	printf("%p\n", (unsigned int*)p + 0x1);
	return 0;
}

本题考查指针加一步长多少?
输出:
在这里插入图片描述
分析:

	p = (struct Test*)0x100000;    
	printf("%p\n", p + 0x1);    //00100014    
	//指针 p 所指向的类型是 struct Test ,该类型占20字节单位,因此加一跳过20字节。
	printf("%p\n", (unsigned long)p + 0x1);   //00100001
	//强制类型转换为 unsigned long 类型,就是一个整数,整数加一就是加一个字节
	printf("%p\n", (unsigned int*)p + 0x1);   //00100004
	//强制类型转换为 unsigned int* 类型,p就指向一个无符号整型,占4个字节,加一就是加4个字节

题三

#include<stdio.h>
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;
}

输出:4,2000000
分析:

	int a[4] = { 1, 2, 3, 4 };
	int* ptr1 = (int*)(&a + 1);      //&a取出整个数组地址,加一跳过整个数组,强制类型转换为int *型,prt1指针指向下图1位置
	int* ptr2 = (int*)((int)a + 1);  //将首元素地址强制类型转换为整型,加一跳过一个字节,再转换回来,int*类型解引用访问4个字节,见图二
	printf("%x,%x", ptr1[-1], *ptr2);   //prt1[-1]==>*(prt1-1),prt1-1指向下图1位置

图一:
在这里插入图片描述
图二:
在这里插入图片描述

题四

#include <stdio.h>
int main()
{
	int a[3][2] = { (0, 1), (2, 3), (4, 5) };   数组的初始化内容有逗号表达式,实际上数组初始化的是1,3,5
	//如果要将上数全部存进去,可以这样写{{0,1},{2,3},{4,5}},或者{0,1,2,3,4,5}
	int* p;
	p = a[0];
	printf("%d", p[0]);
	return 0;
}

输出:1
解析:

	int a[3][2] = { (0, 1), (2, 3), (4, 5) };
	int* p;
	p = a[0];    //将a[0][0]存放入p中
	printf("%d", p[0]);

题五

#include <stdio.h>
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;
}

输出:
在这里插入图片描述
解析:
p的首地址指向a的首地址,我们将数组a画出来,指针p指向的数组是4个元素,如下:在这里插入图片描述
所以,p[4][2]和a[4][2]如图:
在这里插入图片描述
&p[4][2] - &a[4][2],指针相减结果就是两地址间的元素个数,就是4,但是它是小的减大的所以是-4,以%p打印就是FFFFFFFC,以%d打印就是-4

题六

#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));   //aa代表首元素地址即aa[0]的地址,+1就是a[1]的地址
	printf("%d,%d", *(ptr1 - 1), *(ptr2 - 1));
	return 0;
}

输出:10,5
不多解释了

题七

#include<stdio.h>
int main()
{
	char* a[] = { "work","at","alibaba" };
	char** pa = a;
	pa++;
	printf("%s\n", *pa);
	return 0;
}

输出:at
分析:a[0]存放‘w’的地址,a[1]存放‘a’的地址,a[2]存放‘a’的地址,如图(两个a地址不同,由首字符地址可以找到该字符串)
在这里插入图片描述
pa++,原来pa指向a[0],现在指向a[1],解引用得到a[1]的内容即地址,打印字符串得到 at

题八(稍难)

注意题中的++、- - 哦!

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

输出:
在这里插入图片描述
相信大家应该都有所疑惑吧,下面我们来分析一下:

	char* c[] = { "ENTER","NEW","POINT","FIRST" };

由该代码可以画出下图:
在这里插入图片描述

	char** cp[] = { c + 3,c + 2,c + 1,c };
	char*** cpp = cp;

由此又可以得到下图:
在这里插入图片描述

	printf("%s\n", **++cpp);

cpp先++,再解引用,++就改变了cpp里存放的地址,使原本指向cp[0]的指针++变为指向cp[1],如图:
在这里插入图片描述
解引用得到c[2]的地址,解引用得到字符‘P’的地址,打印就是:POINT

	printf("%s\n", *-- * ++cpp + 3);

cpp在原来基础上再++,如图:
在这里插入图片描述
cpp解引用得到cp[2],–cp[2]就是将cp[2]里的地址–,所以cp[2]里地址指向了c[0],如图。解引用得到的地址指向字符‘E’,加3个字节就指向了字符E,打印字符串为ER
在这里插入图片描述

	printf("%s\n", *cpp[-2] + 3);

经由几次++后,cpp指向cp[2] ,cpp[-2]可以写出*(cpp-2) ,得到cp[0],也就是c[3]的地址,再解引用得到字符‘F’的地址,加3得到‘S’的地址,打印字符串得到 ST

	printf("%s\n", cpp[-1][-1] + 1);

cpp[-1][-1] 可以写成*(*(cpp-1)-1) ,cpp-1得到cp[1]的地址,解引用得到c[2]的地址,再-1得到c[1]的地址,解引用得到字符‘N’的地址,加一字节,得到字符‘E’的地址,打印字符串,得到EW

好了关于指针的系列就告一段落了,相信大家应该收获满满吧,下期见了~

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

随风的浪

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

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

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

打赏作者

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

抵扣说明:

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

余额充值