【经典笔试题2】

news2024/11/20 2:43:01

test1

test2

test3

test4

test5

test1

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取到整个数组的地址,+1跳过了整个数组,a强转成int*类型,然后赋值给ptr,此时ptr指向的就是数组a后面的地址,如下图:

在这里插入图片描述

(ptr -1 ) ,指针-1, 跳过了一个int,指向了5的地址,再*,找到了5。
a是数组名,表示数组首元素地址,即1的地址,a+1,跳过一个int,表示第二个元素地址,再 *,找到了第二个元素,即2。
所以打印的结果是2 ,5

test2


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 ;
printf("%p\n", p + 0x1);
printf("%p\n", (unsigned long)p + 0x1);
printf("%p\n", (unsigned int*)p + 0x1);
return 0;
}

关于结构体大小为什么是20字节,具体可以参考结构体内存对齐问题,这里的重点是题目的讲解。

来看:p是一个结构体之这么,p + 0x1,0x1的意思就是16进制的1,相当于指针+1(十六进制),由于p是一个结构体指针,该结构体指针的大小是20字节,所以p+1跳过了20个字节,即0x10 00 14,(16进制的结果)。
第一个打印结果,以%p形式打印,打印的是地址,由于0x10 00 14不够一个十六进制的打印方式,所以需要在前面补00,即0x00 10 00 14

对于第二个打印 p被强转成了unsigned long类型,是长整型,p+1,就是整型+1,整型+1就是+1,就跳过一个字节,即0x10 00 01,所以以%p形式打印出来,就是0x00 10 00 01。

对于第三个打印,p被强转成unsigned int*的指针,是一个整型指针,指针+1,跳过一个整型,即跳过4个字节,所以是0x10 00 04,以%p形式打印,就是0x00 10 00 04.
在这里插入图片描述
结果如上:0x会在打印的时候自动省略。

test3

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

分析:
a是数组名,&a,取到的是整个数组的地址,+1就跳过了整个数组,此时ptr1指向如下图:

在这里插入图片描述
ptr[-1] == *(ptr-1) ,此时找到了4,以%x的形式打印出来,

在这里插入图片描述
4的十六进制形式仍然是4,故打印的是4.
对于ptr2, a被强转成int类型,a就是整型地址,假设a的地址是0x0012FF40,那么a+1就是0x0012FF41,增加的是一个字节的大小,即跳过了一个字节的地址,如下图:

在这里插入图片描述
*ptr2,就顺着ptr所在地址,往后访问4个字节。

在这里插入图片描述
由于计算机是小端存储,低位放在低地址,高位放在高地址,故读取时是 0x02 00 00 00,以%x的形式打印出来,结果就是2000000,2前面的0对于%x来说是没有意义的,所以不会打印出来。所以两个打印的结果是4,2000000

test4

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来说,a的类型是 int(*)[5] ,对于p来说,

p的类型是 int (*)[4],所以我们可以知道,p和a的类型并不相同,有所差异,这将会导致在下面的地址访问有差异,

在这里插入图片描述
a和p在内存中的地址如下图,a[4][2]和p[4][2]的地址也如下图:

在内存中,数组下标是从低地址向着高地址增长的,所以上图左边是低地址,右边是高地址,所以p[4][2]的地址小于a[4][2]的地址。
p[4][2] 和a[4][2]之间相差4个元素,故以%d打印出来是 -4 ,(小-大),以%p的形式打印的话,由于%p打印的是地址,所以先将-4的原码反码补码先写出来,(-4在内存中是以补码来存储的).

1000 0000 0000 0000 0000 0000 0000 0100 - 原码
11111111111111111111111111110111 - 反码
1111 1111 1111 1111 1111 1111 1111 1000 - 补码

对于%p而言,%p认为-4 的补码就是地址,地址没有原码反码的说法,所以直接打印-4的补码(以16进制的形式),对于-4的补码,翻译成16进制就是 FF FF FF FC ,故打印结果就是
FFFFFFFC,-4

在这里插入图片描述

test5

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

这道题目较为复杂,先画图理解:

在这里插入图片描述

c是一级指针数组,cp是二级指针数组,存储的是一级指针数组的地址,cpp是三级指针,指向二级指针数组的地址。

先看第一个printf,先++cpp,cpp最初指向的是cp首元素地址,++后,cpp指向第二个元素地址。

在这里插入图片描述
然后*cpp,此时找到了cp第二个元素,而这个元素是c+2,也就是c的第三个元素的地址,

再进行*,即对c+2进行 *,也就找到了c+2这个元素,即POINT,此时打印出来,也就是打印出POINT。

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

