《c语言深度解剖》--一套非常经典的笔试题

news2024/12/26 23:25:54

学习完c语言,需要对所学知识进行一个检测,下面有一套笔试题,
你有四十分钟进行检测,每道题五分,严格要求自己打分

根据作者原话:在没有何提示的情况下,如果能得满分,那你可以扔掉本书了,因为你的水平已经大大超过了作者;如果能得80分以上,说明你的C语言基础还不错,学习本书可能会比较轻松;如果得分在50分以下,也不要气馁,努力学习就行了;如果不小心得了10分以下,那就得给自己敲敲警钟了;如果不幸得了0分,那实在是不应该,因为毕竟很多题是很简单的。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
答案解析:
在这里插入图片描述
1.根据隐式类型转换存储规则:

long double
double
float
unsigned long int
long int
unsigned int
int
当连个不同类型的值比较或相加减时,默认从低到高转换,即向上转换

所以,a和b相加时,b会隐式转换成unsigned int类型,对于-20来说,其补码为:

100000000 00000000 00000000 00010100 -- 原码
1111111111 111111111 111111111  11101011 -- 反码
1111111111 111111111 111111111  11101100 -- 补码

此时b是无符号整型,首位不再被当成符号位,所以b成了一个很大的数字,加上a当然比6大。


在这里插入图片描述

2.运行到strcpy的时候可能会发生异常,因为str1存储了10个字符a之后,后面存储的不是’\0’,
strcpy拷贝时会寻找’\0’作为结束标志,str1中第10个字符a之后的空间不是str1的,是内存的空间,
strcpy从此地方开始向后寻找’\0’时,会造成内存的非法访问,可能会导致程序出现异常。


在这里插入图片描述

3.i = 10,j = 1.
由于静态的局部变量是再内存中的静态区存储,静态局部变量在初始化一次后不会被销毁,且只初始化一次,在下一次使用时仍然保持上一次的值。所以i只初始化一次,每次继续调用该函数时,仍然保留上一次i的值。
对于j来说,j是静态全局变量,每次调用函数都会被初始化.


在这里插入图片描述

4.除了(3)是400以外,其余全都是4。
(1)p是指针,被置为空, 所以p所指向的地址就是一个空地址,既然是地址,题目限定了在32位系统下,所以就是4个字节。
(2)p其实就是对p进行解引用,p是所指向的对象是一个int类型,计算p其实就是计算int类型的大小。
(3)对于数组来说,数组名表示数组首元素地址,除了下面两个例外:
1.sizeof(数组名),即数组名单独放在sizeof内部,表示的是整个数组的大小。
2.&数组名,取到的是整个数组的地址。

除了上面两个特例,其余的数组名都是表示数组首元素地址。

很明显:(3)中的数组名单独放在sizeof内部,计算的就是整个数组大小,a数组有100个元素,每个元素是int类型,总大小就是400字节。
(4)a[100]就是计算a的第100个元素的大小,虽然a[100]并不存在,也不影响计算a的第100个元素的大小,也是一个int类型。比如说:int b[1] = {0}; 计算sizeof(b[10]),大小仍为4个字节。

(5)&a,是上面两个特例中的第二个特例,取到的是整个数组的地址,其实,整个数组的地址就是首元素的地址,只是如果取到整个数组的地址后+1,会跳过整个数组。
既然它是地址,地址就是4个字节。
(6)&a[0],就是取首元素地址,是地址就是4字节。
(7)这是一个典型的数组传参问题,b传参时,因为b是数组首元素地址,本质上传的是一个int*的指针,形参部分int b[100],实际上这是一个指针,所以计算b的大小,就是计算指针的大小,即4个字节。(b不再是数组首元素地址,b是一个指针)


在这里插入图片描述

5.对于数组a来说,它的元素类型是signed char类型,范围是-128~127。a[0] = -1,a[1] = -2,…a[127] = -128,此时a[128]不可能是-129,因为:
-128的二进制原码是:

100000000 00000000 00000000 10000000

补码是:

11111111 11111111 11111111 10000000

存入a[127]中会发生截断,补码的低8位放进去,即
10000000放入,转化成原码为:

