【C语言进阶(5)】指针笔试题(带图分析)

news2024/11/20 13:39:33

文章目录

  • 笔试题 1
  • 笔试题 2
  • 笔试题 3
  • 笔试题 4
  • 笔试题 5
  • 笔试题 6
  • 笔试题7
  • 笔试题 8

  • 分析下面代码的结果为何是这样

笔试题 1

1. 笔试代码

int main()
{
	int a[5] = { 1, 2, 3, 4, 5 };
	int* ptr = (int*)(&a + 1);

	printf("%d,%d\n", *(a + 1), *(ptr - 1));

	return 0;
}

2. 代码答案

在这里插入图片描述

3. 代码分析

  1. *(a + 1):*(a + 1) == a[1],所以结果是 2。
  2. *(ptr - 1):取出整个数组 a 的地址,数组的地址 + 1 会跳过整个数组。然后再将地址赋给 ptr,此时 ptr 实际指向的是 5 后面那个位置;让 ptr - 1 此时 ptr 指向的就是 5

在这里插入图片描述

笔试题 2

1. 笔试代码

  • 此处结构体的大小在 32 位环境底下为 20 个字节。
struct Test
{
	int Num;
	char* pcName;
	short sDate;
	char cha[2];
	short sBa[4];
}*p;
//假设p 的值为0x000000。 如下表表达式的值分别为多少?
//已知,结构体 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;
}

2. 代码答案

在这里插入图片描述

3. 代码分析

  1. p + 0x1:p 是 struct Test 类型的指针,步长为 20,指针 + 1 会向后走 20 个字节,0x 14 就是 十进制的 20。
  2. (unsigned long)p + 0x1:将 p 变成了一个 unsigned long 类型的变量,也就是说 p 里面存的地址变成了 1 个十进制的数 00000000,将这个数 + 1 后转换成十进制结果就是 00000001。
  3. (unsigned int*)p + 0x1:将 p 强转为 unsigned int* 类型的指针,使得 p + 1 向后走一步的步长变为了 4 个字节,所以结果才会是 00000004。

笔试题 3

1. 笔试代码

int main()
{
	int a[4] = { 1, 2, 3, 4 };
	int* ptr1 = (int*)(&a + 1);
	int* ptr2 = (int*)((int)a + 1);

	printf("%x,%x\n", ptr1[-1], *ptr2);

	return 0;
}

2. 代码答案

在这里插入图片描述

3. 代码分析

  1. ptr1[-1]:ptr1 == (int*)(&a + 1) 和第一题一样,指向的是 4 的后面,ptr1[-1] 等于 *(ptr1 - 1),此时 ptr 指向了 4,所以打印结果为 4。

在这里插入图片描述

  1. *ptr2:此时的 a 表示的是首元素的地址,将首元素地址强转为 int 类型。此时 a 面存着的就是个整型值,整型值 + 1 那就是 + 1 了。将 + 1 后的整型值强转为 int* 赋给 ptr2,此时 ptr 就指向第一个元素的第二个字节的内容。最后以打印 *ptr2 的结果,又因为 ptr2 是个 int* 类型的指针,所以*ptr2 就是从第一个元素的 2 个字节开始向后访问 4 个字节的内容。

在这里插入图片描述

笔试题 4

1. 笔试代码

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

	printf("%d\n", p[0]);

	return 0;
}

2. 代码答案

在这里插入图片描述

3. 代码分析

  • 这是一个三行二列的二维数组,然而要注意数组的初始化内放的其实是 3 个逗号表达式;
  • p = a[0] 将第一行的地址赋给 p,p[0] 就是首行首列也就是第一个表达式的内容 1 啦。

在这里插入图片描述

笔试题 5

1. 笔试代码

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

2. 代码答案

在这里插入图片描述

3. 代码分析

  • 这题的二维数组如果画成多行多列的方式就不好讲了,所以直接按照二维数组在内存中存放的本质来画图。

在这里插入图片描述

  • p 是一个数组指针,它所指向的数组应该有 4 个元素,每个元素都是 int 类型,p + 1 会跳过 4 个int 类型的数据
  • a 作为二维数组数组名,表示首元素地址,它的类型应该是 int (*)[5],然而 p 的类型却为 int(*) [5]。
    • 在将 第一行的地址赋给 p 时 p 肯定时不能这么存的,但如果硬是要存的话,p 最终还是会指向 a[0][0] 的位置。
    • p 虽然指向了 a[0][0] 的位置,但是 p 认为它指向的数组只有 4 个整型,对 p 解引用 或 p + 1 的时候只会向后访问 4 个整型

在这里插入图片描述