对于第二个printf,注意:此时cpp已经指向了cp第二个元素的地址:

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

先++cpp,此时cpp指向了cp第三个元素的地址,

在这里插入图片描述
再进行*,找到了c+1这个元素,然后对c+1进行–操作,即从c+1变成了c,此时找到了c这个元素,而c就是数组首元素的地址,即ENTER的地址,再进行* 操作,找到了ENTER,然后+3,跳过了三个字符,找到了ER,打印出来的结果就算ER。

对于第三个printf,

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

[]的优先级比*的优先级高,所以cpp先和[-2]结合,即cpp[-2],等价于 *(cpp-2),此时cpp指向的是cp第三个元素的地址,-2就指向了第一个元素的地址,即c+3的地址,*操作后,找到了c+3这个元素,而c+3就是c这个数组第三个元素的地址,再 * 操作后,找到了c数组第三个元素,即FIRST,再+3,找到了ST,所以打印出来ST。

对于第四个printf,

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

注意,第三个printf并没有改变cpp指向的位置,因为在第三个printf中,没有对cpp进行++或者–的操作,

对第四个printf , cpp[-1] == *(cpp-1),cpp[-1][-1] ==
*( *(cpp -1) -1) ,即cpp先-1操作,cpp此时是指向cp第三个元素地址:
在这里插入图片描述
即c+1的地址,cpp-1操作后,指向了c+2的地址,*后,找到了c+2这个元素,再进行-1操作,即对c+2进行-1操作,即c+2-1 = c+1,c+1就是数组c的第二个元素的地址,也就是NEW的地址,然后进行 *操作后,找到了NEW,再+1,即找到了EW,打印出来的结果就是EW。

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

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

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

相关文章

详解Web服务器与http https协议工作过程

Web服务器 URL URI URL是URI的一个子集 www www所用的协议 http请求报文分析 状态码(空行:最后一 个响应头部之后是一个空行,发送回车符和换行符,通知服务器以下不再有响应头部。) 网址解析 网址注释实例 HTT…

从工厂方法到注解的小例子

目录一、背景介绍二、思路&方案三、过程过程图一过程图二过程图三过程图四(运行时的图)代码四、总结五、升华一、背景介绍 上篇"自定义注解和注解解析器",通过小例子介绍了自定义注解的运用;本篇继续基于小例子来实现工厂方法,以及注解实…

linux Regmap API

1.针对 I2C 和 SPI 设备寄存器的操作都是通过相关的 API 函数进行操作的。这样 Linux 内核中就会充斥着大量的重复、冗余代码,但是这些本质上都是对寄存器的操作,所以为了方便内核开发人员统一访问I2C/SPI 设备的时候,为此引入了 Regmap 子系…

如何用智能地教狗狗上厕所

背景 22年养了一只很可爱的小狗狗,我其实就一个问题:为啥这么可爱的狗狗会拉屎撒尿呀? 自从崽崽来了我们家之后,最让我们头疼的就是它乱拉、乱尿的问题了,以前会在家里到处乱来,最近一段时间好了很多&…

机器学习(整体结构)

国科大《机器学习》内容,周晓飞老师讲的挺不错的,浅显易懂。 本来是想整理下课程内容的,然而动手后才发现内容过多(很想吐槽,为啥这么多模型?不能相互替代么?)简略画个思维导图算啦…

探索SpringMVC-HandlerAdapter之RequestMappingHandlerAdapter-返回值处理

前言 上回我们回答了ReqeustMappingHandlerAdapter调用目标方法的参数解析问题,今天我们再来回答第二个问题:怎么处理方法调用的返回值。 深入分析返回值处理需求 RequestMapping处理器的返回值类型 相信很多同学对于这个返回值的第一个反应就是返回一…

图解JDK1.7中HashMap头插法扩容造成的死循环问题

JDK1.7中HashMap头插法扩容造成的死循环问题 文章目录JDK1.7中HashMap头插法扩容造成的死循环问题一、背景二、源码解读三、图解单线程环境中扩容多线程环境中扩容四.总结一、背景 HashMap是线程不安全的,在并发使用HashMap时很容易出现一些问题,其中最…

ArcGIS基础实验操作100例--实验66符号图层的保存与加载

本实验专栏参考自汤国安教授《地理信息系统基础实验操作100例》一书 实验平台:ArcGIS 10.6 实验数据:请访问实验1(传送门) 高级编辑篇--实验66 符号图层的保存与加载 目录 一、实验背景 二、实验数据 三、实验步骤 &#xff0…

【OpenGL】基础光照