1 00000000 

而该原码规定就是-128。

而-129的二进制原码为:

100000000 00000000 00000000 10000001

补码为:

11111111 11111111 11111111 01111111

截取低8位存入a[128]中,是

01111111

转换成二进制原码是:

01111111

这是正数,正数的原码反码补码相同,转换成十进制是127.
所以a[128] = 127, a[129] = 126… ,直到a[255] = 0;
strlen计算长度时,就需要找’\0’作为结束标志,而0就代表’\0’。所以计算数组的长度时,大小为255.


在这里插入图片描述
6.(1)const放在p之前,限制的是 * p,所以p不可更改,但是p未被限制,所以p指向的对象可以更改。
(2)同(1),同样放在*p之前,结果同(1)
(3)const放在p之前,p之后,限制的是p,所以p指向的对象不可更改,p可以更改
(4)p和
p都被限制了,所以p指向的对象和
p都不可更改。


在这里插入图片描述

7.代码(1):这时候编译器对代码进行优化,因为在代码(1)的两条语句中,i没有被用作左值(没有被赋值)。这时候编译器认为i的值没有发生改变,所以在第1条语句时从内存中取出i的值赋给j之后,这个值并没有被丢掉,而是在第⒉条语句时继续用这个值给k赋值。编译器不会生成出汇编代码重新从内存里取i的值(不会编译生成装载内存的的汇编指令﹐比如ARM的LDM指令),这样提高了效率。但要注意:两条语句之间i没有被用作左值(没有被赋值)才行。

代码(2)的使用时机:如果i是一个寄存器变量、表示一个端口数据或者是多个线程的共享数据,那么就容易出错,所以说
volatile可以保证对特殊地址的稳定访问。

代码(2)的使用时机:如果i是一个寄存器变量、表示一个端口数据或者是多个线程的共享数据,那么就容易出错,所以说
volatile可以保证对特殊地址的稳定访问。


在这里插入图片描述

8.这道题需要画图理解。结果是 5,2000000
在这里插入图片描述
数组a的5个元素的十六进制表示形式在内存中的布局如上图:
对于ptr1来说,&a取到了整个数组的地址,+1跳过了整个数组,再强转成int*,所以ptr1指向的是数组的后一位的地址。如下图:
在这里插入图片描述
以16进制的形式打印ptr[-1]时,其实可以理解成打印 *(ptr-1),指针-1,跳过指针所指向对象的类型,ptr1指向的对象是int类型,所以-1跳过一个int。如下图:
在这里插入图片描述
指针指向的对象是一个int类型,所以一次取出4个字节。
由于计算机是小端存储模式,所以,低位放在低地址处,高位放在高地址处,拿出来就是 00 00 00 05,以十六进制的形式打印,5前面的0是不显示的,没什么意义,所以打印出来就是5。

对于ptr2来说,a是数组首元素地址,强转成(int),所以a的地址就被强转成了一个整型,假设a的地址为:0x0012ff40,该地址就被强转成了一个整型,此时0x0012ff40是一个整型,整型+1之后,就是0x0012ff41,加了一个字节(整型+1就是+1)。0x0012ff41再强转成一个int*的指针赋给ptr2。此时ptr2指向的位置如下图:
在这里插入图片描述
ptr2指向的对象是int类型,所以ptr2一次性会读取4个字节,即读取
00 00 00 02,由于计算机是小端存储,低位放在低地址,高位放在高地址。

所以以十六进制的形式表示是0x 02 00 00 00,以十六进制的形式打印出来是2 00 00 00,(02中的0会被去掉)


在这里插入图片描述
9.值为32
+号的优先级高于<<,先计算2+3,再计算0x01<<, 即
0x01<<5,
将0x01的十六进制补全是 0x00 00 00 01,转换成二进制的形式为:

00000000 00000000 00000000 00000001

<<操作符移动的是二进制位,左移5位后变成:

00000000 00000000 00000000 00100000

转换成十进制是32


在这里插入图片描述

10.答案:

#define SQR(x) ((x)*(x))

