W...Y的主页 😊
代码仓库分享❤️
在学习语言时,最重要的就是练习,光听不练假把式。下面我就推荐一些C语言必会的题。
执行下面程序,正确的输出是( )
int x=5,y=7; void swap() { int z; z=x; x=y; y=z; } int main() { int x=3,y=8; swap(); printf("%d,%d\n",x, y); return 0; }
A: 5,7 B: 7,5 C: 3,8 D: 8,3
看到上述代码,我们就得从变量开始入手。最开始先定义两个全局变量int x=5,y=7。接下来进入到主函数中也定义了局部变量int x=3,y=8。调用swap()时,使用的是全局变量,与主函数中变量无关,所以输出内容为3,8。我们在做这种题时,一定要考虑局部优先原则。答案:C
以下不正确的定义语句是( )
A: double x[5] = {2.0, 4.0, 6.0, 8.0, 10.0};
B: char c2[] = {'\x10', '\xa', '\8'};
C: char c1[] = {'1','2','3','4','5'};
D: int y[5+3]={0, 1, 3, 5, 7, 9};
本题考查了数组定义与转义字符,\ddd ddd表示1到3个八进制数 如:\130 转义为 字符X \xhh hh表示1到2位十六进制数 如:\x30 转义为 字符0。但是八进制中没有8,所以B选项错误。答案:B
下面这个程序执行后会有什么错误或者效果【多选】( )
#define MAX 255 int main() { unsigned char A[MAX], i; for(i = 0; i <= MAX; i++) A[i] = i; return 0; }
A: 数组越界 B: 死循环 C: 栈溢出 D: 内存泄露
本题考察变量的取值范围。此题使用宏define定义MXA为255,但是定义数组中使用unsigned char(0~255)在数组中应为0~254,所以第一个问题就是for循环中,数组越界。for循环停止的条件为i<=255,但是i的取值范围为(0~255)当超过255时就会返回起始点0继续增加。这会使循环进行死循环。
内存泄漏:创建的临时变量,在栈中,应该会由系统自动释放,所 以应该是不存在内存泄漏的问题。栈溢出:属于缓冲区溢出的一种。栈溢出是由于C语言系列没有内置检查机制来确保复制到 缓冲区的数据不得大于缓冲区的大小,因此当这个数据足够大的时候,将会溢出缓冲区的范围。
答案A,B
请问下列代码的输出结果有可能是哪些【多选】( )
#include <stdio.h> typedef union { int a; struct { short b; short c; }; }X; int main() { X x; x.a = 0x20150810; printf("%x,%x\n", x.b, x.c);return 0; }
A: 2015,810 B: 50810,201 C: 810,2015 D:20150,810
次题目考察联合的特点,联合成员使共用同一块内存空间的。
这时我们就要考虑两种方向,计算机存储形式为大端存储与小端存储。
对于0x20150810 如果按照大端模式存储:从低地址到高地址:20 15 08 10 输出从低地址到高地址:20 15 08 10 如果按照小端模式存储:从低地址到高地址:10 08 15 20 输出从高地址到低地址:08 10 20 15 此数以int类型赋值给联合体x.a,而以结构成员b和c分开访问,分别拿到低地址的2个字节和高地址的2个字节,大端下是 2015和810,小端下是810和2015
答案:A,C
指出下列代码的缺陷【多选】( )
float f[10]; // 假设这里有对f进行初始化的代码 for(int i = 0; i < 10;) { if(f[++i] == 0) break; }
A: for(int i = 0; i < 10;)这一行写错了
B: f是float型数据直接做相等判断有风险
C: f[++i]应该是f[i++]
D: 没有缺陷
我们这种题可以通过选项进行排除选择。
A:for循环必须要有三要素,但是这三个要素可以使用;进行分割不展现其中内容。编译器默认为空内容。所以A选项没有问题。
B:一般float型只能精确到小数后六位(即1e-6),将float型数据的绝对值与1e-6比较,来判断是否相等(为零)。float的精度 误差在1e-6;double精度误差在1e-15;所以要判断一个float型数:if(fabs(f)<1e-6);要判断一个double型数:if(fabs(f)<1e15);若满足,则为零。所以B选项为代码缺陷。
C:这里考察的为前置++与后置++的区别,前置++是先加再进行使用,后置++是先使用此值再进行+1操作。所以 f[++i]应该是f[i++],否则会导致数组越界。
D:B、C都有缺陷所以不选D。
答案:B、C
如下函数 fun 计算 prod=1*2*3*…*n ,并返回计算结果值。但当 n>12 时,返回值不正确。要找出该程序的错 误,正确的调试方法是( )
int fun(int n) { int prod = 1 , i = 0; for(i = 1;i <= n;i++) { prod *= i; } return prod; }
A: 监视变量prod的值,在prod *= i;行处设置断点,然后单步运行,直到发现错误原因
B: 监视变量prod的值,在return prod;行处设置断点,程序中断后,即可发现错误原因
C: 在prod=1;处设置断点,然后在函数调用堆栈中即可发现错误原因
D: 监视变量i的值,在for (i=1; i<=n; i++)行处设置断点,然后单步运行,直到发现错误原因
fun函数在n<12时返回值正确,但是在n>=12后返回值出错,这时我们就要考虑是不是栈溢出问题,所以我们应该监视prod内容,在prod *= i设置断点。
答案:A
以下 scanf 函数调用选项中, 错误的是( )
struct T { char name[20]; int age; int sex; } a[5], *pa=a;
A: scanf("%s",a[0].name);
B: scanf("%d", &pa[0].age);
C: scanf("%d",&(pa->age));
D: scanf("%d", pa->age);
该题考察的是通过scanf函数的调用对结构体数据类型进行初始化。
scanf("输入控制符", 输入参数);功能:将从键盘输入的 字符转化为“输入控制符”所规定格式的数据,然后存入以输入参数的值为地址的变量中。scanf输入时要通过地址找空间, B、C用了&是正确的。name属于字符数组的数组名,相当于数组的首地址,A正确。单独的pa->age可用于输出语句获取 值的形式,用在scanf中的时候需要&操作符,D错误。
答案:A
有以下函数,该函数的功能是( )
int fun(char *s) { char *t = s; while(*t++); return(t-s); }
A: 比较两个字符的大小
B: 计算s所指字符串占用内存字节的个数
C: 计算s所指字符串的长度
D: 将s所指字符串复制到字符串t中
这道题考察我们对指针的理解。
首先将s指针内容赋给t,循环在*t为0时停止,同时t++,t最后会停在字符串结束的'\0'之后的一个位置,返回(t-s)是指针位置的判断,指针相减可以得到字符串长度的大小。
答案:B
C 语言中,下列运算符优先级最高的是 ( )
A: ! B: % C: >> D: ==
单目运算符的优先级通常都比较高,具体情况可查阅运算符优先级表格
答案:A
要使 a 的低四位翻转,需要进行操作是( )
A: a|0xF B: a&0xF C: a^0xF D: ~a
十六进制数0xF是4位1,参与运算时整型提升,高位都是0。低四位和1异或,0^1是1,1^1是0;高位和0异或,0^0是0,1^0 是1。故而可以通过异或F使得a的低四位翻转,并保持高位不变
答案:C
3、下面有关空指针和未初始化指针,说法错误的是( )
A: 对0x0这个地址取值是非法的
B: 空指针可以确保不指向任何对象或函数; 而未初始化指针则可能指向任何地方
C: 空指针与任何对象或函数的指针值都不相等
D: malloc在其内存分配失败时返回的是一个未初始化的指针
malloc函数在内存分配失败时返回NULL,其余选项都正确
答案:D
如果 x=2014 ,下面函数的返回值是( )
int fun(unsigned int x) { int n = 0; while(x + 1) { n++; x = x | (x + 1); } return n; }
A: 20 B: 21 C: 23 D 25
运算符 “ | ” 的作用是:把参见运算两个数所对应的二进制位分别进行“或”运算,即:两位同为“0”,结果才为“0”。
x=x|(x+1)的作用是每次循环把x的二进制中从右往左数的最后一位0变成1
这个作用是对整型中0的个数进行统计,当数的二进制中的0全成为1时,栈溢出全为0循环停止。2014的二进制序列为:0000 0000 000 0000 0000 0111 1101 1110有23个0,所以返回值为23.
答案:C
以下选项中,对基本类型相同的两个指针变量不能进行运算的运算符是( )
A: + B: - C: = D: ==
A错误,因为两个地址相加无意义也可能越界,所以规定不允许指针相加。B选项,可以求出两个数据元素储存位置之间的相 隔同数据类型的元素个数,C选项,赋值,没问题,D选项,判断两指针是否相同。
答案:A
关于代码的说法正确的是( )
#include <stdio.h> int main() { int x = -1; unsigned int y = 2; if (x > y) { printf("x is greater"); } else { printf("y is greater"); } return 0; }
A: x is greater B: y is greater C: 依赖实现 D: 随机
x是有符号数-1,内存中是全1,当有符号的x和无符号数进行比较时,x会隐式类型转换被当做无符号数,是一个很大的数。
算数转换与整型提升如果算数转换不理解的,可以看前面连接的博客进行学习
答案:A
下面函数的输出结果是( )
void func() { int k = 1^(1 << 31 >> 31); printf("%d\n", k); }
A: 0 B: -1 C: -2 D: 1
这里的考点就是移位操作符的使用。
<<(左移):就是把一个二进制数整体向左移动, 舍弃超出的部分,在移动的空白处加0。
>>(右移):算数右移:右边丢弃,左边补原来的符号位。
1的二进制:00000000000000000000000000000001
(1 << 31 );左移31位: 10000000000000000000000000000000
(1<<31>>31):右移31位:1111111111111111111111111111111111111
00000000000000000000000000000001^1111111111111111111111111111111111111 =
1111111111111111111111111111111111110 = -2
答案:C
读代码选结果( )
int count = 0; int x = -1; while(x) { count++; x = x >> 1; } printf("%d",count);
A: 1 B: 2 C: 32 D: 死循环,没结果
算数右移是将右边丢弃,左边补原来的符号位。
负数的符号位是1,所以x永远不会变为0,是个死循环
答案:D
以下程序运行后的输出结果是( )
int main() { int a=1,b=2,m=0,n=0,k; k=(n=b<a)&&(m=a); printf("%d,%d\n",k,m); return 0; }
A: 0,0 B: 0,1 C: 1,0 D: 1,1
k=(n=b<a)&&(m=a);这是这道题的关键:执行顺序如下:先执行n=b<a,赋值运算符优先级低于关系运算符,所以b<a得到0n=0。(0)&&(m=a),&&运算前表达式为假,则 后面的括号(m=a)不运算,m值还是0,最后,&&的结果是0,即k=0
答案:A
以下逗号表达式的值为( )
(x = 4 * 5 , x * 5) , x + 5;
A: 25 B: 20 C: 100 D: 45
逗号表达式是从前到后依次计算子表达式,而其结果是最后一项的值,此题去掉括号后的表达式,和原表达式是等价的,先 计算4*5并赋值给x,x变为20,中间x*5并没有改变x的值,最后一项x+5值是25,也就是整个表达式的值。
答案:A
在下面的字符数组定义中,哪一个有语法错误( )
A: char a[20]="abcdefg";
B: char a[]="x+y=5.";
C: char a[15];
D: char a[10]='5';
D中的'5'是一个字符常量,不能给字符型数组a初始化
答案:D
已知 i,j 都是整型变量,下列表达式中,与下标引用 X[i][j] 不等效的是【多选】( )
A: *(X[i]+j)
B: *(X+i)[j]
C: *(X+i+j)
D: *(*(X+i)+j)
本题考查的是二维数组的元素访问,A选项是 正确的,X[i]就是第i行的数组名,数组名表示首元素的地址,X[i]表示第i行的第 一个元素的地址,+j后就是第i行下标为j的元素的地址,整体解引用就是X[i][j],A正确。B选项因为[]的优先级高于*,所以代 码相当于**((x+i)+j),X+i+j后就越界了,并不代表X[i][j],所以错误。C选项也明显不对,X是二维数组的数组名,数组名相当于第 一行的地址,X+i+j,跳过了i+j行,就越界了,C错误。D选项是标准的指针形式访问二位数组的一个元素。
答案:B、C
在上下文及头文件均正常的情况下,下列代码的输出是( )(注: print 已经声明过)
int main() { char str[] = "Geneius"; print(str); return 0; } print(char *s) {if(*s){print(++s);printf("%c", *s);} }
A: suiene B: neius C: run-time error D: suieneG
代码实现了递归倒序打印字符串的功能,但是++s使得s的值发生了变化,回不到'G'的位置上,故而没有打印'G'
答案:A
在C语言中,以下正确的说法是( )
A: 实参和与其对应的形参各占用独立的存储单元
B: 实参和与其对应的形参共占用一个存储单元
C: 只有当实参和与其对应的形参同名时才共占用存储单元
D: 形参是虚拟的,不占用存储单元
在调用函数的时候,真实传递给函数的是实参,函数定义部分函数名后的参数是形参。形参和实参的名字是可以相同的,在 函数调用的时候,形参是实参的一份临时拷贝,分别占用不同的内存空间,所以A正确,B错误,及时形参和实参的名字相 同,也是占用不同的内存空间,所以B错误;函数如果不被调用时,函数的形参是形式上存在的,但是函数在被调用的时候, 形参是要分配内存空间的,所以D错误。
答案:A
5、在c语言中,一个函数不写返回值类型,默认的返回类型是( )
A: int B: char C: void D: 都不是
一个函数不写返回值类型,默认的返回类型是int,但不提倡这么做
答案:A
我们知道C语言的 break 语句只能跳出离它最近的一层循环,可是有时候我们需要跳出多层循环,下列跳出多层 循环的做法正确的是【多选】( )
A: 将程序写成函数用return结束函数,便可跳出循环
B: 修改外层循环条件例如
for( int i = 0 ; i < MAX1 ; i ++ ) {for( int j = 0 ; j < MAX2 ; j ++ ){if( condition ){i = MAX1;break;}} }
C: 在外层循环设置判断条件例如
for( ; symbol != 1 && condition2 ; ) {for( ; symbol != 1 && condition3 ; ){if( condition1 )symbol = 1 ;} }
D: 在外层循环后面加入break例如
for( ; condition2 ; ) {for( ; condition3 ; ){if( condition1 )symbol = 1 ;}if( symbol == 1 )break ; }
A选项可以使用return强制结束函数内容,跳出循环。
B选项将第一层跳出循环条件改成跳出条件,使用break跳出第二层循环也是不错的方法。
C选项是将两次循环跳出条件关联,改变symbol内容即可跳出两层循环。
D选项在外层使用break,当他已经第二层循环跳出时会判断symbol内容跳出。
此题旨在整理跳出多层循环的方法,每个选项都是正确的,代码为伪代码,condition代表逻辑表达式。
答案:ABCD
以下程序运行时,若输入 1abcedf2df 输出结果是( )
#include <stdio.h> int main() {char ch;while ((ch = getchar()) != '\n'){if (ch % 2 != 0 && (ch >= 'a' && ch <= 'z'))ch = ch - 'a' + 'A';putchar(ch);}printf("\n");return 0; }
A: 1abcedf2df B: 1ABCEDF2DF C: 1AbCEdf2df D: 1aBceDF2DF
我们首先得看函数的功能是什么?
函数功能为:将奇数内容并且为小写字母的转为大写。程序首先考虑ch的ASCII码值是不是奇数,再看是不是小写字母,同时满足时被改为大写字母。
答案:C
今天先分享这么多经典题目,更多题目尽情期待博主后期博客更新。希望这些题目可以帮助到你们更好的学习语言!!!