【C语言】带你完全理解指针(六)指针笔试题

目录

 

1.

 2.

 3.

4.

5.

6.

 7.

 8.


 

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

【答案】

2,5

【解析】

定义了一个指向整数的指针ptr,并将其初始化为&a + 1。这里&a表示整个数组a的地址,而&a + 1表示数组a之后的位置,也就是数组a的末尾之后的位置。

由于ptr指向a的末尾之后的位置,所以*(ptr - 1)表示ptr指向的位置向前偏移一个int的大小,即指向了数组a的最后一个元素。

然后在printf语句中使用*(a + 1)等价于a[1]表示数组a中的第2个元素,也就是2。使用*(ptr - 1)表示数组a中的最后一个元素,也就是5。

因此,最终输出结果为2,5

图解:



 

 2.

struct Test
{int Num;char* pcName;short sDate;char cha[2];short sBa[4];
}*p;
//假设p 的值为0x100000。 如下表表达式的值分别为多少?
//已知,结构体Test类型的变量大小是20个字节
//0x开头的数组是16进制的数字
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;
}
printf("%p\n", p + 0x1);

 这个表达式中,p是一个指针,+ 0x1表示将指针向后偏移1个Test结构体的大小。由于Test结构体的大小是20字节,所以偏移后的地址为0x100014。在printf中使用%p格式化字符串输出这个地址


printf("%p\n", (unsigned long)p + 0x1);

这个表达式中,首先将指针p强制转换为unsigned long类型,然后再加上0x1。这样会将指针的值视为无符号长整型进行计算。假设在你的系统中,unsigned long类型和指针类型都占用4个字节,那么指针的值将会被当做无符号长整型的值来处理。也就是说现在是无符号数了不是指针了。在此基础上,再加上0x1。结果为0x100001。在printf中使用%p格式化字符串输出这个地址。


printf("%p\n", (unsigned int*)p + 0x1);

这个表达式中,首先将指针p强制转换为unsigned int*类型,这里假设unsigned int类型占用4个字节,然后再加上0x1。这样做会将指针的值视为unsigned int类型的指针,并对指针值进行偏移。由于指针类型是unsigned int*,每次偏移一个字节,所以结果为0x100004。在printf中使用%p格式化字符串输出这个地址。



 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);return 0;
}

 

ptr1[-1]等价于*(ptr1-1),表示ptr1向前挪动一个整型指向4,结果就为4

*ptr2整型指针访问四个字节(即红框所框处),此时为内存存放的图解,需要转成真实值即0x02000000。



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[3][2]中实际存储的是{1,3,5}。将a[0]赋值给p指针,即p指向数组第一行地址,再通过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;
}

 【答案】

FFFFFFFC,-4

a的类型是int (*) [5] ——— 即a指针指向一个大小为5的数组

p的类型是int (*) [4] ——— 即p指针指向一个大小为4的数组

当把a所指的地址赋值给指针p之后,a p指向同一地址,但是由于a认为自己指向的是5个元素的数组,而p认为自己指向的是4个元素的数组,这就会导致它们就算下标相同时访问到的内容也是不一样的,如图所示。

printf("%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);

随着数组下标的增长,地址是由低到高的变化,并且指针和指针相减的绝对值得到的是指针之间的元素个数,而当取出p[4][2]和a[4][2]的地址之后相减,就是小地址减去大地址,得到一个负数,就是-4。

%p是打印地址,会认为内存中存储的补码就是地址,所以就是打印-4的补码

原码:10000000 00000000 00000000 00000100

反码:11111111  11111111  11111111   11111011

补码:11111111  11111111  11111111   11111100

以%p地址的形式打印补码转成16进制表示:FF FF FF FC

原码反码补码的转换在之前的博客有涉及原码、反码、补码。有符号整数的表示和运算。-CSDN博客

而-4以%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;
}

 【答案】10,5

【解析】

  1. 首先,int aa[2][5] 声明了一个2行5列的二维数组,并初始化了其中的元素。

  2. int* ptr1 = (int*)(&aa + 1); 中的 &aa 是取二维数组 aa 的地址,表示整个二维数组的起始地址。然后通过 + 1 将指针向后移动,指向数组的下一个位置。最后将结果强制转换为 int* 类型,赋值给 ptr1

  3. int* ptr2 = (int*)(*(aa + 1)); 中的 *(aa + 1) 表示取二维数组 aa 中的第2行的地址。然后将结果强制转换为 int* 类型,赋值给 ptr2

  4. *(ptr1 - 1) 表示 ptr1 所指向的元素的前一个元素的值。在这里,它指向二维数组 aa 的最后一个元素。

  5. *(ptr2 - 1) 表示 ptr2 所指向的元素的前一个元素的值。在这里,它指向二维数组 aa 的第一行的最后一个元素。