然而,该宏是有缺陷的,如果传入x++,++x这样有副作用的参数,宏就会出现问题。

(指出宏有缺陷者满分)


在这里插入图片描述
11.结构体在内存中的存储较为复杂,具体请看
结构体内存对齐
这里直接说明答案即可:
(在未说明的情况下,默认对齐数为8)
代码(1)的结构体大小为12字节,代码(2)的结构体大小为8字节。


在这里插入图片描述
12.实际上,这道题目是存在一点问题的,实际中不能随便找一个地址,就对该地址的内容进行访问,这是野指针问题,是非法访问的问题,对编译器来说这是违法行为。
相当于题目让你闯红灯,闯红灯本来就是违法行为。(这里没有针对任何人,只是就本道题说一下我的看法);

可能题目是想让写题人知道指针的强大和灵活,让写题人重视指针的运用。

不过如果真的要写,就是下面的写法:

int *p = (int*)0x12ff7c;
*p = 0x100;

在这里插入图片描述
13.
a表示数组首元素地址,a+1跳过了一个元素的大小,所以a+1就是a[1]的地址,*(a+1) 就拿到了a[1],所以结果是1。
对ptr来说,&a取到的是整个数组的地址,+1跳过了整个数组,所以ptr指向了元素5的后一位, * (ptr-1) 就指向5,打印出来就是5。


在这里插入图片描述
14. 0x100014,0x100001,0x010004
(1)
首先需要知道结构体的大小是多少,由上面结构体内存存储模式可知,该结构体大小为20字节。
p是一个结构体指针,指针+0x1,跳过了一个结构体的大小,所以p+1跳过了20字节,因为p的值为0x100000,所以p+1为0x100014,(20)转换为十六进制是14。
(2)
将p强转成unsigned long类型后,p的值就是一个长整型,即0x100000是unsigned long类型,整型+1就是+1.
结果为:0x100001

(3)将p强转成unsigned int*的指针,+1后跳过一个int类型,所以结果为0x100004


在这里插入图片描述
15.考察逗号表达式。
(0,1)计算的结果是1,(2,3)计算结果是3,(4,5)计算结果是5
a初始化后的结果为:

1 2
5 0
0 0

a[0]就是第一行元素的地址,此时p就是指向第一行元素的地址,然后打印p[0],相当于找到了第一行第一个元素,打印结果为1


在这里插入图片描述
16.(1)传参的时候有问题,b[10]实际上是不存在的。
(2)fun的参数部分,如果它是想对数组的a[3]进行修改,传参应该传b即可,因为b是数组名,数组名表示首元素地址,类型是char* ,想改变它的值,应该使用char*的指针来接收。

编译器会有一个警告,说类型不匹配,因为b[10]的类型是char,而函数参数类型是char*。


在这里插入图片描述
17.(1)在使用完pstu后没有置空,这是一个野指针问题。
(2)结构体的成员name也是一个指针,代码并没有给该指针申请空间,直接使用name会出现越界访问问题。


在这里插入图片描述
18,典型的递归问题,直接上答案:

0 
1 
2 
5 
10

在这里插入图片描述
19.
getchar函数的返回类型是一个int,但是c是一个char类型,将一个int类型放入char类型中会发生截断。‘
假如读取失败,getchar会返回EOF,EOF是一个宏,其本质是-1,
但有可能getchar读取失败返回的EOF不再-128~127这个范围内,导致if条件判断语句不进入,存在潜在的危险。


在这里插入图片描述

20.方法1:

int main()
{
	int a = 1;
	int ret = *((char*)&a);
	if (ret == 1)
	{
		printf("小端\n");
	}
	else
	{
		printf("大端\n");
	}
}

方法2:

union un
{
	int a;
	char c;
}s;

int main()
{
	s.a = 1;
	if (s.c == 1)
	{
		printf("小端\n");
	}
	else
	{
		printf("大端\n");
	}
	return 0;
}

在没有何提示的情况下,如果能得满分,那你可以扔掉本书了,因为你的水平已经大大超过了作者;如果能得80分以上,说明你的C语言基础还不错,学习本书可能会比较轻松;如果得分在50分以下,也不要气馁,努力学习就行了;如果不小心得了10分以下,那就得给自己敲敲警钟了;如果不幸得了0分,那实在是不应该,因为毕竟很多题是很简单的。

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

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