介绍 现实世界中的光照是极其复杂,难以计算的,因此OpenGL的光照使用的是简化的模型,其中一个模型被称为冯氏光照模型(Phong Lighting Model)。 冯氏光照模型的主要结构由三个分量组成: 环境(Ambient)光照漫反射(Diffuse)光照镜…

blender学习笔记2023.01.05

文章目录why基操why 想画条大黄鱼 想画一下渔网 网箱 写笔记预防忘记 基操 1.语言改为中文 不过后续可能改回英文去 2.顶部导航栏—编辑—偏好设置—界面—翻译—(关掉)新建数据 目的是预防插件导致奇奇怪怪的报错 这里左下角位置处点击 保存修改 3…

初识LCD1602及编程实现字符显示

一、LCD1602基础知识及接线方法LCD1602是一种工业字符型液晶,能够同时显示16x02即32字符(16列两行)引脚说明第 1 脚: VSS 为电源地 第 2 脚: VDD 接 5V 正电源 第 3 脚: VL 为液晶显示器对比度调整端,接正电源时对比度最弱,接地时…

【Neo4j构建知识图谱】:官方服务图谱大型数据集下载与可视化方法【数据集包括:食谱数据、足球、权力的游戏、美国宇航局、英国公司注册、财产所有权、政治捐款】

目录 1、服务端口免费查看知识图谱2、关于 Neo4j 示例数据集的实现3、下载离线数据集4、项目概览与实现案例还可以看到解析python源码还可以看到解析cypher源码各种数据集实现案例参考1、服务端口免费查看知识图谱 此服务器托管许多具有只读访问权限的数据集,供公众使用。 该…

2022尚硅谷SSM框架跟学(三)MyBatis基础三

2022尚硅谷SSM框架跟学 三 MyBatis基础三9.动态SQL9.1if9.2where方法一:加入恒成立的条件方法二:使用where标签9.3trim9.4choose、when、otherwise9.5foreach9.51批量添加9.52批量删除批量删除方式1批量删除方式2批量删除方式39.6SQL片段10.MyBatis的缓存10.1MyBatis的一级缓存…

JS基础(一)——认识JS及其基础语法

网页的三个组成部分 HTML:用于控制网页的内容CSS:用于控制网页的样式JavaScript:用于控制网页的行为 网页的行为指用户与浏览器的行为交互、浏览器与浏览器与服务器的数据交互。 ECMAScriptS(ES) ECMAScriptS是Java…

OpenCV入门

OpenCV入门图像金字塔高斯金字塔(cv2.pyrUp、cv.pyrDown)拉普拉斯金字塔边缘检测图像轮廓 (cv2.findContours)轮廓特征(cv2.contourArea、cv2.arcLength)轮廓近似(cv2.approxPolyDP)边界矩形、外接圆(cv2.boundingRect、cv2.minEnclosingCircle)模板匹配…

C库函数:time.h

time.h C 标准库 – <time.h> | 菜鸟教程 (runoob.com) 库变量 下面是头文件 time.h 中定义的变量类型&#xff1a; 序号变量 & 描述1size_t 是无符号整数类型&#xff0c;它是 sizeof 关键字的结果。2clock_t 这是一个适合存储处理器时间的类型。3time_t is 这是一…

C库函数:math.h

math.h C 标准库 – <math.h> | 菜鸟教程 (runoob.com) 16double pow(double x, double y) 返回 x 的 y 次幂。17double sqrt(double x) 返回 x 的平方根。18double ceil(double x) 返回大于或等于 x 的最小的整数值。19double fabs(double x) 返回 x 的绝对值。20doubl…

矩阵分析:QR分解

Householder变换 Householder变换是一种简洁而有意思的线性变换&#xff0c;也可称为镜面反射变换&#xff0c;Householder变换矩阵为HI−wTwHI-w^TwHI−wTw 考虑向量α\alphaα和一个单位向量w:wTw1w:w^{T}w1w:wTw1 α\alphaα在www 方向上的分量是 αw//(wTα)wwwTα\alpha _…

Python快速制作自动填写脚本:100%准确率

嗨害大家好鸭&#xff01;我是小熊猫~ 环境使用 Python 3.8Pycharm 模块使用 import requests —> 数据请求模块 pip install requestsimport parsel —> 数据解析模块 pip install parselfrom selenium import webdriver —> 自动测试模块 pip install selenium3.…

#H. Linear Approximation

Description给你一个数列A&#xff0c;希望你找出一个数字B。使得下面这个式子的值最小Abs(A1-(B1))Abs(A2-(B2))Abs(A3-(B3))..........Abs(An-(Bn))FormatInput第一行给出输入n第二行给出数列A,数字的值在[1,1e9]N<2e5Output如题Samples输入数据 152 2 3 5 5输出数据 12思…