所以,最后的输出结果为:
10, 5,其中 *(ptr1 - 1) 的值为二维数组 aa 的最后一个元素 10,*(ptr2 - 1) 的值为二维数组 aa 的第一行的最后一个元素 5。

 



7.

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

【答案】at

【解析】

 a的地址赋值给pa。然后通过pa++pa指向了a数组中的第二个指针元素



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

【答案】

POINT

ER

ST

EW 

【解析】

最初状态:


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

** ++cpp,cpp先自增1,跳过一个char**类型指向下一个元素的地址,如图。

此时再对cpp进行解引用,找到cp[1],再解引用,找到c[2]即P的地址。此时%s打印出来就是POINT


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

【* -- * ++cpp + 3】,加号优先级是最低的,所以最后算。cpp先自增1跳过一个char**大小指向下一个元素的地址,如图。

此时再对cpp进行解引用,找到的是cp[2]即指向了c+1这块空间,再自减1则指向了c这块空间,再解引用找到了c[0]即ENTER中第一个E的地址,此时+3跳过三个char,最后指向ENTER中第二个E的地址,此时用%s打印出来就是ER

第一步++cpp也就是指向cp中的第三个元素c+1这块空间

第二步*++cpp,也就是得到cp[2]

第三步-- * ++cpp,c+1变为c

第四步* -- * ++cpp,找到了c中的第一个元素所指向的ENTER的空间指针指向E

第五步* -- * ++cpp + 3,从指向E变为指向E。


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

*cpp[-2] + 3】等价于【* *(cpp-2)+3】,与前面的cpp自增自减不同,cpp-2只是表达式并不会改变cpp的指向。

第一步cpp指向的位置向前移动两位之后解引用找到cp中的第一个元素也就是c+3,

第二步解引用找到c中的第4个元素也就是c[3]指向的是first。

第三步指针加三也就是从指向F变为指向S

所以答案是ST


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

【 cpp[-1][-1] + 1】等价于【*(*(cpp-1) -1) + 1】

*(cpp-1)找到c+2,c+2再-1就是c+1的地址,再进行解引用找到NEW中N的地址,再+1找到E的地址,此时用%s打印出来就是EW

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

通过Omnet++官网tictoc教程学习在Omnet++中构建和运行仿真 Part4

官方链接 文章目录 Part4:让仿真更像实际网络增加节点信道和内部类型定义双向连接的链路自定义消息类 Part4:让仿真更像实际网络 增加节点 现在我们将迈出一大步:创建几个tic模块并将它们连接到一个网络中。现在,我们将保持简单:其中一个节…

苹果电脑启动磁盘是什么意思 苹果电脑磁盘清理软件 mac找不到启动磁盘 启动磁盘没有足够的空间来进行分区

当你一早打开苹果电脑,结果系统突然提示: “启动磁盘已满,需要删除部分文件”。你会怎么办?如果你认为单纯靠清理废纸篓或者删除大型文件就能释放你的启动磁盘上的空间,那就大错特错了。其实苹果启动磁盘的清理技巧有很…

pyside6自定义部件库和软件框架的建设记录

自定义的部件库原则上尽量做到前后端分离,接口方便,复制简单。 单选框部件 # encoding: utf-8 ################################################### # 自定义的单选框 #################################################### 对外接口&…

蓝桥杯2024年第十五届省赛真题-R 格式(高精度乘法 + 加法)

本题链接:蓝桥杯2024年第十五届省赛真题-R 格式 - C语言网 题目:​​​​​​​ 样例: 输入 2 3.14 输出 13 思路: 根据题意,结合数据范围,这是一道模板的高精度乘以低精度问题。 题意是double 类型 d 与…

【C++】类和对象③(类的默认成员函数:拷贝构造函数 | 赋值运算符重载)

🔥个人主页:Forcible Bug Maker 🔥专栏:C 目录 前言 拷贝构造函数 概念 拷贝构造函数的特性及用法 赋值运算符重载 运算符重载 赋值运算符重载 结语 前言 本篇主要内容:类的6个默认成员函数中的拷贝构造函数…

由于找不到krpt.dll,无法继续执行代码的5种解决方法

在正常使用电脑的过程中,当尝试启动某个应用程序或者执行特定功能时,系统突然弹出一个错误提示窗口,明确指出由于缺失关键性文件——krpt.dll,导致当前运行的软件无法正常读取并执行相应的程序代码,进而无法顺利完成预…

Neo4j 图形数据库中有哪些构建块?

Neo4j 图形数据库具有以下构建块 - 节点属性关系标签数据浏览器 节点 节点是 Graph 的基本单位。 它包含具有键值对的属性,如下图所示。 NEmployee 节点 在这里,节点 Name "Employee" ,它包含一组属性作为键值对。 属性 属性是…