相关文章

【项目实战】32G的电脑启动IDEA一个后端服务要2min,谁忍的了?

一、背景 本人电脑性能一般&#xff0c;但是拥有着一台高性能的VDI&#xff08;虚拟桌面基础架构&#xff09;&#xff0c;以下是具体的配置 二、问题描述 但是&#xff0c;即便是拥有这么高的性能&#xff0c;每次运行基于Dubbo微服务架构下的微服务都贼久&#xff0c;以下…

认识 CSS pointer-events 属性

pointer-events 的基本信息 pointer-events 属性用来控制一个元素能否响应鼠标操作&#xff0c;常用的关键字有 auto 和 none pointer-events: none; // 让一个元素忽略鼠标操作 pointer-events: auto; // 还原浏览器设定的默认行为 规范定义 条目状态初始值auto可用值适用所…

【表格单元格可编辑】vue-elementul简单实现table表格点击单元格可编辑,点击单元格变成弹框修改数据

前言 这是继我另一个帖子就是单元格点击变成输入框后添加的功能 因为考虑到有些时候修改单元格的信息可能点击后要修改很多&#xff0c;那一个输入框不好用 所以这时候就需要一个弹框可以把所有表单都显示出来修改 所以这里就专门又写了一个demo&#xff0c;用于处理这种情况 …

深兰科技机器人商丘制造基地正式投产,助力商丘经济高质量发展

2月9日&#xff0c;深兰科技机器人商丘制造基地投产仪式在商丘市梁园区北航创新园隆重举行。商丘市人大常委会副主任、梁园区委书记张兵&#xff0c;梁园区区长薛天江、河南省装备制造业协会会长张桦&#xff0c;河南省机器人行业协会会长王济昌&#xff0c;深兰科技集团董事长…

使用ChatGPT和EZDML迅速高效生成可运行的软件系统原型

ChatGPT最近很热&#xff0c;其对程序员可以说影响极大&#xff0c;是不得不跟的潮流趋势&#xff0c;因此EZDML新版也把ChatGPT的支持加上了&#xff0c;可以在几分钟内按您的意思生成一个数据模型&#xff0c;再搭载使用EZDML自带的代码模板&#xff0c;能快速生成可真正运行…

基于FPGA的 SPI通信 设计(1)

引言 低速通信目前搞过 UART串口通信、IIC通信。其实 SPI 也算是中低速&#xff08;有时也可以用作高速通信&#xff09;串行通信的范畴&#xff0c;但是一直还没真正实现过&#xff0c;所以此系列就 SPI的协议以及FPGA设计作几篇博客记录。欢迎订阅关注~ SPI 标准协议 x1模式…

【软件测试】测试外包,我们该去吗?看看资深测试工程师的见解......

目录&#xff1a;导读前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09;前言 外包的含义和目的&a…

2023年家族办公室研究报告

第一章 概况 家族办公室最早起源于古罗马时期的大“Domus”&#xff08;家族主管&#xff09;以及中世纪时期的大“Domo”&#xff08;总管家&#xff09;。现代意义上的家族办公室出现于19世纪中叶&#xff0c;一些抓住产业革命机会的大亨将金融专家、法律专家和财务专家集合…

MySQL数据库14——更新和删除数据

SQL里面使用UPDATE更新数据&#xff0c;删除使用DELETE语句。 Mysql要修改一下设置&#xff0c;才能更新&#xff1a; 在左上角菜单栏里面选择偏好栏&#xff0c;取消下面这个红框的勾选 更新单个字段的数据 如果运行环境为MySQL 则使用以下语句进行备份。 CREATE TABLE stu…

VS中scanf报错+extern关键字+常量+转义字符

目录 一、解决VS中scanf报错 二、extern关键字 三、常量 &#xff08;一&#xff09;C语言中的常量分为以下以下几种 1. 字面常量 2. const 修饰的常变量 3. #define 定义的标识符常量 4. 枚举常量 四、转义字符 &#xff08;一&#xff09;\? &#xff08;二&…

