第一题(注意)
1.下列 C 代码中,不属于未定义行为的有:______。
A:int i=0; i=(i++);
B:char *p="hello"; p[1]='E';
C:char *p="hello"; char ch=*p++;
D:int i=0; printf("%d %d\n",i++,i--);
答案及解析 C
未定义行为是指C语言标准未做规定的行为。同时,标准也从没要求编译器判断未定义行为,所以这些行为有编译器自行处理,在不同的编译器可能会产生不同的结果,可能报错,可能正常运行,可能运行结果不同。
未定义行为:
1.变量即是左边结果,又是右边的操作数,如a+=a++,a %= b ^= a ^= b ^= a
2.使用越界数组也是C的一个“未定义行为”
3.允许一个随便指的指针的读写。
4.使用未初始化的变量5.改变字符串常量
A:经典的变量即是左边结果,又是右边操作数,属于未定义行为;
B:首先p指向的是字符串常量,修改字符串常量也是未定义行为;
C:定义了一个字符串常量,后面的ch是取的*p++,先p++,p存的是hello的首元素地址,是p的地址,p++指向e,解引用之后取到的是e,ch = e。只是赋值,没有改变字符串常量,不是未定义行为;
D:在printf语句中i++和i--无法确定谁先运行,是未定义
相关博客:C/C++未定义行为的例子汇总-CSDN博客
第二题
2.下面程序输出为()
#include <stdio.h>
int fun(int a) {
int b = 0;
static int c = 3;
b++;
c++;
return (a+b+c);
}
int main( ) {
int i=0;
for(; i < 3; i++)
printf("%d",fun(2));
return 0;
}
A:777
B:789
C:7911
D:71320
答案及解析 B
本题考查的是局部的static变量(静态变量)的相关知识,我们要知道,局部静态变量只会初始化一次,然后后续变化都会累加;
第三题(有异议)
3.下列叙述中,错误的是:
A:计算机不能直接执行C语言编写的源程序。
B:C程序经编译后,生成的扩展名为.obj的文件是一个二进制文件。
C:扩展名为.obj的文件,经链接程序生成扩展名为.exe的文件是一个二进制文件。
D:扩展名为.obj和.exe的二进制文件都可以直接运行。
答案及解析 D
本题是考查大家对翻译环境的理解,关于翻译环境的博客:通过历史 --> 了解翻译环境(预处理、编译、汇编、链接)-CSDN博客
A:计算机只识别二进制指令,所以要通过预处理--> 编译 --> 汇编 --> 链接 才能传给计算机
B:这里的B选项不严谨,准确来说编译生成的是.s的文件,并不是我们的obj文件,因为我们的编译器是会先把.c 文件经过预处理先生成.i文件,之后对.i文件进行编译翻译成我们的汇编代码生成.s文件,之后才是经过汇编翻译成我们的.obj/.o这样的目标文件,但是目标文件是不能够执行的,还需要通过链接,找到对应的动态库啊或者静态库这样的,为的是找到你调用的函数的定义。
这里的不严谨取决你的编译器是直接将C语言翻译成二进制指令,还是要先把C转换成汇编,再由汇编变成二进制,如果是前者,就是对的,后者就是错的。其实一般就是转为汇编,毕竟我们先有汇编变成二进制的编译器啊,站在巨人的肩膀上嘛!而且C语言和汇编还相似,所以我才会说这里不严谨,毕竟计算机这门学科应该是发展性,继承性的学科,而不是我发明了个新的东西,要重新开始写所有的东西。但是D是最错的,所以就是D了。
在牛客网本题的评论就是本人发的,没有存在抄袭哦
C:这是对的,.obj的文件通过链接之后才形成.exe的可执行程序;
D:记住.obj/.o只是目标文件,还没有找到对应的函数定义,所以无法执行,需要通过链接寻找动态库或者静态库,才可以找到函数的定义,进而生成可执行的.exe文件。
第四题
4. 设有 int x=11; 则表达式 (x++ * 1/3) 的值是( )
A:3
B:4
C:11
D:12
答案及解析 A
本题考查的是优先级的问题,这里就不做解释
相关博客:C语言操作符优先级表格(建议收藏,每次看一下)-CSDN博客
第五题
5. 在 gcc 环境下,已知数组 int arr[5]={1,2,3,4,5}; 则 *(*(&arr+1)-1) 的结果为
A:1
B:0
C:4
D:5
答案及解析 D
本题是考查的&arr代表的是什么?
本身arr代表的是数组首元素地址,&arr是取出整个数组的地址,那他就相当于一个指针变量里存放一整个数组的地址,如何把一个数组的地址都存进去呢?就是把数组每个元素的地址,变成一个指针数组,再放在这个指针变量中,所以这个变量也就是二级指针,这样说其实很抽象,大家可以看图来理解。既然&arr是一个二级指针,加一就是跳过的一个数组,我们还需要知道地址是连续的,所以&arr+1指向的就是这里,但是实际就是5的地址后面的地址,因为是跳过一整个数组的地址,*(arr+1)就是解引用,取到的是一级指针,也就是5后面的地址,*(arr+1)- 1 就是对这个地址减1,减少的就是sizeof(int)的大小,就是5的地址,再解引用就是5了。