Hit the World Hit世界 Hit2日服官网地址+配置要求+测试时间

Hit the World/Hit世界/Hit2日服官网地址配置要求测试时间 Hit the World/Hit世界是NEXON旗下MMOROG游戏,作品类型上是典型的类天堂游戏,升级思路很简单,一般是跟着主线走,除了主线还有副本升级。支持移动和PC两端,继…

1113. 红与黑--Flood Fill 算法

目录 1113. 红与黑--Flood Fill 算法---宽搜(BFS)或DFS) 输入格式 输出格式 数据范围 输入样例: 输出样例: 思路: 1.BFS 思路: 2.DFS 思路 方法一:(BFS&#x…

STM32H7的8个串口fifo收发(兼容232和485)

STM32H7的8个串口fifo收发(兼容232和485) 串口硬件串口时序串口高级特性同步和异步的区别单工、半双工、全双工的区别 STM32H78个串口fifo驱动定义数据结构uart_fifo.huart驱动包括中断配置等 应用示例RS485深入理解 仅供学习。 USART 的全称是 Universa…

【电控笔记6.2】拉式转换与转移函数

概要 laplace:单输入单输出,线性系统 laplace 传递函数 总结

sqlilabs靶场1—20题学习笔记(思路+解析+方法)

前几个题目较为简单,均尝试使用各种方法进行SQL注入 第一题 联合查询 1)思路: 有回显值 1.判断有无注入点 2.猜解列名数量 3.判断回显点 4.利用注入点进行信息收集 爆用户权限,爆库,爆版本号 爆表,爆列&…

全球顶级的低代码开发平台,你知道几个?

什么是低代码开发平台? 低码开发平台是一个应用程序,提供图形用户界面编程,从而以非常快的速度开发代码,减少了传统的编程工作。 这些工具有助于快速开发代码,最大限度地减少手工编码的努力。这些平台不仅有助于编码,而且还能快速安装和部署。 低码开发工具的好处 低代码平…

3dmax在线渲染怎么取消?怎么关闭云渲染

在线渲染,无论是通过云渲染服务还是渲染农场,已经成为众多3dmax动画制作者的首选方式来执行渲染任务。然而,如果在渲染过程中需要禁用这一在线渲染功能,该怎么操作呢?接下来,让我们一起探讨如何关闭这一功能…

【精读文献】Scientific data|2017-2021年中国10米玉米农田变化制图

论文名称:Mapping annual 10-m maize cropland changes in China during 2017–2021 第一作者及通讯作者:Xingang Li, Ying Qu 第一作者单位及通讯作者单位:北京师范大学地理学部 文章发表期刊:《Scientific data》&#xff08…

书生浦语学习第二课 轻松玩转书生浦语趣味Demo

本节课让同学们实践 4 个内容,分别是:部署 InternLM2-Chat-1.8B 模型进行智能对话、部署一期实战营优秀作品 八戒-Chat-1.8B 模型、 运行 Lagent 智能体 Demo、实践部署 浦语灵笔2 模型。 第一步,打开 Intern Studio 界面,点击 创…

【Qt 学习笔记】Qt常用控件 | 按钮类控件Check Box的使用及说明

博客主页:Duck Bro 博客主页系列专栏:Qt 专栏关注博主,后期持续更新系列文章如果有错误感谢请大家批评指出,及时修改感谢大家点赞👍收藏⭐评论✍ Qt常用控件 | 按钮类控件Check Box的使用及说明 文章编号:…

CSS实现卡片在鼠标悬停时突出效果

在CSS中,实现卡片在鼠标悬停时突出,通常使用:hover伪类选择器。 :hover伪类选择器用于指定当鼠标指针悬停在某个元素上时,该元素的状态变化。通过:hover选择器,你可以定义鼠标悬停在元素上时元素的样式,比如改变颜色、…

基于Docker构建CI/CD工具链(七)使用Jmeter进行自动化压测

上一篇文章中,我们详细介绍了构建 Apifox Cli 的 Docker 镜像的步骤,并通过简单的示例演示了如何利用 GitLab 的 CI/CD 功能,将构建好的镜像利用在自动化测试作业中。在今天的文章中,我们将重点讨论如何构建 JMeter 的 Docker 镜像…

【Entity Framework】你知道如何处理无键实体吗

【Entity Framework】你知道如何处理无键实体吗 文章目录 【Entity Framework】你知道如何处理无键实体吗一、概述二、定义无键实体类型数据注释 三、无键实体类型特征四、无键实体使用场景五、无键实体使用场景六、无键使用示例6.1 定义一个简单的Blog和Post模型:6…