文章目录
- 初识C语言
-
- 变量、作用域、生命周期
- 字符串、数组
- 关键字
- 指针
- 分支、循环语句
- 函数
- 递归
- 数组
- 操作符、算术转换、表达式
- 指针、结构体
- Debug和Release的区别
本章整理出来一些C语言基础部分相关选择题练习。
初识C语言 变量、作用域、生命周期 题1
下面哪个不是C语言内置的数据类型:
A.char
B.double
C.struct Stu
D.short
C语言中内置类型包括:
char//字符数据类型
short//短整型
int//整形
long//长整型
long long//更长的整形
float//单精度浮点数
double//双精度浮点数
struct关键字是用户用来自定义的结构体类型,不属于C语言的内置类型,是自定义类型。
因此:选择C
题2
局部变量的作用域是:
A.main函数内部
B.整个程序
C.main函数之前
D.局部变量所在的局部范围
在C语言中,变量分为局部变量和全局变量。
局部变量:一般将定义在函数中的变量称为局部变量,其只能在函数内部使用。
全局变量:定义在全局作用域中的变量,即函数外的变量,称之为全局变量,全局变量的生命周期随程序启动而生,随程序结束而消亡,在任何函数中都可以使用。
注意:全局变量使用起来方便,但为了防止冲突和安全性,尽量避免定义全局变量。
A:main函数内部定义的局部变量作用域在main函数中,但是其他函数中的局部变量则不在,因此A选项不对。
B:局部变量作用域在函数内部,全局变量是整个程序,因此B选项不对
C:main函数之前,是系统做的一些事情,因此也不对
D:正确,即在函数体内
因此:选择D
题3
下面代码输出的结果是:( )
#include
int num = 10;
int main()
{
int num = 1;
printf("num = %d\n", num);
return 0;
}
答案是1。
本题主要考察量的访问规则,C语言中:
- 不允许在同一个作用域中定义多个相同名称的变量
- 允许在不同的作用域中定义多个不同名称的变量
- 不同作用域中定义的变量,在访问时采用就近原则。
根据以上描述可知,对于以上代码:
- 全局作用域中的num和main中的num可以同时存在,不会冲突,因为不是同一个作用域
- 在main函数中访问num时,**采用就近原则,**因此访问的是main中的num,相当于将全局作用域中的num屏蔽了
字符串的结束标志是:( )
A.是’0’
B.是eof
C.是’\0’
D.是空格
C语言规定:以’\0’作为有效字符串的结尾标记
A:错误,是’\0’不是字符0
B:EOF一般用来作为检测文本文件的末尾
因此:选择C
题5
下面代码的结果是:( )
#include
#include
int main()
{
char arr[] = {'h', 'e', 'l','l', 'o'};
printf("%d\n", strlen(arr));
return 0;
}
strlen是用来获取字符串的有效长度的,结尾标记’\0’不包含在内。
strlen获取的规则非常简单:从前往后一次检测,直到遇到’\0’是就终止检测。
而上题中arr是一个字符数组,不是一个有效的字符串,因为后面没有放置’\0’,因此strlen在求解时,将有效字符检测完之后,还会继续向后检测,直到遇到’\0’是才终止,因此答案为不确定,就看紧跟在’o’之后的第一个’\0’在什么位置。
题6
下面那个不是转义字符?
A.’\n’
B.’\060’
C.’\q’
D.’\b’
A:’\n’ 转义字符,代表换行
B:’\060’ 转义字符,060八进制数据,十进制为48,因此’\48’表示的就是’0’
C:’\q’ 什么都不是
D:’\b’ 转义字符,表示退格
因此:选择C
题7
关于数组描述错误的是:
A.数组是一组相同类型元素的集合
B.数组的下标是从1开始的
C.数组的下标是从0开始的
D.数组如果初始化,可以不指定数组的大小
数组的下标是从0开始的。
需要注意的是D:int a[] = {1,2,3},数组可以通过初始化确定大小。
int b[10] = {1}; 这是不完全初始化,数组10个元素,只给第一个元素值为1,那么剩下的元素默认值为0。
题8
C语言中下面那个数组的创建错误的:( )
A.int arr[10] = {0};
B.int n = 10; int arr[n] = {0};
C.int arr[] = {1,2,3,4,5,6,7,8,9,0};
D.char ch[12] = “hello world”;
答案是B,数组的大小必须是常量。只有支持C99标准的编译器才支持变长数组,而且可变长数组不能进行初始化。
题9
下面程序的结果是:( )
#include
#include
int main()
{
printf("%d\n", strlen("c:\test\121"))
return 0;
}
答案解析:
strlen:获取字符串的有效长度,不包括’\0’
“c:\test\121”: 在该字符串中,\t是转义字符,水平制表,跳到下一个tab的位置;而\121表示ASCII码为121的字符,即:字符’Q’ ,故上述字符串实际为:“c: estQ”,只有7个有效字符
关键字 题10
关于C语言关键字说法正确的是:( )
A.关键字可以自己创建
B.关键字不能自己创建
C.关键字可以做变量名
D.typedef不是关键字
C语言关键字:C语言定义的,具有特定含义、专门用于特殊用途的C语言标识符,也称为保留字
A:错误,关键字是语言自身定义的
B:正确
C:错误,关键字具有特殊含义,不能作为变量名
D:错误,typedef是用来给类型取别名的关键字
因此,选择B
题11
下面那个不是关键字:( )
A.int
B.struct
C.define
D.continue
答案解析:
C语言关键字:C语言定义的,具有特定含义、专门用于特殊用途的C语言标识符,也称为保留字
define不是关键字,是编译器实现的,用来定义宏的预处理指令,不是C语言中的内容。
int、struct和continue都是C语言中包含的关键字。
因此:选择C
题12
关于static说法不正确的是:( )
A.static可以修饰局部变量
B.statc可以修饰全局变量
C.static修饰的变量不能改变
D.static可以修饰函数
答案解析:本题主要考察static的特性
- static修饰变量
a. 函数中局部变量:
生命周期延长:该变量不随函数结束而结束
初始化:只在第一次调用该函数时进行初始化
记忆性:后序调用时,该变量使用前一次函数调用完成之后保存的值
存储位置:不会存储在栈上,放在数据段
b. 全局变量
改变该变量的链接属性,让该变量具有文件作用域,即只能在当前文件中使用
c. 修饰变量时,没有被初始化时会被自动初始化为0
- static修饰函数
改变该函数的链接属性,让该函数具有文件作用域,即只能在当前文件中使用
题13
下面代码的结果是什么?( )
#include
int sum(int a)
{
int c = 0;
static int b = 3;
c += 1;
b += 2;
return (a + b + c);
}
int main()
{
int i;
int a = 2;
for (i = 0;
i < 5;
i++)
{
printf("%d,", sum(a));
}
}
答案解析:
本题主要考察static修饰局部变量的特性,static修饰局部变量,该变量不会随函数的结束而消失,并且只在第一次调用时进行初始化,后序调用该函数时,使用的都是上次结束前该变量的值。
第一次循环:a=2 b=5 c=1 a+b+c=8
第二次循环:a=2 b=7 c=1 a+b+c=10
第二次循环:a=2 b=9 c=1 a+b+c=12
第二次循环:a=2 b=11 c=1 a+b+c=14
第二次循环:a=2 b=13 c=1 a+b+c=16
题14
用在switch语言中的关键字不包含哪个?( )
A.continue
B.break;
C.default
D.case
答案解析:
switch是用来进行多分支选择的语句,一般结构是:
switch(整型变量表达式){case 整型常量表达式xx1:// ...break;
case 整型常量表达式xx2// ...break;
default:// ...}
当整型变量表达式的内容与某个case后的常量相等后,就执行该case下的语句,break表示该case以后的内容不会执行,如果没有跟break,会继续执行当前case之后的case分支。
当变量表达式的内容没有与那个case匹配,就会执行default下的内容。
switch中常用的关键字:case 、break、 default,当然case中语句比较复杂时,可能会用if进行判断。
continue是用来结束本次循环的,而switch不是循环,因此其中不能使用continue关键字。
因此:选择A
指针 题15
关于指针说法正确的是:( )
A.sizeof(char*)大小一定是1
B.指针是变量,用来存放地址
C.指针变量的大小都是4个字节
D.指针不是变量
答案解析:本题主要考察指针的相关特性
A:错误,指针是一种复合数据类型,指针变量内容是一个地址,因此一个指针可以表示该系统的整个地址集合,
故按照32位编译代码,指针占4个字节,按照64位编译代码,指针占8个字节(注意:不是64位系统一定占8个字节,关键是要按照64位方式编译)
B:正确
C:错误,参考A选项解释
D:错误,该条描述比较模糊,指针可以认为是一种数据类型,也可以认为是定义出来的指针变量
因此,选择B。
分支、循环语句 题16
下面代码执行的结果是:( )
#include
int main()
{
int i = 0;
for (i = 0;
i<10;
i++)
{
if (i = 5)
printf("%d ", i);
}
return 0;
}
答案解析:
上述代码本来的想法应该是:循环10次,每次循环时如果i==5则打印i的结果。
但if语句中表达式的==写成了赋值,相当于每次循环尽量都是将i的值设置成了5,5为真,因此每次都会打印5
i每次修改成5打印后,i的值永远不会等于10,因此造成死循环
故:死循环的打印5。
题17
关于if语句说法正确是:( )
A.if语句后面只能跟一条语句
B.if语句中0表示假,1表示真
C.if语句时一种分支语句,可以实现单分支,也可以实现多分支
D.else语句总是和它的对其的if语句匹配
答案解析:
A:错误,if之后可以跟多条语句,跟多条语句时需要使用{}括起来
B:错误,0表示假,非零表示真
C:正确
D:不一定,要看具体的代码,如果代码不规范,可能没有对齐,比如:
if()
if()
else
;
上述else虽然是和外层if对齐,但是会和内部if进行匹配。
因此,选C
题18
关于switch说法不正确的是:( )
A.switch语句中的default子句可以放置在任意位置
B.switch语句中case后的表达式只能是整型常量表达式
C.switch语句中case子句必须在default子句之前
D.switch语句中case表达式不要求顺序
答案解析:
A:正确,可以放在任意位置,但是一般建议最好还是放在最后
B:正确,case语句后一般放整形结果的常量表达式或者枚举类型,枚举类型也可以看成是一个特殊的常量
C:错误,没有规定case必须在default之前,一般case最好放在default之前
D:正确,但一般还是按照次序来
因此:选择C
题19
int func(int a)
{
int b;
switch (a)
{
case 1: b = 30;
case 2: b = 20;
case 3: b = 16;
default: b = 0;
}
return b;
}
则func(1) = ( )
答案解析:
switch的每个case之后如果没有加break语句,当前case执行结束后,会继续执行紧跟case中的语句。
func(1)可知,在调用func时形参a的值为1,switch(a)<==>switch(1),case 1被命中,因为该switch语句中所有分支下都没有增加break语句,因此会从上往下顺序执行,最后执行default中语句返回。
因此:选择D
题20
switch?语句中,c不可以是什么类型( )
A.int
B.long
C.char
D.float
答案解析:
switch语句中表达式的类型只能是:整形和枚举类型
D选项为浮点类型,不是整形和枚举类型
因此:选择D
题21
下面代码的执行结果是什么( )
#include
int main() {
int x = 3;
int y = 3;
switch (x % 2) {
case 1:
switch (y)
{
case 0:
printf("first");
case 1:
printf("second");
break;
default: printf("hello");
}
case 2:
printf("third");
}
return 0;
}
答案解析:
switch语句时多分支的选择语句,switch中表达式结果命中那个case,就执行该case子项,如果case子项后没有跟break语句,则继续往下执行。
关于该题解析,请看以下注解:
#include
int main() {
int x = 3;
int y = 3;
switch (x % 2) {// x%2的结果为1,因此执行case1
case 1:
switch (y)// y是3,因此会执行case3,而case3不存在,那只能执行default
{
case 0:
printf("first");
case 1:
printf("second");
break;
default: printf("hello");
// 打印hello,打印完之后,内部switch结束,此时外部case1结束
}// 因为外部case1之后没有添加break语句,所以继续执行case2
case 2:// 打印third
printf("third");
// 外部switch结束
}
return 0;
}
即:先在内部switch的default位置打印hello,紧接着在外部case2中打印third
因此:选择D
题22
关于while(条件表达式) 循环体,以下叙述正确的是( )? (假设循环体里面没有break,continue,return,goto等等语句)
A.循环体的执行次数总是比条件表达式的执行次数多一次
B.条件表达式的执行次数总是比循环体的执行次数多一次
C.条件表达式的执行次数与循环体的执行次数一样
D.条件表达式的执行次数与循环体的执行次数无关
答案解析:
while(条件表达式)循环体
while循环中,当条件表达式成立时,才会执行循环体中语句,每次执行期间,都会对循环因子进行修改(否则就成为死循环),修改完成后如果while条件表达式成立,继续循环,如果不成立,循环结束
故:while循环条件将会比循环体多执行一次。
因此:选择B
题23
有以下程序
#include
int main()
{
int a = 0, b = 0;
for (a = 1, b = 1;
a <= 100;
a++)
{
if (b >= 20) break;
if (b % 3 == 1)
{
b = b + 3;
continue;
}
b = b-5;
}
printf("%d\n", a);
return 0;
}
程序的输出结果是?( )
答案分析:
#include
int main()
{
int a = 0, b = 0;
// for循环将a和b的初始值均设置为1
for (a = 1, b = 1;
a <= 100;
a++)
{
if (b >= 20) break;
if (b % 3 == 1)
{
b = b + 3;
continue;
}b = b-5;
}
printf("%d\n", a);
return 0;
}
第一次循环:a = 1,b=1,a<100,进入循环体,b小于20,第一个if不成立,b%3==1%3==1成立,b=b+3, 此时b的值为4,continue跳过本次循环后面的代码,来到调整部分,a++,a = 2
第二次循环:a = 2,b=4,a < 100,b小于20,if不成立,b%3==4%3==1成立,b=b+3, 此时b的值为7,a++,a = 3
第三次循环:a = 3,b=7,a< 100,b小于20,if不成立,b%3==7%3==1成立,b=b+3, 此时b的值为10,a++,a = 4
第四次循环:a = 4,b=10,a < 100,b小于20,if不成立,b%3==10%3==1成立,b=b+3, 此时b的值为13,a++,a = 5
第五次循环:a = 5,b=13,a < 100,b小于20,if不成立,b%3==13%3==1成立,b=b+3, 此时b的值为16,a = 6
第六次循环:a = 6,b=16,a < 100,b小于20,if不成立,b%3==16%3==1成立,b=b+3, 此时b的值为19,a++,a = 7
第七次循环:a = 7,b=19,a < 100,b小于20,if不成立,b%3==19%3==1成立,b=b+3, 此时b的值为22,a++
,a = 8
第八次循环:a = 8,b=22,a<100,b大于20,if成立,循环break提出
最后打印a:8
因此:选择C
函数 题24
题目名称:
能把函数处理结果的二个数据返回给主调函数,在下面的方法中不正确的是:( )
题目内容:
A.return 这二个数
B.形参用数组
C.形参用二个指针
D.用二个全局变量
答案解析:
A:错误,一个函数只能返回一个结果
B:正确,将形参存在数组中,修改数组中内容,可以通过数组将修改结果带出去
C:正确,形参如果用指针,最终指向的是外部的实参,在函数中对指向指向内容进行修改,改变的就是外部的实参
D:正确,全局变量不受函数的结束而结束,在函数中改变全局变量,主调函数中可以看到改变之后的结果
因此,选择A
题25
关于函数调用说法不正确的是:( )
A.函数可以传值调用,传值调用的时候形参是实参的一份临时拷贝
B.函数可以传址调用,传址调用的时候,可以通过形参操作实参
C.函数可以嵌套定义,但是不能嵌套调用
D.函数可以嵌套调用,但是不能嵌套定义
答案解析:
A:正确,形参按照值的方式传递,将来形参就是实参的一份临时拷贝,修改形参不会影响外部的实参
B:正确,形参按照指针方式传递,将来形参就是实参地址的一份拷贝,形参指向的是实参,修改形参指针指向的内容, 就是在操作实参
C:错误,C语言中,函数不能嵌套定义
D:正确,函数可以嵌套调用,即:A()中调用B(),B()中调用A(),但是要控制好,否则就成为无限递归
因此,选择C
题26
在函数调用时,以下说法正确的是:( )
A.函数调用后必须带回返回值
B.实际参数和形式参数可以同名
C.函数间的数据传递不可以使用全局变量
D.主调函数和被调函数总是在同一个文件里
答案解析:
A:错误,函数可以没有返回值,如果没有返回值也就不需要待会任何结果
B:正确,形参和实参在不同的函数中,即不同的作用域,因此形参和实参可以同名
C:错误,可以使用全局变量传参
D:错误,不一定,函数的定义可以放在任意的文件中,使用时只需要包含头文件即可
因此,选择B
题27
关于函数的声明和定义说法正确的是:( )
A.函数的定义必须放在函数的使用之前
B.函数必须保证先声明后使用
C.函数定义在使用之后,也可以不声明
D.函数的声明就是说明函数是怎么实现的
答案解析:
A:错误,函数的定义可以放在任意位置,函数的声明必须放在函数的使用之前
B:正确
C:错误,函数定义在使用之后,使用之前没有声明时,编译器编译时识别不了该函数
D:错误,函数的声明只是告诉编译器函数返回值类型、函数名字以及函数所需要的参数,函数定义才是说明函数是怎么 实现的
题28
关于实参和形参描述错误的是:( )
A.形参是实参的一份临时拷贝
B.形参是在函数调用的时候才实例化,才开辟内存空间
C.改变形参就是改变实参
D.函数调用如果采用传值调用,改变形参不影响实参
答案解析:
A:正确,传参时不论是按照值还是指针方式传递,形参拿到的都是实参的一份拷贝
B:正确,函数没有调用时,形参没有空间
C:错误,如果是按照值的方式传递,形参和实参各自有各自的空间,改变形参不能改变外部的实参
D:正确,因为形参和实参是两个不同的变量
题29
函数调用exec((vl,v2),(v3,v4),v5,v6); 中,实参的个数是:( )
【C语言练习|C语言选择题-C基础】A.3
B.4
C.5
D.6
答案解析:
exec((vl,v2),(v3,v4),v5,v6) 总共有四个参数
(v1, v2)属于第一个实参,逗号表达式,真实的参数时v2
(v3,v4)属于第二个实参,逗号表达式,真实的参数是v4
v5属于第三个实参
v6属于第四个实参
因此选择:B
题30
以下关于函数设计不正确的说法是:( )
A.函数设计应该追求高内聚低耦合
B.要尽可能多的使用全局变量
C.函数参数不易过多
D.设计函数时,尽量做到谁申请的资源就由谁来释放
答案解析:
A:正确,高内聚低耦合即:函数体内部实现修改了,尽量不要对外部产生影响,否则:代码不方便维护
B:错误,全局变量每个方法都可以访问,很难保证数据的正确性和安全性
C:正确,参数越少越好,否则用户在使用时体验不是很好,还得必须将所有参数完全搞明白才可以使用
D:正确,谁申请的谁维护谁释放,否则如果交给外部使用者释放,外部使用者可能不知道或者忘记,就会造成资源泄漏
因此,选择B
题31
关于C语言函数描述正确的是:( )
A.函数必须有参数和返回值
B.函数的实参只能是变量
C.库函数的使用必须要包含对应的头文件
D.有了库函数就不需要自定函数了
A:错误,可以没有参数和返回值类型,根据需要给出
B:错误,函数的实参可能是变量,也可能是常量,也可能是宏,也可能是指针等等
C:正确,在使用库函数时,必须要包含该库函数所在的头文件,否则编译器将不能识别
D:错误,库函数是语言设计者为了让用户能够更好的使用,而给出的,但并不能解决用户的所有问题,因此其他问题还
需要用户自己写方法解决
因此:选择C
题32
C语言规定,在一个源程序中,main函数的位置( )
A.必须在最开始
B.必须在库函数的后面
C.可以任意
D.必须在最后
答案解析:
main函数的位置可以再任意位置,但是如果在主函数之前调用了那些函数,必须在main函数前对其所调用函数进行声明或包含其被调用函数的头文件。
因此:选择C
题33
以下叙述中不正确的是:( )
A.在不同的函数中可以使用相同名字的变量
B.函数中的形式参数是在栈中保存
C.在一个函数内定义的变量只在本函数范围内有效
D.在一个函数内复合语句中定义的变量在本函数范围内有效(复合语句指函数中的成对括号构成的代码)
答案解析:
A:正确 不同的函数属于不同的作用域,因此不同的函数中定义相同名字的变量不会冲突
B:正确 在C语言中,函数的形参一般都是通过参数压栈的方式传递的
C:正确 在函数内定义的变量,称为局部变量,局部变量只能在其定义的函数中使用
D:错误 复合语句中定义的变量只能在复合语句中使用
因此:选择D
递归 题34
关于递归的描述错误的是:( )
A.存在限制条件,当满足这个限制条件的时候,递归便不再继续
B.每次递归调用之后越来越接近这个限制条件
C.递归可以无限递归下去
D.递归层次太深,会出现栈溢出现象
答案解析:
递归的两个条件:
- 将问题转化为其子问题,子问题要与原问题具有相同的解法
- 递归的出口
B:正确,因为每次递归,都是将原问题进一步缩小,缩小到限制条件时,就可以往回返,直到第一次递归调用
比如:递归求和
int Sum(int N)
{
if(N == 1)
return 1;
return Sum(N-1)+N;
}
假设:求Sum(4)的递归调用过程
Sum(4)<----
||
||
Sum(3)<----
||
||
Sum(2)<----
||
||
Sum(1)-----
C:错误,递归不能无限递归下去,否则会造成死循环和栈溢出
D:正确,因为每次递归,相当于都是一次新的函数调用,而每次函数调用系统必须给该函数划分栈帧空间,内部的递 归函数没有退出,上层的递归就不能退出,栈帧就会累积许多块,如果累积超过栈的总大小,就会栈溢出。
数组 题35
关于一维数组初始化,下面哪个定义是错误的?( )
A.int arr[10] = {1,2,3,4,5,6};
B.int arr[] = {1,2,3,4,5,6};
C.int arr[] = (1,2,3,4,5,6);
D.int arr[10] = {0};
答案解析:
A:正确,10个int的一段连续空间,前6个位置被初始化为1,2,3,4,5,6,其他位置为0
B:正确,数组中有6个空间,并被初始化为1,2,3,4,5,6
C:错误,数组的初始化不能使用(),只能使用{}
D:正确,10个int类型的一段连续空间,每个位置都被初始化为0
因此,选择C
题36
定义了一维 int 型数组 a[10] 后,下面错误的引用是:( )
A.a[0] = 1;
B.a[0] = 5*2;
C.a[10] = 2;
D.a[1] = a[2] * a[0];
答案解析:
数组是相同类型的一段连续的空间,下标是从0开始的,比如:int array[N]
下标的范围为[0,N),其中N位置不能存储有效元素
A:正确,将0号位置设置为1
B:正确,将0号位置设置为10
C:错误,越界
D:正确,1号位置初始化为a[2]*a[0]之后的结果
因此,选择C
题37
若定义int a[2][3]={1,2,3,4,5,6}; 则值为4的数组元素是( )
A.a[0][0]
B.a[1][0]
C.a[1][1]
D.a[2][1]
答案解析:
int a[2][3]表示2行3类的二维数组,根据其初始化知:
第0行即a[0]存储3个元素: 1,2,3
第1行即a[1]存储3个元素: 4,5,6
因此值为4的元素在第1行第0列
因此,选择B
题38
下面代码的结果是:( )
#include
int main()
{
int arr[] = {1,2,(3,4),5};
printf("%d\n", sizeof(arr));
return 0;
}
A.4
B.16
C.20
D.5
答案解析:
对于int arr[] = {1,2,(3,4),5}数组,里面总共有4个元素,(3,4)为逗号表达式,取后者,因此数组中元素分别为:1,2,4,5
而sizeof(arr)求的是整个数组所占空间的大小,即:4sizeof(int)=44=16
因此,选择B
题39
下面代码的结果是:( )
#include
int main()
{
char str[] = "hello bit";
printf("%d %d\n", sizeof(str), strlen(str));
return 0;
}
A.10 9
B.9 9
C.10 10
D.9 10
答案解析:
str字符数组使用"hello bit"初始化,最终也会将’\0’放置到数组中,因此数组中总共有10个元素
sizeof(str):获取数组的总大小,10个元素,每个元素占1个字节,因此总共是10个字节
strlen(str): 获取字符串中有效字符的个数,不算’\0’,因此总共9个有效字符
故上述printf会分别打印:10 9
因此,选择A
题40
给出以下定义:
char acX[] = “abcdefg”;
char acY[] = {‘a’,’b’,’c’,’d’,’e’,’f’,’g’};
以下说法正确的是( )
A.数组acX和数组acY等价
B.数组acX和数组acY的长度相同
C.数组acX的长度大于数组acY的长度
D.数组acX的长度小于数组acY的长度
答案解析:
acX和acY都是字符数组,但是初始化表达式不同,acX和acY的区别如下:
acX:数组中总共有8个元素,分别是:‘a’,‘b’,‘c’,‘d’,‘e’,‘f’,‘g’,’\0’
acY:数组中总共有7个元素,分别是:‘a’,‘b’,‘c’,‘d’,‘e’,‘f’,‘g’
因此,选择C
题41
关于一维数组描述不正确的是:( )
A.数组的下标是从0开始的
B.数组在内存中是连续存放的
C.数组名表示首元素的地址
D.随着数组下标的由小到大,地址由高到低
答案解析:
A:正确,C语言规定,数组的下标是从0开始的
B:正确,数组的空间是一段连续的内存空间
C:正确,数组名既可以表示数组的地址,也可以表示数组首元素的地址,两个在数值上是一样的,但是含义不一样。
注意:数组名只有在sizeof和&后才代表整个数组,其它都表示首元素的地址
D:错误,这个要是系统而定,一般都是下标由小到大,地址由低到高
因此,选择D
题42
以下能对二维数组a进行正确初始化的语句是:( )
A.int a[2][]={{0,1,2},{3,4,5}};
B.int a[][3]={{0,1,2},{3,4,5}};
C.int a[2][4]={{0,1,2},{3,4},{5}};
D.int a[][3]={{0,2},{},{3,4,5}};
答案解析:
对于二维数组int array[M][N], 说明如下:
- M和N都必须为常数,
- M代表数组有M行,N代表每行中有N个元素
- 其中M可以省略,省略后必须给出初始化表达式,编译器从初始化结果中推断数组有多少行
- N一定不能省略,因为N省略了就不能确定一行有多少个元素,也不能确定数组有多少行
B:正确,参考上述说明
C:错误,数组有两行,但是初始化给了三行
D:错误,初始化不允许{0,2}该种情况存在
因此,选择B
题43
下面代码的结果是:( )
#include
int main()
{
int a, b, c;
a = 5;
c = ++a;
//a = 6,c =6
b = ++c, c++, ++a, a++;
//b = 7,c = 8,a = 8
b += a++ + c;
// b = 7+8+8 = 23
printf("a = %d b = %d c = %d\n:", a, b, c);
//9,23,8
return 0;
}
A.a = 8 b = 23 c = 8
B.a = 9 b= 23 c = 8
C.a = 9 b = 25 c = 8
D.a = 9 b = 24 c = 8
答案解析:
++运算符:分为前置++和后置++,
前置++:先加1,后使用,即先使用变量中内容,然后给结果加1
后置++:先使用变量中内容,整个表达式结束时,给变量加1
逗号表达式,取最后一个表达式的值。
#include
int main()
{
int a, b, c;
a = 5;
c = ++a;
// ++a:加给a+1,结果为6,用加完之后的结果给c赋值,因此:a = 6c = 6
b = ++c, c++, ++a, a++;
// 逗号表达式的优先级,最低,这里先算b=++c, b得到的是++c后的结果,b是7
// b=++c 和后边的构成逗号表达式,依次从左向右计算的。
// 表达式结束时,c++和,++a,a++会给a+2,给c加1,此时c:8,a:8,b:7
b += a++ + c;
// a先和c加,结果为16,在加上b的值7,比的结果为23,最后给a加1,a的值为9
printf("a = %d b = %d c = %d\n:", a, b, c);
// a:9, b:23, c:8
return 0;
}
答案为B
操作符、算术转换、表达式 题44
下面哪个是位操作符:( )
A.&
B.&&
C.||
D.!
答案解析:
A. & 是按位与操作符,正确
B. && 是逻辑与,不是按位与,错误
C. || 是逻辑或,错误
D. ! 是逻辑反操作符,错误
题45
下面代码的结果是:( )
#include
int main()
{
int i = 1;
int ret = (++i)+(++i)+(++i);
printf("ret = %d\n", ret);
return 0;
}
A.10
B.12
C.9
D.程序错误
答案解析:
表达式(++i)+(++i)+(++i),只有操作符的优先级和结合性,没法确定唯一计算路径
所以这个表达式可能因为计算顺序的差异导致结果是不一致的,所以表达式是错误的表达式。
可以在VS和Linux gcc测试,结果可能有差异。
题46
下面代码的结果是:( )
#include
int main()
{
int arr[] = {1,2,3,4,5};
short *p = (short*)arr;
int i = 0;
for(i=0;
i<4;
i++)
{
*(p+i) = 0;
}for(i=0;
i<5;
i++)
{
printf("%d ", arr[i]);
}
return 0;
}
A.1 2 3 4 5
B.0 0 3 4 5
C.0 0 0 0 5
D.1 0 0 0 0
arr数组在内存中的存储格式为:
0x00ECFBF4: 01 00 00 00
0x00ECFBF8: 02 00 00 00
0x00ECFBFC: 03 00 00 00
0x00ECFC00: 04 00 00 00
0x00ECFC04: 05 00 00 00
指针p的类型为short*类型的,因此p每次只能所有两个字节,for循环对数组中内容进行修改时,一次访问的是:
arr[0]的低两个字节,arr[0]的高两个字节,arr[1]的低两个字节,arr[1]的高两个字节,故改变之后,数组中内容如下:
0x00ECFBF4: 00 00 00 00
0x00ECFBF8: 00 00 00 00
0x00ECFBFC: 03 00 00 00
0x00ECFC00: 04 00 00 00
0x00ECFC04: 05 00 00 00
故最后打印:0 0 3 4 5
题47
下面代码的结果是:
#include
int i;
int main()
{
i--;
if (i > sizeof(i))
{
printf(">\n");
}
else
{
printf("<\n");
}
return 0;
}
A.>
B.<
C.不输出
D.程序有问题
答案解析:
C语言中,0为假,非0即为真。
全局变量,没有给初始值时,编译其会默认将其初始化为0。
i的初始值为0,i–结果-1,i为整形,sizeof(i)求i类型大小是4,按照此分析来看,结果应该选择B,但是sizeof的返回值类型实际为无符号整形,进行算术转换,因此编译器会自动将左侧i自动转换为无符号整形的数据,-1对应的无符号整形是一个非常大的数字,超过4或者8,故实际应该选择A。
题48
关于表达式求值说法不正确的是:( )
A.表达式求值先看是否存在整形提升或算术转换,再进行计算
B.表达式真正计算的时候先看相邻操作符的优先级决定先算谁
C.相邻操作符的优先级相同的情况下,看操作符的结合性决定计算顺序
D.只要有了优先级和结合性,表达式就能求出唯一值
A:正确
B:正确
C:正确
D: 错误,有了优先级和结合性,表达式也有可能有不同的计算路径,导致计算结果的差异。
指针、结构体 题49
下面代码输出的结果是:( )
#include
int main()
{
int a = 0x11223344;
char *pc = (char*)&a;
*pc = 0;
printf("%x\n", a);
return 0;
}
A.00223344
B.0
C.11223300
D.112233
答案解析:
假设,a变量的地址为0x64,则a变量在内存中的模型为:
0x64| 44 |
0x65| 33 |
0x66| 22 |
0x67| 11 |
char类型的指针变量pc指向只能指向字符类型的空间,如果是非char类型的空间,必须要将该空间的地址强转为char类型。
char pc = (char)&a; pc实际指向的是整形变量a的空间,即pc的内容为0x64,即44,
*pc=0,即将44位置中内容改为0,修改完成之后,a中内容为:0x11223300
因此:选择C
题50
关于指针的概念,错误的是:( )
A.指针是变量,用来存放地址
B.指针变量中存的有效地址可以唯一指向内存中的一块区域
C.野指针也可以正常使用
D.局部指针变量不初始化就是野指针
答案解析:
A:正确,指针变量中存储的是一个地址,指向同类型的一块内存空间
B:正确,地址是唯一的,一个指针变量中只能存储一个地址,因此可以唯一指向内存中的一块区域
C:野指针指向的空间时非法的,或者说该指针指向的空间已经不存在了,因此野指针不能使用
D:局部指针变量没有初始化时里面就是随机值,因此指向那个位置不一定,故将其看成是野指针
因此:选择C
题51
以下系统中,int类型占几个字节,指针占几个字节,操作系统可以使用的最大内存空间是多大:( )
A.32位下:4,4,2^32 ,64位下:8,8,2^64
B.32位下:4,4,不限制, 64位下:4,8,不限制
C.32位下:4,4,2^32 ,64位下:4,8,2^64
D.32位下:4,4,2^32, 64位下:4,4,2^64
答案解析:
32位系统下:
int占4个字节,指针表示地址空间个数,总共有2^32个,故占4个字节
64位系统下:
int占4个字节,指针表示地址空间个数,总共有2^64个,故占8个字节
因此:选择C
题52
下列程序段的输出结果为( )
unsigned long pulArray[] = {6,7,8,9,10};
unsigned long *pulPtr;
pulPtr = pulArray;
*(pulPtr + 3) += 3;
printf(“%d,%d\n”,*pulPtr, *(pulPtr + 3));
A.9,12
B.6,9
C.6,12
D.6,10
答案解析:
unsigned long pulArray[] = {6,7,8,9,10};
unsigned long *pulPtr;
pulPtr = pulArray;
// 数组名代表数组首元素地址,因此pulptr指向的是数组中第一个元素的位置
*(pulPtr + 3) += 3;
// pulptr+3访问的是数组中第三个元素(数组下标从0开始),故将9改为9+3=12
printf(“%d,%d\n”,*pulPtr, *(pulPtr + 3));
// 打印第一个和第三个元素,因此:打印6和12
因此:选择C
题53
如有以下代码:
struct student
{
int num;
char name[32];
float score;
}stu;
则下面的叙述不正确的是:( )
A.struct 是结构体类型的关键字
B.struct student 是用户定义的结构体类型
C.num, score 都是结构体成员名
D.stu 是用户定义的结构体类型名
答案解析:
A:正确,在C语言中需要自定义类型时,要用到struct关键字
B:正确:在C语言中,用struct定义的结构体,定义结构体类型变量时,需要用struct student
C:正确:结构体中的变量名称,称之为结构体的成员
D:错误:stu是定义的结构体类型变量,不是名称,如果想要让stu为结构体类型名称时,必须在结构体定义时添加 typedef关键字
因此:选择D
题54
下面程序的输出结果是:()
struct stu
{
int num;
char name[10];
int age;
};
void fun(struct stu *p)
{
printf(“%s\n”,(*p).name);
return;
}
int main()
{
struct stu students[3] = {{9801,”zhang”,20},
{9802,”wang”,19},
{9803,”zhao”,18}
};
fun(students + 1);
return 0;
}
A.zhang
B.zhao
C.wang
D.18
答案解析:
在main函数中先定义了一个stu结构体类型的数组students,students指向结构体的起始位置,students+1表示该数组中的第一个元素,因此fun的形参实际指向的是students数组中的第一个元素,故打印的是wang
因此:选择C
题55
结构体访问成员的操作符不包含:( )
A… 操作符
B.-> 操作符
C.* 解引用操作符
D.sizeof
答案解析:
A:正确,结构体类型变量访问结构体中成员时,使用.操作符
B:正确,指向结构体类型变量的指针访问结构体中成员时,使用->操作符
C:正确,指向结构体类型变量的指针也可以通过.方式访问成员,只不过要先通过*对该指针解引用
D:错误,sizeof是求结构体类型大小的
因此:选择D
题56
关于二级指针描述描述正确的是:( )
A.二级指针也是指针,只不过比一级指针更大
B.二级指针也是指针,是用来保存一级指针的地址
C.二级指针是用来存放数组的地址
D.二级指针的大小是4个字节
答案解析:
A:错误,二级指针是指针,不能说起比一级指针大,只能说二级指针指向的空间中存储的也是一个地址
B:正确
C:错误,数组的地址一般用一级指针存储,或者用数组指针接收
D:二级指针是指针,但是否占4个字节不一定,要看具体的系统
因此:选择B
题57
下面关于指针运算说法正确的是:( )
A.整形指针+1,向后偏移一个字节
B.指针-指针得到是指针和指针之间的字节个数
C.整形指针解引用操作访问4个字节
D.指针不能比较大小
答案解析:
注意:此题是有问题的,说法不严谨,如果将整形指针理解成int*类型的指针,那么一下说法解析如下
A:错误,整形指针+1,向后便宜一个整形类型的大小,即4个字节
B:错误,两个指针相减,指针必须指向一段连续空间,减完之后的结构代表两个指针之间相差元素的个数
C:正确,整形指向的是一个整形的空间,解引用操作访问4个字节
D:指针中存储的是地址,地址可以看成一个数据,因此是可以比较大小的
因此:选择C
题58
下面哪个是指针数组:( )
A. int* arr[10];
B.int * arr[];
C.int **arr;
D.int (*arr)[10];
答案解析:
指针数组是一个数组,该数组的每个元素是一个指针
A:正确,定义了一个数组,该数组中有10个元素,每个元素都是int*的指针类型
B:错误,编译失败,定义数组时,要给出空间的大小,如果没有给时,必须要给出初始化结果
C:错误,定义了一个二级指针
D:错误,*和arr先结合,说明arr不是数组。实际上arr是一个指针,一个指向数组的指针
因此:选择A
题59
下面程序要求输出结构体中成员a的数据,以下不能填入横线处的内容是( )
#include < stdio.h >
struct S
{
int a;
int b;
};
int main( )
{
struct S a, *p=&a;
a.a = 99;
printf( "%d\n", __________);
return 0;
}
A.a.a
B.*p.a
C.p->a
D.(*p).a
答案解析:
结构体类型变量需要访问其成员时,用.运算符,如果是指向结构体变量的指针访问时,需要用->,或者先对指针解引用,取到指向的结构体类型的变量,再通过.访问,但是要注意优先级
因此:选择B
Debug和Release的区别 题60
C程序常见的错误分类不包含:( )
A.编译错误
B.链接错误
C.栈溢出
D.运行时错误
答案解析:
栈溢出是运行时错误的一种,因此C程序为将栈溢出单独列出,栈溢出包含在运行时错误中。
因此:选择C
题61
关于VS调试快捷键说法错误的是:( )
A.F5-是开始执行,不调试
B.F10-是逐过程调试,遇到函数不进入函数
C.F11-是逐语句调试,可以观察调试的每个细节
D.F9是设置断点和取消断点
答案解析:
A:错误,F5是开始调试,在遇到短点的位置可以停下来,Ctrl+F5是开始执行,不调试
B:正确,F10遇到函数时不会进入到函数体中,F11会
C:F11遇到函数时,会进入函数中
D:F9会在光标所在行下短点,如果有短点会取消短点
因此,选择A
题62
关于Debug和Release的区别说法错误的是:( )
A.Debug被称为调试版本,程序调试找bug的版本
B.Release被称为发布版本,测试人员测试的就是Release版本
C.Debug版本包含调试信息,不做优化。
D.Release版本也可以调试,只是往往会优化,程序大小和运行速度上效果最优
答案解析:
A:正确,Debug为调试版本,一般在开发完成后发布工程前,调试代码都是在Debug模式下进行的
B:正确,Release版本最终是要发送给用户的,发给用户的版本必须要没有问题,测试人员就是最后一个把关的
C:正确,Debug版本是调试版本,编译器编译时会增加一些调试信息,编译器基本不会对其进行优化
D:错误,Release版本虽然也可以调试,但是没有意义,因为编译器的优化太大了,一般都是在Debug版本下调试的,Release版本一般编译器会进行大量的优化,删除无用的代码,指令的次序调整等,让其速度更快
因此:选择D
题63
语言中哪一种形式声明了一个指向char类型变量的指针p,p的值不可修改,但p指向的变量值可修改?( )
A.const char *p
B.char const p
C.charconst p
D.const char *const p
答案解析:
const放在*左边,修饰的是指针指向的内容,该内容不可变;const放在*的右边,修饰的是指针,表示该指针不可变
A:错误,const修饰*p,表示p指向的内容不能修改
B:错误,同上
C:正确,const修饰p本身,表示p的指向不能修改,p指向的空间中内容可以修改
D:错误,第一个const表示p指向的内容不能修改,第二个const表示p不能指向其他变量
因此,选择C
题64
以下关于指针的说法,正确的是( )
A.int *const p与int const *p等价
B.const int *p与int *const p等价
C.const int *p与int const *p等价
D.int *p[10]与int (*p)[10]等价
答案解析:
A:错误,int* const p中,const修饰指针变量p本身,表示p的指向不能改变,
int const *p中,const修饰p指针解引用之后的结果,表示p指向的内容不能改变
因此,不等价
B:错误,同上
C:正确,const都修饰p指针解引用之后的结果,表示p指向的内容不能改变
D:错误,int p[10]定义了一个指针数组,数组中10个元素,每个元素都是int类型的指针
int (*p)[10]定义了一个数组指针,该指针只能指向存储10个整形元素的数组
因此:选择C
题65
原码、反码、补码说法错误的是( )
A.一个数的原码是这个数直接转换成二进制
B.反码是原码的二进制符号位不变,其他位按位取反
C.补码是反码的二进制加1
D.原码、反码、补码的最高位是0表示负数,最高位是1表示正数
ABC正确,D关于符号位的描述说反了
题66
unsigned int a= 0x1234;
//0x00001234
unsigned char b=*(unsigned char *)&a;
在32位大端模式处理器上变量b等于( )
A.0x00
B.0x12
C.0x34
D.0x1234
大端序中,低地址到高地址的四字节十六进制排列分别为00 00 12 34,其中第一个字节的内容为00,故选A
题67
关于大小端字节序的描述正确的是( )
A.大小端字节序指的是数据在电脑上存储的二进制位顺序
B.大小端字节序指的是数据在电脑上存储的字节顺序
C.大端字节序是把数据的高字节内容存放到高地址,低字节内容存放在低地址处
D.小端字节序是把数据的高字节内容存放到低地址,低字节内容存放在高地址处
A应为B,CD互相说反了。
我们说的大小端针对的是一个数据(大于1个字节)在内存中的存储方式,对于数组,随着元素下标的增大,地址增大,这时大小端存储说的是每个元素是怎么存储的,元素与元素之间和大小端没有关系。
推荐阅读
- c++|最易/难学习的编程语言榜单出炉,C++最难学()
- 编程语言|“竟想替代 C 语言(编程语言Go、Rust、C++ 和 Zig 生产力对比!)
- C|C语言(2048游戏演示和说明)
- C|C语言(扫雷游戏演示和说明)
- kafka|2万字|30张图带你领略glibc内存管理精髓(因为OOM导致了上千万损失)
- C语言|C语言指针
- 3D|点云边界提取方法总结
- C语言|C语言项目实践——通讯录(三版本联合分解)
- 数据结构|LeetCode(206. 反转链表)