3.1 &p[4][2] - &a[4][2]

  • a[4][2] 很好找,p[4][2] 可以转换成 ((p + 4) + 2),接下来就是分析 p + 4 以及 *(p + 4) + 2 在哪了。
    • p + 4:对于 p 来说,它所指向的数组应该只有 4 个元素,所以 p + 4 跳过的元素应该是 4 * 4 = 16,最后 p + 4 就指向了 a[3][1] 的为位置.
    • *(p + 4) + 2:*(p + 4) 就是访问从 a[3][1] 开始的向后 4 个元素,所以 *(p + 4) +2 的位置实际指向 a[3][3]

在这里插入图片描述

  • 两个指针(地址)相减的绝对值是两个地址之间的元素个数

  • 用小的地址(&p[4][2])减去大的地址(&a[4][2])的结果是 -4,但是以 %p 的形式打印 -4 出来就得先分析数据在内存中存储的情况了。

11111111 11111111 11111111 11111100  //-4 的补码-4 的补码以 %p 的形式打印时,&p 认为 -4 的补码是个地址,地址是没有原反补概念的。
所以 %p 会直接将 -4 的补码直接以 16 进制的形式打印出来,结果就是 FFFFFFFC

3.2 &p[4][2] - &a[4][2]

  • &p[4][2] 与 &a[4][2] 之间隔着 4 个元素,所以 &p[4][2] - &a[4][2] 结果就是 -4。以 %d 打印的出来的结果自然就是 -4 了。

笔试题 6

1. 笔试代码

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\n", *(ptr1 - 1), *(ptr2 - 1));

	return 0;
}

2. 代码答案

在这里插入图片描述

3. 代码分析

  • *(ptr1 - 1):&aa 表示整个二维数组的地址,&aa + 1 指向了 10 的后面,ptr1 存着 10 后面的地址。将这个地址强转为 int* 赋给 ptr1,ptr1 的步长就变为了 4 个字节, ptr1 - 1 往前移动 4 个字节指向了 10 这个位置。

在这里插入图片描述

  • *(ptr2 - 1):aa 表示的是首元素(第一行)的地址,aa + 1 跳过第一行指向了 第二行的地址。*(aa + 1) 相当于直接拿到了第二行,也相当于拿到了第二行的数组名。而将第二行的数组名赋给 ptr2 ,ptr2 就等于指向了 第二行的第一个元素 6。因为 ptr2 是 int* 类型的指针,ptr2 - 1 往前移动 4 个字节指向了 5 这个元素。

在这里插入图片描述

笔试题7

1. 笔试代码

int main()
{
	char* a[] = { "work","at","alibaba" };
	char** pa = a;
	pa++;

	printf("%s\n", *pa);

	return 0;
}

2. 代码答案

在这里插入图片描述

3. 代码分析

  • a 是一个字符指针数组,该数组存储着每个串的第一个字符的地址。
  • 数组名 a 表示数组首元素(“word”)的第一个字符 ‘w’ 的地址,将 a 赋给 pa 相当于让 pa 指向了数组的 ’ w '。

在这里插入图片描述

  • pa++ 相当于让 pa 跳过了一个 char* 的元素指向了 a[1],对 pa 解引用 通过 a[1] 的地址就找到了 a[1] 中存储的内容(“at”)了。

在这里插入图片描述

笔试题 8

1. 笔试代码

int main()
{
	char* c[] = { "ENTER","NEW","POINT","FIRST" };
	char** cp[] = { c + 3,c + 2,c + 1,c };
	char*** cpp = cp;

	printf("%s\n", **++cpp);			//解析在 3.1
	printf("%s\n", *-- * ++cpp + 3);	//解析在 3.2
	printf("%s\n", *cpp[-2] + 3);		//解析在 3.3
	printf("%s\n", cpp[-1][-1] + 1);	//解析在 3.4

	return 0;
}

2. 代码答案

在这里插入图片描述

3. 代码分析

  • 整体布局图大致如下,具体怎么画的就不详细介绍了。

在这里插入图片描述

3.1:**++cpp

  1. ++cpp 指向了 cp[1],注意是对 cpp 进行 ++ 操作,此时 cpp 被改变彻底指向 cp[1]
  2. 第一次解引用(*cpp)后通过 cp[1] 中存储着的 c + 2 的地址找到了 c[2]。
  3. 第二次解引用(**cpp)后通过 c[2] 中存储着的 ’ P ’ 的地址找到了 ’ P ’ 这个字符。
  4. 最后再以 %s 的形式从 ’ p ’ 开始打印字符串 “POINT”。

在这里插入图片描述