轻松解决Session-Cookie 鉴权(含坑)附代码

Session-Cookie 鉴权 cookie介绍 Cookie 存储在客户端&#xff0c;可随意篡改&#xff0c;不安全有大小限制&#xff0c;最大为 4kb有数量限制&#xff0c;一般一个浏览器对于一个网站只能存不超过 20 个 Cookie&#xff0c;浏览器一般只允许存放 300个 CookieCookie 是不可跨…

力扣SQL刷题11

目录标题1194. 锦标赛优胜者--做出来了1225. 报告系统状态的连续日期-勉强1159. 市场分析 II1205. 每月交易II1194. 锦标赛优胜者–做出来了 题型&#xff1a;看题 解答&#xff1a;先处理matches表&#xff0c;整出分数列和players表连接 注意点&#xff1a; union all 时…

【逐步剖C】-番外篇-实用调试技巧

一、 Bug介绍 在正式开始讲解调试技巧之前先介绍一下我们亦敌亦友的Bug。 程序错误&#xff0c;即英文的Bug&#xff0c;也称为缺陷、臭虫&#xff0c;是指在软件运行中因为程序本身有错误而造成的功能不正常、死机、数据丢失、非正常中断等现象。 早期的计算机由于体积非常庞…

2.21、管程

管程就是一个软件模块&#xff0c;里面封装了实现同步&#xff0c;互斥的函数 1、为什么要引入管程 信号量机制存在的问题&#xff1a;编写程序困难、易出错 能不能设计一种机制&#xff0c;让程序员写程序时不需要再关注复杂的 PV 操作&#xff0c;让写代码更轻松呢? 1973年…

使用python从houdini导出arnold材质

先说结果,如果要使用python从houdini导出arnold材质可以使用以下命令 import hou import htoa vops [hou.node("/shop/arnold_vopnet1/")] htoa.material.materialExport(vops,"D:/mat.mtlx")以下是在寻找解决方法的过程中记录的流水账日志 google泛搜索…

MySQL入门篇-MySQL MHA高可用实战

MHA简介 MHA&#xff08;Master High Availability&#xff09;目前在MySQL高可用方面是一个相对成熟的解决方案&#xff0c;它由日本DeNA公司的youshimaton&#xff08;现就职于Facebook公司&#xff09;开发&#xff0c;是一套优秀的作为MySQL高可用性环境下故障切换和主从提…

2023软考考哪个证书好?

软考有三个级别&#xff08;初级&#xff0c;中级和高级&#xff09;&#xff0c;这三个级别分别对应5个方向&#xff0c;下面这张图片呢&#xff0c;可以一目了然&#xff0c;一些小小建议&#xff01;&#xff01;&#xff01;遵循一个原则&#xff1a;首先选专业对口的科目&…

为什么这11道JVM面试题这么重要(附答案)

本文内容整理自 博学谷狂野架构师 运行时数据区都包含什么 虚拟机的基础面试题 程序计数器Java 虚拟机栈本地方法栈Java 堆方法区 程序计数器 程序计数器是线程私有的&#xff0c;并且是JVM中唯一不会溢出的区域&#xff0c;用来保存线程切换时的执行行数 程序计数器&#xff…

算法笔记(三)—— 桶排序及排序总结

堆 逻辑上是一棵完全二叉树&#xff08;依次遍满或者全满&#xff09;。 数组可以转为完全二叉树&#xff0c;完全二叉树某结点左孩子(2*i1)&#xff0c;右孩子(i*22)&#xff0c;父结点((i-1/)2)&#xff0c;根节点的父还是自己。 如何将数组转化为堆&#xff08;大根堆&…

Web自动化测试——selenium篇(一)

文章目录一、环境准备二、Web 自动化测试 Demo三、元素定位常用方法四、元素定位失败可能原因五、测试对象操作六、等待操作七、信息打印在学习 Web 自动化测试的过程中&#xff0c;selenium 是其中的常用工具。除了其开源免费&#xff0c;包含丰富的 API 以外&#xff0c;它还…