3.2:*-- * ++cpp + 3

  • 注意:此时的 cpp 指向 cp[1] 的位置
  1. 先算 ++cpp 让 cpp 指向 cp[2] 的位置,此时 cpp 被彻底改为指向 cp[2]
  2. 对 ++cpp 后的结果解引用找到了 cp[2] 中存放着的 c + 1 这个值。
  3. 找到了 c + 1 ,让 c + 1 自减变成了 c (c[0])。c[0] 中存放着 “ENTRE” 的首字符 ’ E ’ 的地址。此时 cp[2] 中的值 c + 1 彻底被改成了 c
  4. 从首字符 ’ E ’ 的地址 + 3 指向了 " ENTER " 的第二个 ’ E '。
  5. 最后再解引用然后 %s 形式打印从 ’ E ’ 开始的字符串 “ER”。

在这里插入图片描述

3.3:*cpp[-2] + 3

  • 注意:此时的 cpp 指向了 cp[2] 的位置
  • *cpp[-2] + 3 等于 *(*(cpp - 2) + 3)
  1. cpp[-2] 等价于 *(cpp - 2),cpp - 2 指向了 cp[0] 的位置,*(cpp -2) 即访问 cp[0] 中存放的 c + 3 的地址。此时并没有改变 cpp 本身的值,cpp 本身还是指向 cp[2]
  2. *cpp[-2] :为访问 c + 3 中存放着的 “FIRST” 的首字符 ’ F ’ 的地址;
  3. *cpp[-2] + 3:为从 ’ F ’ 的地址开始指针 + 3 指向了 ’ S ’ 的地址。
  4. 最后以 %s 的形式打印从 ’ S ’ 开始的字符串 “ST”。

在这里插入图片描述

3.4:cpp[-1][-1] + 1

  • 注意:此时的 cpp 还是指向 cp[2] 的位置
  • cpp[-1][-1] + 1 等于 *(*(cpp - 1) - 1) + 1
  1. cpp[-1] 等价于 *(cpp - 1) ,cpp - 1 指向 cp[1] 这块空间。
  2. cpp[-1][-1] 等于 (cpp - 1) - 1,(cpp - 1) 的结果是 c + 2 这个数值,*(cpp - 1) - 1 是让 c + 2 这个数值变成 c + 1,然后再对这个值进行解引用,此时得到的值为 “NEW” 的首字符 ‘N’ 的地址。
  3. 从 ‘N’ 的地址 + 1,指向 ‘E’ 的地址。
  4. 最后以 &s 的形式打印从 ‘E’ 开始的字符串 “EW”。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/919063.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

一文速学-让神经网络不再神秘,一天速学神经网络基础(一)

前言 思索了很久到底要不要出深度学习内容,毕竟在数学建模专栏里边的机器学习内容还有一大半算法没有更新,很多坑都没有填满,而且现在深度学习的文章和学习课程都十分的多,我考虑了很久决定还是得出神经网络系列文章,…

这才是教室巡课正确的打开方式,你做的太Low了!

随着教育领域不断演变和技术的不断进步,在线巡课系统正在逐渐引起人们的关注。通过实时观察教师的课堂教学,系统为教育管理者提供了窗口,使他们能够更深入地了解教学实践,从而更好地满足学生的学习需求。 在线巡课系统为教育管理者…

小梦C嘎嘎——启航篇】C++STL 中 list日常使用的接口介绍

小梦C嘎嘎——启航篇】CSTL 中 list日常使用的接口介绍😎 前言🙌什么是list?常用的函数接口无参的构造函数接口拷贝构造接口赋值运算符重载 总结撒花💞 😎博客昵称:博客小梦 😊最喜欢的座右铭&a…

Linux知识点 -- Linux多线程(三)

Linux知识点 – Linux多线程(三) 文章目录 Linux知识点 -- Linux多线程(三)一、线程同步1.概念理解2.条件变量3.使用条件变量进行线程同步 二、生产者消费者模型1.概念2.基于BlockingQueue的生产者消费者模型3.单生产者单消费者模…

如何创建「录取查询系统」?

随着高校招生规模的不断扩大,学校录取工作变得越来越繁琐。为了提高效率和准确性,许多学校开始采用电子化的录取查询系统。易查分作为一款功能强大的在线查询工具,可以帮助学校快速搭建自己的「录取查询系统」。 好消息!博主给大家…

【C++代码】二分查找,移除元素

题目:二分查找 给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。 题解 在升序数组 nums \textit{nums} nums …

Linux安装mysql ( ARM架构,rpm包)

下载对应的mysql 阿里源:阿里巴巴开源镜像站-OPSX镜像站-阿里云开发者社区 华为开源镜像站_软件开发服务_华为云 华为源: 华为开源镜像站_软件开发服务_华为云 选择华为鲲鹏镜像 https://repo.huaweicloud.com/kunpeng/yum/el/7/aarch64/ 下载mysql wg…

【3ds Max】练习——制作衣柜

目录 步骤 一、制作衣柜顶部 二、制作衣柜门板 三、制作衣柜底部 四、制作柜子腿部 五、制作柜子底板 步骤 一、制作衣柜顶部 1. 首先创建一个平面,然后将图片素材拖入平面 2. 平面大小和图片尺寸比例保持一致 3. 单机鼠标右键,选择对象属性 勾选…

简历考察点2_《CiCi-基于Vue3.0的智能音乐分享平台》

(1)项目初始化和推荐页面开发: 重点:轮播图、Scroll、下拉加载方法实现、 问题一:轮播图实现 ① 获取轮播图数据:虽然找到接口了,但是由于XHR请求在浏览器端会有跨域的限制,不能直…

8_分类算法-k近邻算法(KNN)

文章目录 1 KNN算法1.1 KNN算法原理1.2 KNN过程1.3 KNN三要素1.4 KNN分类预测规则1.5 KNN回归预测规则1.6 KNN算法实现方式(重点)1.7 k近邻算法优缺点 2 KD-Tree2.1 KD Tree构建方式2.2 KD Tree查找最近邻2.3 KNN参数说明 1 KNN算法 定义:如…

fineReport10问题笔记

1. word导出相关问题 1.1 导出文字为图片 fineReport技术文档 1)文本控制 选中单元格,点击「单元格属性>样式>对齐」,文本控制设置有四种,分别为「自动换行、单行显示、单行显示(调整字体)、多行显…

AA实验是什么?

AA实验是什么:AA实验是在AB实验正式上线前做的分流均匀性检验,这个时候还没有正式上实验策略,只是为了检验两组的分流是否均匀先空跑一段时间。 AA实验的准备工作:这个时候要进行的工作是检查 两组分流是否均匀 、埋点是否正常 。…

精益求精:通付盾安卓应用加固升级,为移动安全保驾护航!

在如今竞争激烈的移动应用领域,保障应用资源的安全性成为刻不容缓的任务。最近,通付盾针对资源加密方案进行了全面升级,大幅增强了其兼容性,实现了更全面的资源文件类型保护。这次升级为移动应用的安全性和稳定性迈出了坚实的一步…

driver‘s license exam 2

机动车科目二内容 driver‘s license exam 1_spencer_tseng的博客-CSDN博客 driver‘s license exam 2_spencer_tseng的博客-CSDN博客 driver‘s license exam 3_spencer_tseng的博客-CSDN博客 driver‘s license exam 4_spencer_tseng的博客-CSDN博客 car indicator light…

跨平台图表:ChartDirector for .NET 7.1 Crack

什么是新的 ChartDirector for .NET 7.0 支持跨平台使用,但仅限于 .NET 6。这是因为在 .NET 7 中,Microsoft 停止了用于非 Windows 使用的 .NET 图形库 System.Drawing.Common。由于 ChartDirector for .NET 7.0 依赖于该库,因此它不再支持 .…

物通博联嵌入式数据采集网关采集传感器的数据上传到云端

在当今的物联网(IoT)时代,各种传感器广泛应用于各种工业领域。传感器数据采集是实现自动化生产的基础,可以为企业决策提供科学的数据支持,通过各类智能传感器采集传输终端,将采集的传感器数据实时传输到设备…

2048. 下一个更大的数值平衡数;1292. 元素和小于等于阈值的正方形的最大边长;2707. 字符串中的额外字符

2048. 下一个更大的数值平衡数 核心思想:枚举直接从n1开始枚举它是不是平衡数即可。 1292. 元素和小于等于阈值的正方形的最大边长 核心思想:枚举正方形的左上角优化。优化部分有两部分,第一部分是计算面积的优化,预先处理好g,让…

LVS集群 (NET模式搭建)

目录 一、集群概述 一、负载均衡技术类型 二、负载均衡实现方式 二、LVS集群结构 一、三层结构 二、架构对象 三、LVS工作模式 四、LVS负载均衡算法 一、静态负载均衡 二、动态负载均衡 五、ipvsadm命令详解 六、搭建实验流程 一、首先打开三台虚拟机 二、…

SpreadsheetGear 2017 2023 for .NET Crack

SpreadsheetGear 2017 & 2023 for .NET Crack Spreadsheet Gear for.NET被描述为允许用户和开发人员使用iOS、Android、Mac OS、Linux,最后是UWP,以利用可扩展的Excel报告以及与图表API兼容的全面Excel,以及为用户和开发人员提供的最快、…

Rancher证书更新

一、环境 主机名 IP地址 操作系统 rancher版本 K8s-Master 192.168.10.236 Centos 7 2.5.9 二、更新证书 1、查看当前证书到期时间 2、进行证书轮换 [rootK8s-Master ~]# docker ps |grep rancher/rancher d581da2b7c4e rancher/rancher:v2.5.9 …