目录
题目一:
题目二:
题目三:
题目四:
题目五:
题目六:
题目七:
题目八:
题目九:
题目十:
题目十一:
题目十二:
题目十三:
题目十四:
题目十五:
题目十六:
题目十七:
题目十八:
题目十九:
题目二十:
题目二十一:
题目二十二:
题目二十三:
题目二十四:
题目二十五:
题目二十六:
题目二十七:
题目二十八:
题目二十九:
题目三十:
题目三十一:
题目三十二:
题目三十三:
题目三十四:
题目三十五:
题目三十六:
题目三十七:
题目三十八:
题目三十九:
题目四十:
题目四十一:
题目四十二:
题目四十三:
题目四十四:
题目四十五:
题目四十六:
题目四十七:
题目四十八:
题目四十九:
题目五十:
题目五十一:
题目五十二:
题目五十三:
题目五十四:
题目五十五:
题目五十六:
题目五十七:
题目五十八:
题目五十九:
题目六十:
题目六十一:
题目六十二:
题目六十三:
题目六十四:
题目六十五:
题目六十六:
题目六十七:
题目六十八:
题目六十九:
题目七十:
题目七十一:
题目七十二:
题目七十三:
题目七十四:
题目七十五:
题目七十六:
题目七十七:
题目七十八:
题目七十九:
题目八十:
题目一:
执行下面程序,正确的输出是( )
A: 5,7 B: 7,5 C: 3,8 D: 8,3
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;
}
选择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};
选择B。
题解:
- 选项A正确。选项A是一个双精度类型的数组,并且进行了初始化,数组的大小为5,属于完全初始化状态。
- 选项B错误。选项B是一个字符数组,里面有三个元素,前两个元素分别表示16进制,运用了转义字符'\x00'的形式,最后一个元素想表达8进制,但8进制逢八进一,因此'\8'是不正确的。
- 选项C正确。选项C是一个字符数组,一维数组可以省略数组的大小,但必须进行初始化,选项中初始化了5个元素,因此该数组的大小也默认为5。
- 选项D正确。选项D是一个整形数组,在定义数组时,数组大小,即[]里可以是常量表达是,因此[5+3]是一个常量表达式,是可以的。
题目三:
test.c 文件中包括如下语句,文件中定义的四个变量中,是指针类型的变量为【多选】( )
A: a
B: b
C: c
D: d
#define INT_PTR int*
typedef int* int_ptr;
INT_PTR a, b;
int_ptr c, d;
选择ACD。
题解:
- 选项A正确。选项A中,是一种#define定义标识符形式,这种形式会进行替换操作,因为替换下来的内容为int*,因此int* a是一个指针类型的变量。
- 选项B错误。选项B与选项A的是声明变量形式的一种,可以进行多个变量直接用逗号进行声明,但是声明时的类型选项B为int类型,与选项A不同,这是因为#define标识符,并不属于类型,只是内容的替换操作,进行宏替换后代码是这样的:int *a, b,因此只会作用于选项A。
- 选项C正确。选项C中,是一种typedef自定义类型名,属于给类型起别名,本质上还是该类型,只不过换了名字,因此属于指针类型的变量。
- 选项D正确。与选项C相同,typedef自定义类型名后,仍然属于指针类型,并且这种书写方式是一种变量声明允许的形式,声明多个变量时,用逗号分隔。
#define定义宏/标识符:本质是替换,并没有实际意义。
typedef:类型重命名,本质上还是原来的类型,只不过换了名字表示。
题目四:
若给定条件表达式 (M)?(a++):(a--) ,则其中表达式 M ( )
A: 和(M==0)等价
B: 和(M==1)等价
C: 和(M!=0)等价
D: 和(M!=1)等价
选择C。
题解:
给定条件表达式(M)?(a++):(a--)。 (表达式1)? (表达式2): (表达式3)为三目运算符。 计算规则为:先判断表达式1是否为真,若为真,则计算表达式2,并将表达式2的结果作为整个表达式最终的结果,表达式3 不计算;否则,表达式3的结果为最终结果,表达式2不计算。 在此表达式中,若M=0,为假,计算a--; 若M≠0,为真,计 算a++; 若要求与M等价,则要满足M取0时为假,取非0数值时为真。 c选项中:假定M取0,则M表示假,当M是0时,表达式 M!=0不成立,为假,计算a--; 当M取非0数值时,M为真,表达式M!=0成立,为真,计算a++; 符合题意,选C。
题目五:
有如下定义语句,则正确的输入语句是【多选】( )
A: scanf("%d%s",&b,&c);
B: scanf("%d%s",&b,c);
C: scanf("%d%s",b,c);
D: scanf("%d%s",b,&c);
int b;
char c[10];
选择AB。
题解:
题目中有两条语句:int b 和 char c[10],b为整形变量,c为字符数组。输入语句,scanf是一个输入函数,也称为格式化输入函数,输入的量需要匹配格式符号,如输入int型的变量,则需要匹配%d,输入字符数组,则需要匹配%s。
而scanf函数,需要传入要输入变量的地址。变量的地址进行&地址操作即可,数组的地址通常为数组名,数组名即首元素地址。而题目中,进行&数组名的操作也是正确的,&数组名表示整个数组的地址,但存储的也是首元素的地址,只有通过加减操作时,才能体现出来不同,因此AB选项效果是相同的。
题目六:
以下程序段的输出结果是( )
A: 12 B: 13 C: 16 D: 以上都不对
#include<stdio.h>
int main()
{
char s[] = "\\123456\123456\t";
printf("%d\n", strlen(s));
return 0;
}
选择A。
题解:
这道题主要考察转义字符的理解,字符数组s中有三组转义字符,分别是:\\,\123,\t。
- \\:对\进行转义,如果不转义。则会与\后的123组成一个8进制数。
- \123:转义字符,表示8进制数。\000
- \t:横向制表符。
题目七:
若有以下程序,则运行后的输出结果是( )
A: 4 B: 8 C: 9 D: 6
#include <stdio.h>
#define N 2
#define M N + 1
#define NUM (M + 1) * M / 2
int main()
{
printf("%d\n", NUM);
return 0;
}
选择B。
题解:
这道题考察的是#define宏替换知识。#define是一种直接替换规则,往往是先替换再计算,计算过程看下图:
题目八:
如下函数的 f(1) 的值为( )
A: 5 B: 6 C: 7 D: 8
int f(int n)
{
static int i = 1;
if(n >= 5)
return n;
n = n + i;
i++;
return f(n);
}
选择C。
题解:这道题考察的是对static静态修饰符的用法。下面对static用法进行讲解:
- static修饰局部变量:改变了局部变量的生命周期,让其出了作用域不销毁,保留数据,此时该局部变量不存放在栈区,存放在静态区。
- static修饰全局变量:改变了全局变量的外部链接属性,全局变量是作用域为整个工程,其它源文件声明外部变量后,可进行时候,当进行static修饰时,全局变量的作用域为本源文件。
- static修饰函数:改变了函数的外部链接属性,与全局变量一样,函数是作用于整个工程的,当static修饰后,只能在本源文件使用。
题目九:
下面3段程序代码的效果一样吗( )
A: (2)=(3) B: (1)=(2) C: 都不一样 D: 都一样
int b;
(1)const int *a = &b;
(2)int const *a = &b;
(3)int *const a = &b;
选择B。
题解:
这道题考察const修饰符的知识点。const修饰符可以修饰变量与修饰指针。
- 修饰变量:当一个变量被const进行修饰,那该变量变为常变量,拥有了常量属性,变量值不能被修改,从语法层次上属于常量范畴,从该变量本身上,还是变量,可以通过指针操作修改。
- 修饰指针的两种情况:
- const修饰指针时放在*的左边时:将对指针指向的变量的值进行限制,不能修改指针指向变量的值,对指针的指向,即存储地址不作限制
- const修饰指针时放在"*的右边时:将对指针的指向,即存储的地址进行限制,不能修改指针的内容,即指针中存放的地址,可以修改指针指向变量的值。
- 简易口诀:左定值,右定向。
题目十:
对于下面的说法,正确的是( )
A: 对于 struct X{short s;int i;char c;},sizeof(X)等于sizeof(s) + sizeof(i) + sizeof(c)
B: 对于某个double变量 a,可以使用 a == 0.0 来判断其是否为零
C: 初始化方式 char a[14] = "Hello, world!"; 和char a[14]; a = "Hello, world!";的效果相同
D: 以上说法都不对
选择D。
题解:
- 选项A错误。计算struct结构体类型字节大小不能通过简单相加成员变量的字节大小得到,需要进行内存对齐方式,步骤分别是:
- 第一个成员变量的字节大小从偏移量0处开始存放。
- 后面的成员变量,计算出该变量的对齐数,对齐数计算公式为:字节数:编译器默认对齐数,取较小值,则为该变量的对齐数。
- 根据对齐数,将该变量存储到该对齐数倍数的位置上,如对齐数为4,则查看偏移量中4的位置是否没被存储,如果没有则将从偏移量4的位置依次存储4字节,如果有,则再看偏移量8的位置,依次类推。
- 最后计算出结构体类中每个成员变量的对齐数,然后取最大的对齐数,此时该对齐数必须是偏移量中存储后字节个数的倍数,因为偏移量是从0开始的,如果偏移量存储到7的位置,其实已经存储了8个字节,如果结构体中最大对齐数是8,那就要是8的倍数的字节,则正好合适,那么,这个结构体的字节大小就为8了,同样的,如果不是8个字节,那就要找8的倍数,即16,这将会舍弃一部分空间,拿空间换对齐的做法,以此类推。
- 选项B错误。B选项,考察double类型的比较,由于浮点数存在误差,不能直接判断两个数是否相等,通常采 用比较两数之差的绝对值是否小于一个很小的数字(具体的可自己设定这样一个数,作为误差)来确定是否相等。
- 选项C错误。当将数组进行声明没有进行初始化时,在声明后进行初始化,对于字符数组来说,有两种方式:gets和循环输入。题目中的做法是不正确的,a是表示数组的首元素地址,直接进行复制字符串是错误的,为数组首地址是常量不能改变。
题目十一:
已知函数的原型是: int fun(char b[10], int *a); ,设定义: char c[10];int d; ,正确的调用语句是( )
A: fun(c,&d);
B: fun(c,d);
C: fun(&c,&d);
D: fun(&c,d);
选择A。
题解:
- 选项A正确。题目中的函数有两个形参,分别是字符数组与整形指针,因此在主调函数中,所要传递的实参类型为:数组名和整形地址。因此选项A符合。
- 选项B错误。B选项的错在第二个参数中,传递的是一个变量或常量,并不是一个地址。
- 选项C错误。函数中需要接受字符数组和整形指针,在C选项中,第二个参数符合,第一个参数不正确,因为对&数组名操作是取出数组的地址,那么在C语言中,要存储数组的地址,需要一个指针数组,则对应形参应该为:char (*)b[10]。
- 选项D错误。两个实参均错误,第一个参数应传递数组名,即首元素地址,第二个参数应传递d变量的地址。
题目十二:
请问下列表达式哪些会被编译器禁止【多选】( )
A: *c = 32;
B: *d = 43
C: e=&a
D: f=0x321f
int a = 248, b = 4;
int const *c = 21;
const int *d = &a;
int *const e = &b;
int const * const f = &a;
选择ABCD。
题解:
C语言中,const关键字有两种用法:分别是修饰变量和修饰指针
- const修饰变量:该变量称为常变量,拥有了常属性,即从语法层次上该变量变为常量,不能被修改,但从变量本身来说,还是变量,因此叫常变量。
- const修饰指针:有两种情况:
- const在*的左边:此时const修饰的是指针指向变量的内容,被const修饰,不能进行修改。
- const在*的右边:此时const修饰的是指针的指向,即指针的内容,被const修饰,不能进行修改。
- 还有一种特殊情况:*的左右两边都被const修饰,此时指针指向的变量内容和指针的指向均不能被修改。
题目十三:
以下程序的输出结果为( )
A: ***
B: *** *** *** ***
C: *** ***
D: * * *
#include <stdio.h>
int i;
void prt()
{
for (i = 5; i < 8; i++)
printf("%c", '*');
printf("\t");
}
int main()
{
for (i = 5; i <= 8; i++)
prt();
return 0;
}
选择A。
题解:
代码中,int i;为全局变量,当在main函数中进行for循环时,i = 5,然后调用prt()函数,接着在prt函数内for循环,此时i = 5,开始循环,当循环执行完毕后,i == 8,此时打印了三个* 和一个制表符,当回到main函数中,此时在for循环内部,继续接着执行,发现i++后,i == 9了,因此结束循环。
题目十四:
下面代码段的输出是( )
A: -6
B: 12
C: 0
D: -12
int main()
{
int a=3;
printf("%d\n",(a+=a-=a*a));
return 0;
}
选择D。
题解:
本题考查复合赋值运算符的知识点。对于代码中:(a+=a-=a*a),根据赋值语句的规定,执行顺序是从右到左,再执行之前,我们可以将该表达式展开:a = a + (a = a- a * a) ,开始计算:a = a + (-6),此时a的值不再是3,因为(a = a-a*a)是一个赋值语句,会改变a的值,最后:a = -6 + -6,a == -12。
题目十五:
下列不能实现死循环的是( )
A: while(1){}
B: for(;1;){}
C: do{}while(1);
D: for(;0;){}
选择D。
题解:
C语言中规定·,0为假,非0为真。题目中只有D选项的判断条件出为假,即0,因此不会进入循环,构成不了死循环。
题目十六:
设变量已正确定义,以下不能统计出一行中输入字符个数(不包含回车符)的程序段是( )
A: n=0;while(ch=getchar()!='\n')n++;
B: n=0;while(getchar()!='\n')n++;
C: for(n=0;getchar()!='\n';n++);
D: n=0;for(ch=getchar();ch!='\n';n++)
选择D。
题解:
此题考查的是使用getchar清空缓冲区的知识点。
- 选项A正确。当我们进行输入操作时,输入的内容不单单是键盘上输入的内容,我们往往会在最后敲上一个回车(\n),而回车也会被存储在缓冲区中,在程序进行读取时,也会将回车读取,但往往回车并不是我们要的内容,因此需要进行判断,当读取内容是回车时,则不再执行程序,因此选项A将读取内容放到ch中进行判断是正确的。
- 选项B正确。同样的,getchar读取缓冲区里的内容后进行判断,读取到的内容可以不放置变量中,仍然可以进行判断。
- 选项C正确。与while循环一样,只是三个部分的定义位置不同,在for循环中,对于读取缓冲区内容,需要定义在条件判断部分。
- 选项D错误。for循环中第一项初始化表达式只会执行一次,即第一次执行循环时,因此将读取缓冲区的代码放在初始化部分,因此ch只从输入流中取一个字符,之后就再不会取字符,因此会死循环。
题目十七:
运行以下程序后,如果从键盘上输入 65 14 ,则输出结果为( )
A: 3
B: 2
C: 1
D: 0
int main()
{
int m, n;
printf("Enter m,n;");
scanf("%d%d", &m,&n);
while (m!=n) //1
{
while(m>n) m=m-n; //2
while(n>m) n=n-m; //3
}
printf("m=%d\n",m);
return 0;
}
选择C。
题解:
本题没什么技巧,需要耐心的计算。考查while循环和循环嵌套的理解,初值m=65,n=14;循环1判断m!=n为真,来到循环2判断m>n为真,执行 m=m-n;直到m=9,n=14;循环2结束来到循环3判断n>m为真,执行n=n-m;直到m=9,n=5;循环3结束回到循环1,如此往复直 到m==n时,循环结束。
题目十八:
若运行以下程序时,从键盘输入 ADescriptor ,则下面程序的运行结果是( )
A: v0=7,v1=4,v2=7
B: v0=8,v1=4,V2=8
C: v0=11,v1=4,v2=11
D: v0=12,v1=4,v2=12
#include <stdio.h>
int main()
{
char c;
int v0=0,v1=0,v2=0;
do
{
switch(c=getchar())
{
case'a':case'A':
case'e':case'E':
case'i':case'I':
case'o':case'O':
case'u':case'U':v1 += 1;
default:v0+= 1;v2+=1;
}
}while(c!='\n');
printf("v0=%d,v1=%d,v2=%d\n",v0,v1,v2);
return 0;
}
选择D。
题解:
本题考查do...while循环和switch语句的知识点。
题目中说明会从键盘输入 ADescriptor <回车>,对于do...while循环来说,是先执行后判断,虽然该题的判断条件是c!='\n'时结束循环,但因为是do...while循环,因此当读取到\n时,仍然执行一次再进行判断。
而对于switch选择语句来说,case后没有break的情况下,会一直往下执行,直到遇到break或执行结束,因此无论输入什么,都会执行default语句,因此v0和v2的值是一样的,均为12,对于v1来说,只有符合case后的常量才执行,因此为4。
题目十九:
如下函数是求两个int数字最大公约数的,指出其中存在的问题【多选】( )
A: 参数类型不对
B: 循环变量min初值不对
C: 判断等于的符号不对
D: 返回类型不对
int gcd(char x,char y)
{
int min = x < y ? x : y;
for (min = 0; min > 0; min--)
if (x % min = 0 && y % min = 0)
return min;
}
选择ABC。
题解:
本题主要考查函数的参数、for循环的初始条件、以及等于和赋值的区别。
题目是用函数求两个int数字的最大公约数,而gcd函数的形参类型为字符类型,因此不符合题目要求。函数内部的for循环,mind的初始值被赋值为0,但条件判断部分缺不符合,因此不会进入循环。对于for循环内部的if判断语句来说,min = 0,这是赋值语句,会改变min的值,这在判断语句中是一个大忌。因此要区分好min == 0和min = 0的区别。
题目二十:
执行下面的程序段,语句3的执行次数为( )
A: n(n+2)/2
B: (n-1)(n+2)/2
C: n(n+1)/2
D: (n-1)(n+2)
for(i = 0; i <= n-1; i++) // (1)
for(j = n; j > i; j--) // (2)
state; // (3)
选择C。
题解:
外循环有n次,当i=0,内循环为n次,当i=1,内循环为n-1次,当i=2时,内循环为n-2次,以此类推,总次数为 n+(n-1)+(n-2)+......+2+1,就是个等差数列,等于n(n+1)/2。
题目二十一:
如下程序的功能是( )
A: 测字符数组ch的长度
B: 将数字字符串ch转换成十进制数
C: 将字符数组ch中的小写字母转换成大写
D: 将字符数组ch中的大写字母转换成小写
#include <stdio.h>
int main()
{
char ch[80] = "123abcdEFG*&";
int j;
puts(ch);
for(j = 0; ch[j] != '\0'; j++)
if(ch[j] >= 'A' && ch[j] <= 'Z')
ch[j] = ch[j] + 'e' - 'E';
puts(ch);
return 0;
}
选择D。
题解:
- 该代码的作用是将一个大写字母转换成小写字母。
- 在Ascll码表中,大写字母从65开始,小写字母从97开始,因此大写字母和小写字母之间相差了32。
- 代码中的ch[j] + 'e' - 'E'相当于ch[j] + 32,因为小写字母-大写字母,可以得出相差32
- 大写字母 + 32 ,就等于对应的小写字母。
题目二十二:
对于代码段,下面描述正确的是()
A: 其中循环控制表达式与0等价
B: 其中循环控制表达式与'0'等价
C: 其中循环控制表达式是不合法的
D: 以上说法都不对
t=0;
while(printf("*"))
{
t++;
if (t<3)
break;
}
选择B。
题解:
- printf输出函数是由返回值的,返回值为打印在输出框里的字符个数,如printf("*"),那将会把字符*打印在屏幕上,则为1。
- 因此while循环条件恒为真,选项中只有B选项符合。
- '0'与0不一样,'0'转化为Ascll码值为48,因此也是恒为真的。
题目二十三:
以下程序运行时,若输入 1abcedf2df 输出结果是( )
A: 1abcedf2df
B: 1ABCEDF2DF
C: 1AbCEdf2df
D: 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;
}
选择C。
题解:
- 代码的主要意图是将符合条件的小写字母转为大写字母。
- 小写字母与大写字母相差32,因此小写字母-大写字母就能得出32,在与大写小写字母相减,则转化为大写字母。因为大写字母在Ascll码中比小写字母小。
- 程序首先考虑ch的ASCII码值是不是奇数,再看是不是小写字母,同时满足时被改为大写字母。
题目二十四:
下列条件语句中,功能与其他语句不同的是( )
A: if(a) printf("%d\n",x); else printf("%d\n",y);
B: if(a==0) printf("%d\n",y); else printf("%d\n",x);
C: if (a!=0) printf("%d\n",x); else printf("%d\n",y);
D: if(a==0) printf("%d\n",x); else printf("%d\n",y);
选择D。
题解:
- 可以将题目理解为:判断条件a为0则打印y,a不为0,则打印x。
- 因此选项中ABC是符合的,只有D选项是a为0,打印x,a不为0,打印y。
题目二十五:
我们知道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 ; }
选择ABCD。
题解:
- 选项A正确。return为返回关键字,往往在函数中用于返回返回值,return之后,函数将结束,因此在多层循环下,进行return来跳出循环是正确的。
- 选项B正确。将外层循环的值改变后,内层循环中的break跳出了内层循环到外层循环,此时会继续对外层循环进行判断,而此时的外层循环条件已被改为MAX1,因此不符合,则实现跳出循环。
- 选项C正确。与选项B类似,更改了判断条件中的值,让内外层循环均为假,则跳出循环。
- 选项D正确。因为break只能跳出一层循环,因此直接在外层循环加break是正确的。
题目二十六:
以下叙述中正确的是( )
A: 只能在循环体内和switch语句体内使用break语句
B: 当break出现在循环体中的switch语句体内时,其作用是跳出该switch语句体,并中止循环体的执行
C: continue语句的作用是:在执行完本次循环体中剩余语句后,中止循环
D: 在while语句和do-while语句中无法使用continue语句
选择A。
题解:
- break:终止循环,只能循环语句和switch语句使用。
- continue:跳过本次循环,执行下一次循环,只能在循环语句使用。
题目二十七:
下列for循环的次数为( )
A: 0
B:5
C:1
D: 无限
for(int i = 0 ; i || i++ < 5;);
选择D。
题解:
这道题主要考察for循环条件判断和逻辑或操作符相关知识点。
在第一次执行for循环时,程序对for循环的条件判断部分进行判断真假,发现为真,因此进入循环体执行循环,执行一次后,因为条件判断部分进行了i++,因此i变为1,当进行判断时。发现i为1,则不会再判断||后的语句,进入循环,i的值始终为1,导致死循环。
- 逻辑或的特殊:当发现左边为1时,整个表达式为1,不会执行||后的表达式
- 逻辑与的特殊:当发现左边为0时,整个表达式为0,不会执行&&后的表达式
题目二十八:
以下描述中正确的是( )
A: 由于do-while循环中循环体语句只能是一条可执行语句,所以循环体内不能使用复合语句 B: do-while循环由do开始,用while结束,在while(表达式)后面不能写分号
C: 在do-while循环体中,不一定要有能使while后面表达式的值变为零("假")的操作
D: do-while循环中,根据情况可以省略while
选择C。
题解:
这道题考察do...while循环相关知识点。
do...while循环与其它循环的区别:
- 循环体至少执行一次
- while(表达式)后需要写分号
因此这题可以排除掉B。选项A错误。循环体可以使用复合语句,并且大部分是使用复合语句。选项D错误。不能省略while,这在C语言中不支持。因此选择C,虽然在循环体不写使while后面表达式值变为假的操作会造成死循环,但并不是错误的,只是不提倡。
题目二十九:
设函数fun和实参数组的说明是如下形式,则对函数的调用语句中,正确的是( )
A: fun("asd" , a[]);
B: fun('x' , A);
C: fun('68' , 2.8);
D: fun(32 , a);
void fun(char ch,float x[]);
float a[10];
选择D。
题解:
fun函数有两个参数,分别是char类型和float数组类型,在C语言中,对于函数形参其实并没有用数组接收,只是支持写出数组的模样,本质上还是指针变量,用于接收数组的首元素地址。
因此选项中只有D选项符合,实参中传递32和a,对于char类型来说,字符是以ascll码值进行存储的,因此传递32是可以的,对于着ascll码值32的字符,第二个参数传递了a,即数组首元素地址。
题目三十:
在c语言中,一个函数不写返回值类型,默认的返回类型是( )
A:int
B:char
C:void
D:都不是
选择A。
题解:
在C语言中,一般情况下对于函数的返回值是由定义的,根据return值,进行声明对应得返回值类型,当然,可以不写返回值类型,但C语言中不写返回值类型会有默认的返回值类型,即int形,因此在有一些书籍上,可能看到以下代码:
main()
{
return 0;
}
题目三十一:
以下对C语言函数的有关描述中,正确的有【多选】( )
A: 在C语言中,一个函数一般由两个部分组成,它们是函数首部和函数体
B: 函数的实参和形参可以是相同的名字
C: 在main()中定义的变量都可以在其它被调函数中直接使用
D: 在C程序中,函数调用不能出现在表达式语句中
选择AB。
题解:
本题考察函数相关知识点。
- 选项A正确。在C语言中,函数确实是由两个部分组成,分别是函数首部和函数体。
- 选项B正确。函数实参和形参的名字可以相同,因为实参和形参处于不同的内存空间中,相对应的作用域就不一样了,因此使用相同的变量名是可以的。
- 选项C错误。在main()函数中定义的变量属于main函数内的局部变量,局部变量只在局部范围使用,在其它函数中是不能使用的。
- 选项D错误。C程序中,函数调用可以出现在表达式语句中。
题目三十二:
在C语言中,以下正确的说法是( )
A: 实参和与其对应的形参各占用独立的存储单元
B: 实参和与其对应的形参共占用一个存储单元
C: 只有当实参和与其对应的形参同名时才共占用存储单元
D: 形参是虚拟的,不占用存储单元
选择A。
题解:
本题考察实参和形参的知识点。
- 选项A正确。实参与对应的形参各自拥有独立的存储单元的,只不过形参的值和实参一样,因此可以说形参是实参的一份临时拷贝。
- 选项B错误。实参与形参不会公用一块存储单元,在进行函数调用之前,会将形参进行压栈操作,创建了一块存储单元存放实参的值,这块空间也叫形参,因此形参是实参的一份临时拷贝。
- 选项C错误。实参和形参是可以同名的,因为在不同的存储单元中,因此无论是否同名,实参和形参不共同占用存储单元。
- 选项D错误。形参是占存储单元的,在函数调用前,会将实参的值存储到寄存器中,然后进行压栈,相当于临时拷贝了实参。
题目三十三:
在上下文及头文件均正常的情况下,下列代码的输出是( )(注: print 已经声明过)
A: suiene
B: neius
C: run-time error
D: suieneG
int main()
{
char str[] = "Geneius";
print(str);
return 0;
}
print(char *s)
{
if(*s)
{
print(++s);
printf("%c", *s);
}
}
选择A。
题解:
本题考察指针、前置++、函数递归相关知识点。
代码中有一个字符数组str,值为Geneius,在第一次调用函数时,指针s指向首元素地址G,经过判断,符合进入判断题,接着开始递归调用了,调用时,实参为++s,这就代表着,会先改变指针的地址指向,再进行传参,因此递归到s指向\0时,不符合条件进行返回,每返回一次,*s的值已经是++后的了,因此只会打印suiene,G是不会打印的,因为s的指向前置++了。
题目三十四:
对于函数 void f(int x); ,下面调用正确的是( )
A: int y=f(9);
B: f(9);
C: f(f(9));
D: x=f();
选择B。
题解:
本题考查函数调用知识点。
- 选项A错误。void f(int x)函数是无返回值函数,因此用int x接收不不正确的。
- 选项B正确。函数是一个无返回值,参数为int类型的函数,因此f(9)正确。
- 选项C错误。f(f(9))这种将函数作为函数的实参行为本质上是可以的,也叫做链式访问,但需要遵循一个原则:作为另一个函数参数的函数必须要有返回值,但本题的函数是没返回值的,因此错误。
- 选项D错误。选项D在调用函数时没有传递int类型的数据,并且用x来接收返回值,但本题函数是没有返回值的,并且x也没声明类型。
题目三十五:
给定 fun 函数如下,那么 fun(10) 的输出结果是( )
A: 0
B: 10
C: 55
D: 3628800
nt fun(int x)
{
return (x==1) ? 1 : (x + fun(x-1));
}
选择C。
题解:
本题考察函数递归的知识点。
代码是一个递归函数,计算x+(x-1)+(x-2)+...+2+1即等差数列的和。
题目三十六:
如下程序的运行结果是( )
A: 'a' 'b'
B: ab\0c\0
C: ab c
D: ab
char c[5]={'a', 'b', '\0', 'c', '\0'};
printf("%s", c);
选择D。
题解:
本题考察格式化字符%s打印字符串知识点。在C语言中,使用%s打印字符数组时,%s的特点是打印\0之前的字符。
题目三十七:
若有定义: int a[2][3]; ,以下选项中对 a 数组元素正确引用的是( )
A: a[2][0]
B: a[2][3]
C: a[0][3]
D: a[1>2][1]
选择D。
题解:
本题考查二维数组的使用知识点。
- 选项A错误。该数组的行和列分别为2、3,选项A使用数组时指定的行下标为2,超出了行的范围。
- 选项B错误。与选项A类似,选项B使用的行和列下标均超过范围
- 选项C错误。使用的列下标超过范围。
- 选项D正确。C语言规定,数组[]访问操作符中,需要是常量表达式,因此选项D中a[1>2][1]符合条件,1>2表达式的值为假,即0.
题目三十八:
在下面的字符数组定义中,哪一个有语法错误( )
A: char a[20]="abcdefg";
B: char a[]="x+y=5.";
C: char a[15];
D: char a[10]='5';
选择D。
题解:
本题考察字符数组的定义以及初始化知识点。
- 选项A正确。定义了一个大小为20的字符数组,并进行了初始化。
- 选项B正确。将数组大小进行省略,并且对数组进行初始化。
- 选项C正确。定义了一个字符数组。
- 选项D错误。'5'是一个字符,需要用char类型接收,而题目中是字符数组,接收时有两种方式:1、{'', '', '',....} 2、" "
题目三十九:
下列定义数组的语句中正确的是【多选】( )
A:
#define size 10 char str1[size], str2[size+2];
B: char str[];
C: int num['10'];
D: int n=5; int a[n][n+2];
选择AB。
题解:
本题考察数组的定义知识点。
- 选项A正确。在数组定义时,数组的大小必须是常量表达式,选项A用#define定义了标识符常量,属于常量,因此正确。
- 选项B错误。定义数组时,可以省略数组的大小,但必须进行初始化。
- 选项C正确。选项C定义了一个int整型数组,并且指定了大小为'10','10'为一个字符,在C语言中,字符是以ascll码进行存储的,在定义数组时,将字符作为数组的大小时,会被转化为所对应的ascll码值。
- 选项D错误。在c语言的C99后,支持变长数组的存在,变长数组就是拿变量作为数组大小,但有两个条件:1、数组不能初始化 2、变量的值不能进行修改。而选项D将a数组的列定义为n+2,对变量进行了修改,这是不允许的。
题目四十:
已知 i,j 都是整型变量,下列表达式中,与下标引用 X[i][j] 不等效的是【多选】( )
A: *(X[i]+j)
B: *(X+i)[j]
C: *(X+i+j)
D: *(*(X+i)+j)
选择BC。
题解:
本题考察使用指针对二维数组的使用知识点。
- 选项A错误。X[i]相当于一维数组中的数组名,表示首元素地址,即第一行第一个元素的地址,通过+j操作,会跳过j个类型的空间。是和X[i][j]等效的
- 选项B正确。X相当于二维数组的数组名,即第一行的地址,通过+i操作,会跳过i行的空间,然后在访问[j]的元素,这是一种越界访问,跳过i行会超过数组空间,不符合X[i][j]。
- 选项C正确。同样的,X表示第一行的地址,通过i+j行数组空间,会越界访问,不符合X[i][j]。
- 选项D错误。选项D的 *(*(X+i)+j)其实与选项A等价,X+i 为跳过i行,然后*后,并且获取到这一行的首元素,最后又进行+j操作,意思就是这一行的首元素跳过j个空间,与选项A的作用一样。
题目四十一:
下列程序的输出是( )
A: 上述程序有错误
B:6
C:8
D: 12
#include<stdio.h>
int main()
{
int a [12]= {1,2,3,4,5,6,7,8,9,10,11,12},*p[4],i;
for(i=0;i<4;i++)
p[i]=&a [i*3];
printf("%d\n",p[3][2]);
return 0;
}
选择D。
题解:
本题主要考察指针的运用。
题目代码的意思是将a数组中以3个元素为一组,将每一组的首元素地址存放在指针数组中,在最后打印p[3][2]就为12这个元素。
题目四十二:
二维数组X按行顺序存储,其中每个元素占1个存储单元。若X[4][4]的存储地址为0xf8b82140,X[9][9]的存储地址为0xf8b8221c,则X[7][7]的存储地址为()
A: Oxf8b821c4
B: Oxf8b821a6
C: Oxf8b82198
D:0Xf8b821c0
选择A。
题解:
本题考察数组的存放特点以及计算地址之间差距相关知识点。
题目给出X[4][4]的地址和X[9][9],因此我们可以进行计算所求X[7][7]与X[4][4]相差几个元素,因为每个元素占1个存储单元,即4字节,具体求解过程看下图:
题目四十三:
以下哪个选项可以正确描述 sizeof(double) ( )
A: 一个整型表达式
B: 一个双精度型表达式
C:一个不合法的表达式
D:一种函数
选择A。
本题考察sizeof相关知识。
sizeof在C语言中是一个单目操作符,其作用是传入类型,计算该类型的字节大小,返回一个对象的类型字节大小,结果是无符号整形,因此可以将其看成一个整形表达式。
题目四十四:
下列代码运行后的结果是什么( )
A:b,b
B:b,c
C:a,b
D:a,c
int main()
{
char a = 'a',b;
printf("%c,", ++a);
printf("%c\n", b = a++);
return 0;
}
选择A。
题解:
本题考察前置++与后置++相关知识点。
字符在内存中以Ascll码形式存在,因此++a,其实是对该字符的Ascll码进行+1,对于a++相同,只不过是后置++,会先使用,因此打印的均为:'b'
题目四十五:
以下逗号表达式的值为( )
A:25
B:20
C:100
D:45
(x = 4 * 5 , x * 5) , x + 5;
选择A。
题目:
本题考察逗号表达式知识点。
逗号表达式的特点:从前往后依次计算,整个表达式的值为最后一个表达式的值。因此从前往后算,第一个表达式:x = 4 * 5 中x值为20,第二个表达式 x*5 ,X的值没有变化,因为没有进行赋值操作,最后一个表达式 x + 5,x值为25,因此最后逗号表达式的值为25。
题目四十六:
求函数返回值,传入 -1 ,则在64位机器上函数返回( )
A: 死循环
B: 64
C: 32
D: 16
int func(int x)
{
int count = 0;
while (x)
{
count++;
x = x&(x - 1);//与运算
}
return count;
}
选择C。
本题考察按位与(&)操作符相关知识。
- &操作符特点:一个为0均为0,两个为1才为1.
- 题目中代码在计算x的二进制中有几个1,这是一种常用的代码,x&(x-1),两个相邻的数进行按位与后,就能去掉x低位一个1,因此int类型为4字节,32位,循环32次,count的值也就是32,选择C。
题目四十七:
读代码选结果( )
A: 1
B: 2
C: 32
D: 死循环,没结果
int count = 0;
int x = -1;
while(x)
{
count++;
x = x >> 1;
}
printf("%d",count);
选择D。
题目:
本题考察移位操作符相关知识点。
- 移位操作符分为左移(<<),右移(>>)。
- 左移特点:高位舍弃,低位补零(正负数都一样)
- 右移有两种形式:算数右移、逻辑右移。
- 算数右移:低位舍弃,高位补符号位,正数符号位为0,负数符号位为1.
- 逻辑右移:低位舍弃,高位补0.
- 但大部分编译器采取算数右移。
- 本题对x==-1,进行循环的右移1,因为采取算数右移,-1的补码是全1,因此低位舍弃,高位补符号位1,二进制的值没有改变,因此陷入死循环,没结果。
题目四十八:
下述赋值语句错误的是( )
A: a = (b = (c = 2 , d = 3))
B: i++
C: a/b = 2
D: a = a < a + 1
选择C。
题解:
本题考察赋值语句相关知识点。
- 选项A正确。赋值语句的结合性是从右到左,因此从右边开始计算,b = (c =2, d= 3),括号中是一个逗号表达式,因此整个表达式的值为d = 3,也就是3,因此b为3,那a也为3
- 选项B正确。i++,使用了后置++操作符,但本质上也属于赋值语句,因为改变了自身,相当于:i+=1
- 选项C错误。C语言中规定,赋值语句分为两个区域,一个为左值,即=左边,一个为右值,即=右边,左值需是一个规范的标识符,右值需是一个表达式。选项C的左值错误,左值是不可变化的,并且需要符合标识符的规则。
- 选项D正确。赋值语句右边是一个表达式,因此a < a+1 是可以的,是一个条件表达式,恒为真,那就是1.
题目四十九:
若有 int w=1, x=2, y=3, z=4; 则条件表达 w < x ? w : y < z ? y : z 的值是( )
A: 1
B: 2
C: 3
D: 4
选择A。
题解:
本题考察条件操作符(三目操作符)相关知识点。
- 三目操作符特点:首先判断真假,真的话值取第一个,假取第二个。
- 多个三目操作符:遵循结合性,多个三目操作符构成一个三目操作符时,要从右到左执行。
- 本题从右到左执行,最后值为w,为1.
题目五十:
以下程序运行后的输出结果是( )
A: 0,0
B: 0,1
C: 1,0
D: 1,1
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。
题解:
本题考察逻辑操作符相关知识点。
- 逻辑与:关注真假,一个为假,均为假,两个为真才为真
- 逻辑或:关注真假,一个为真,均为真,两个为假才为假。
- 逻辑与执行特点:当发现前面的表达式为假后,后面表达式不会执行,整个表达式值为假。
- 逻辑或执行特点:当发现前面的表达式为真后,后面表达式不会执行,整个表达式为真。
- 本题符合逻辑与的执行特点,(n=b<a)为0,即为假,因此后面的(m=a)不会执行,k和m均为0.
题目五十一:
声明以下变量,则表达式: ch/i + (f*d – i)的结果类型为( )
char ch; int i; float f; double d;
A:char
B:int
C:float
D:double
选择D。
题解:
本题主要考察各种类型进行混合计算时,类型的转换。
基本数据类型的等级从低到高如下:char int long float double运算的时候是从低转到高的,表达式的类型会自动提升 或者转换为参与表达式求值的最上级类型。因此当任何类型与double进行算术运算时,最后都是double。
题目五十二:
关于代码的说法正确的是( )
A:x is greater
B:y is greater
C:依赖实现
D:随机
#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。
题解:
本题考察当有符号整形与无符号整形进行比较时的知识点。
C语言中对于整型,是分为有符号和无符号(unsigned)的。
- 有符号:最高位的二进制为符号位,正数为0,负数为1。
- 无符号:最高位的二进制不作为符号位。因此也没有正负之分。
当有符号的整形x与无符号整形y进行比较时,C语言会对x进行自动转化,转化为无符号。当x变为无符号时,那高位的1不再表示符号位,因此-1会表示一个很大的数,二进制位变为了全1,接近
UINT_MAX,因此x总是比y大的。
题目五十三:
已知有如下各变量的类型说明,则以下不符合C语言语法的表达式是( )
int k, a, b; unsigned int w = 5; double x = 1.42;
A:x%3
B:w+=-20
C:k=(a=200,b=300)
D:a+=a-=a=9
选择A。
题解:
A选项,取余操作两边必须是整数
题目五十四:
下面函数的输出结果是( )
void func() { int k = 1^(1 << 31 >> 31); printf("%d\n", k); }
A:0
B:-1
C:-2
D:1
选择C。
题解:
本题考察移位操作符和异或操作符。
首先对()里的移位操作进行计算,从左到右开始,对1进行左移,右边补0,因此二进制位会变为高位1剩余31位均为0,变为负数。接着对该数进行右移,采用算数右移,低位舍弃,高位补符号位,即1,最后得到一个32个1的二进制。最后该数与1进行异或操作,异或:相同为0,相异为1。最后为-2
题目五十五:
如下代码的输出结果是( )
A:1
B:4
C:2
D:8
#include <stdio.h>
int main()
{
int i = 1;
sizeof(i++);
printf("%d\n", i);
return 0;
}
选择A。
题解:
本题主要考察sizeof运算符的执行时机。
在C语言中,sizeof为一个单目操作符,用于求类型的大小,单位是字节。题目中的代码i++,在一般的表达式中,先使用后++, 会进行+1操作,但这是在运行阶段才会生效。sizeof是在编译阶段运行的,因此i++不会生效,最后结果仍为1。
题目五十六:
请阅读以下程序,其运行结果是( )
int main() { char c='A'; if('0'<=c<='9') printf("YES"); else printf("NO"); return 0; }
A: YES
B: NO
C: YESNO
D: 语句错误
选择A。
题解:
本题考察条件判断语句中,出现范围判断的知识点。
在C语言中,想对一个变量判断是否在某个范围中,需要分别写最小边界值和最大边界值,并且用逻辑与操作符隔开。题目中 '0' <= c <= 'A'这种写法是错误的,这是数学中理解的写法,在C语言中,需:'0'<= c && c<='A'。
题目五十七:
假设编译器规定 int 和 short 类型长度分别为32位和16位,若有下列C语言语句,则 y 的机器数为( )
unsigned short x = 65530; unsigned int y = x;
A: 0000 7FFA
B: 0000 FFFA
C: FFFF 7FFA
D: FFFF FFFA
选择B。
题解:
本题考察无符号整型提升和隐式转换知识点。
x转为十六进制形式为0xFFFA。当x赋值给y时,x会进形整形提升,对于无符号情况,高位会补0,最后赋值给y,因此最后结果为B。
题目五十八:
下列程序的输出结果是什么( )
#include<stdio.h> int main() { int n = 1001; int ans = 0; for(int i = 1; i <= n; ++i) { ans ^= i % 3; } printf("%d",ans); return 0; }
A: -2
B: 0
C: 1
D: 2
选择B。
题解:
i % 3 的值按1、2、0循环,可推算出ans按1、3、3、2、0、0循环,循环进行1001次,而1001%6=5,也就是ans按规律得 到的第5个数为最终结果,故ans=0
题目五十九:
C 语言中,下列运算符优先级最高的是 ( )
A: !
B: %
C: >>
D: ==
选择A。
题解:
单目运算符的优先级通常都比较高,具体情况可查阅运算符优先级表格,参考文章:【C语言】万字详讲操作符-CSDN博客
题目六十:
要使 a 的低四位翻转,需要进行操作是( )
A: a|0xF
B: a&0xF
C: a^0xF
D: ~a
选择C。
题解:
本题主要考察按位操作符相关知识点。
- 按位与(&):对二进制进行操作,一个为0均为0,两个为1才为1.
- 按位或(|):对二进制进行操作,一个为1均为1,两个为0才为0.
- 按位异或(^):对二进制进行操作,相同为0,相异为1.
- 按位取反(~):0变1,1变0.
本题要对a的低四位进行翻转,其它位不变,那只有进行按位异或才能完成,因为0xF的二进制位1111,因此当相同时为0,不同时为1,就能实现翻转,其它位也不被影响。
题目六十一:
如果 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
选择C。
题解:
本题代码的作用是对整型中0的个数进行统计,x=x|(x+1);的作用是每次循环把x的二进制中从右往左数的最后一位0变成1,直道变 成全1的时候x+1就溢出为全0,循环结束。2014的二进制是0000 0000 000 0000 0000 0111 1101 1110,所以结果是 23.
题目六十二:
下列语句定义 x 为指向 int 类型变量 a 的指针,其中哪一个是正确的( )
A: int a , *x = a;
B: int a , *x = &a;
C: int *x = &a , a;
D: int a , x = a;
选择B。
题解:
本题考察指针相关知识点。
- 选项A错误。指针变量x需要接收一个地址,必须对a进行&操作。
- 选项B正确。对a进行&操作后,赋值给指针变量x。
- 选项C错误。属于先使用后声明,这是不允许的。
- 选项D错误。x不是指针变量。
题目六十三:
下面有关空指针和未初始化指针,说法错误的是( )
A: 对0x0这个地址取值是非法的
B: 空指针可以确保不指向任何对象或函数; 而未初始化指针则可能指向任何地方
C: 空指针与任何对象或函数的指针值都不相等
D: malloc在其内存分配失败时返回的是一个未初始化的指针
选择D。
题解:
- 选项A正确。
- 选项B正确。当给指针变量进行初始化时,如果没有明确的指向,可以置为空指针的形式,即NULL,空指针不指向任何对象和函数。但未初始化的指针,会随机指向任何地方。
- 选项C正确。空指针不指向任何地方,因此也不会相等。
- 选项D错误。malloc动态开辟空间失败后,会返回NULL,即空指针。
题目六十四:
若有定义 int a[8]; ,则以下表达式中不能代表数组元素 a[1] 的地址的是( )
A: &a[0]+1
B: &a[1]
C: &a[0]++
D: a+1
选择C。
题解:
- 选项A正确。地址+1操作,可以跳过该类型的空间,指向下一块空间,这里先得到了首元素地址,进+1,那就指向了第二个元素地址。
- 选项B正确。&a[1]指向第二个元素地址。
- 选项C错误。根据操作符的优先级,a[0]会先与++进行结合,因此对一个表达式&,这是错误的。
- 选项D正确。a表示首元素地址,+1就是指向第二个元素地址。
题目六十五:
以下选项中,对基本类型相同的两个指针变量不能进行运算的运算符是( )
A: +
B: -
C: =
D: ==
选择A。
题解:
- 选项A正确。两个指针变量,那就是两个地址,当两个地址相加时,可能会溢出,因此错误。
- 选项B错误。指针进行相减操作,其实就是地址进行相减,这是允许的,通常会用来求两个数据地址相隔的元素个数。
- 选项C错误。指针接收地址,因此赋值是可以的。
- 选项C错误。==,对两个指针的地址进行判断是否相等。
题目六十六:
有以下函数,该函数的功能是( )
int fun(char *s) { char *t = s; while(*t++); return(t-s); }
A: 比较两个字符的大小
B: 计算s所指字符串占用内存字节的个数
C: 计算s所指字符串的长度
D: 将s所指字符串复制到字符串t中
选择B。
题解:
本题主要考察指针的运用。
在该代码中,循环在*t为0时停止,同时t++,t最后会停在字符串结束标志'\0'之后的一个位置,t作为尾部指针减去头部指针,其实是对地址进行相减,因此是计算s指向字符串中占用内存的字节数,包括\0在内。而C选项为字符串长度,但字符串长度是不包括\0的。
题目六十七:
若有“ float a[3]={1.5,2.5,3.5},*pa=a;*(pa++)*=3; ”,则 *pa 的值是( )
A: 1.5
B: 2.5
C: 3.5
D: 4.5
选择B。
题解:
在*pa=a中指针pa指向a[0];pa++返回值仍是操作之前的值;*(pa++)取pa指向的地址的值;*(pa++)*=3将该值变为原来 的3倍,也就是数组a的第一个值为4.5;由于pa++之后pa指针移动了sizeof(float)个字节,所以pa指向a[1],所以值为 2.5。
题目六十八:
以下程序运行后的输出结果是( )
#include <stdio.h> int main() { int a[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}, *p = a + 5, *q = NULL; *q = *(p+5); printf("%d %d\n", *p, *q); return 0; }
A: 运行后报错
B: 6 6
C: 6 11
D: 5 10
选择A。
题解:
题目最后询问指针p和q的指向的值,指针q初始化为NULL,接着又解引用指针q,是错误的,对NULL指针是不能解引用的。当创建指针时,如果不知道初始化什么,可以置为空指针,但是,C语言是不允许对空指针进行解引用操作的。这属于野指针的范畴,只能对该指针的指向进行改变后,再进行解引用操作。
题目六十九:
设有定义 char *p[]={"Shanghai","Beijing","Honkong"}; 则结果为 j 字符的表达式是( )
A: *p[1] +3
B: *(p[1] +3)
C: *(p[3] +1)
D: p[3][1]
选择B。
题解:
本题主要考查对指针的运算操作。
对一个指针进行加法操作,将改变指针的指向。B选项,p是个char*类型的数组,p[1]拿到字符串"beijing"的首地址,再加3便是'j'的地址,解地址拿到'j'
题目七十:
以下叙述中正确的是( )
A: 即使不进行强制类型转换,在进行指针赋值运算时,指针变量的基类型也可以不同
B: 如果企图通过一个空指针来访问一个存储单元,将会得到一个出错信息
C: 设变量p是一个指针变量,则语句p=0;是非法的,应该使用p=NULL;
D: 指针变量之间不能用关系运算符进行比较
选择B。
题解:
- 选项A错误。不同类型指针一般不可以直接赋值操作。
- 选项B正确。对空指针进行解引用操作,该指针会变成一个野指针,这是不允许的。
- 选项C错误。p=NULL;和p=0;是等价的;
- 选项D错误。指向同一数组的两指针变量进行关系运算可表示它们所指数组元素之间的位置关系。
题目七十一:
有如下代码,则*(p[0]+1)所代表的数组元素是( )
int a[3][2] = {1, 2, 3, 4, 5, 6}, *p[3]; p[0] = a[1];
A:a[0][1]
B:a[1][0]
C:a[1][1]
D:a[1][2]
选择C。
题解:
代码中有两个值,a是一个二维数组,p是一个指针数组。在C语言中,a[1]表示第二行的首元素地址,即a[1][0],因此p[0]存储着a[1][0]元素地址,进行+1后,那就是跳过1个元素大小的空间,即指向a[1][1],那C选项符合。
题目七十二:
关于指针下列说法正确的是【多选】( )
A:任何指针都可以转化为void *
B:void *可以转化为任何指针
C: 指针的大小为8个字节
D: 指针虽然高效、灵活但可能不安全
选择ABD。
题解:
- 选项A正确。void* 是一个通用类型,任何类型的指针,都可以通过强转为void*
- 选项B正确。同样的,void*表示无类型的指针,因此可以强转为任何类型的指针。
- 选项C错误。指针的大小为4/8字节,在32位平台总,大小是4字节,在64平台中,大小为8字节。
- 选项D正确。指针是存储地址的,可以通过操作地址,来改变值,非常灵活,但也非常不安全,因为可能会有野指针的情况出现。如非法访问等。
题目七十三:
以下 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);
选择D。
题解:
该题考察的是通过scanf函数的调用对结构体数据类型进行初始化。scanf("输入控制符", 输入参数);功能:将从键盘输入 的字符转化为“输入控制符”所规定格式的数据,然后存入以输入参数的值为地址的变量中。scanf输入时要通过地址找空间, B、C用了&是正确的。name属于字符数组的数组名,相当于数组的首地址,A正确。单独的pa->age可用于输出语句获取值的 形式,用在scanf中的时候需要&操作符,D错误
题目七十四:
如下函数 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++)行处设置断点,然后单步运行,直到发现错误原因
选择A。
题解:
题目说明,当n>12时,计算出的结果不正确。因此需要关注结果,那就是prod *=1 这条语句。因此选择A。
题目七十五:
下列给定程序中,函数 fun 的功能是:把形参a所指数组中的奇数按原顺序依次存放到 a[0]、a[1]、a[2]… 中,把 偶数从数组中删除,奇数个数通过函数值返回。 例如,若a所指数组中的数据最初排列为: 9,1,4,2,3,6,5,8,7 ,删除 偶数后,a所指数组中的数据为: 9,1,3,5,7 ,返回值为5。请在程序的下画线处填入正确的内容并将下画线删除,使 程序得出正确的结果( )
int fun(int a[], int n) { int i, j; j=0; for (i=0; i<n; i++) if (a[i]%2== _________ ) { a[j]=a[i]; _________; } return _________; }
A: 0 j++ j
B: 1 j++ j+1
C: 0 j++ j+1
D: 1 j++ j
选择D。
题解:
本题代码的作用是将数组a中的偶数删除,将奇数从下标0开始存放。第一处下划线填1,因为一个数取余2为1则是奇数。第二处下划线天j++,没什么特别之处,就是将奇数从下标0开始放置,j不断更新。最后一处下划线填j。第二处填j++的作用就能体现出来了,因为是后置++,因此最后的j是比最后一个元素下标多一个的,那就是元素的总个数了。
题目七十六:
指出下列代码的缺陷【多选】( )
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: 没有缺陷
选择BC。
题解:
- 选项A错误。for循环中,是可以省略循环控制条件,只能说在该题代码中,不利于代码的可读性,但不能说什么错误。
- 选项B正确。当浮点型和整型进行比较,这是不允许的,因为整型在内存中是以二进制的形式进行存储,而浮点型的存储方式不是以二进制,因此不能进行进行比较。
- 选项C正确。当i是前置++时,i的值永远不可能为0,因此i要后置++。
- 选项D错误。
题目七十七:
请指出以下程序的错误【多选】( )
void GetMemory(char **p, int num) { if(NULL == p && num <= 0)//1 return; *p = (char*)malloc(num); return; } int main() { char *str = NULL; GetMemory(&str, 80); //2 if(NULL != str) { strcpy(&str, "hello"); //3 printf(str); //4 } return 0; }
A: 1
B: 2
C: 3
D: 4
选择AC。
题解:本题代码想为str开辟一处空间,然后将hello拷贝到str中,但有两处地方错误了。
- 选项A,即1错误。主调函数中将&str和80传参,str本身是一个指针变量,进行取地址操作后,得到的其实是该指针的地址,因此需要用二级指针进行接收。故指针p和变量num只需要一个符合就进行return,不需要两个条件都符合。
- 选项C,即3错误。&str表示指针的地址,而指针的地址,只能存放地址,将hello拷贝到其中,这是错误的。
题目七十八:
请问下列代码的输出结果有可能是哪些【多选】( )
#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
选择AC。
题解:
对于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
题目七十九:
下面这个程序执行后会有什么错误或者效果【多选】( )
#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: 内存泄露
选择AB。
题解:
本题主要考查无符号字符类型的大小区间。
有符号的char类型,大小区间为:-127~128
无符号的char类型,大小区间为:0~255
因此这里的A选项错误。无符号字符型最大空间位255,当i==255时,依然进入循环,进行赋值操作,这属于越界访问了。
B选项也错误。这个是因为无符号字符型的变量大小在 0-255之间,所以说i永远不可能大于255的,是个死循环。
内存泄漏:创建的临时变量,在栈中,应该会由系统自动释放,所 以应该是不存在内存泄漏的问题。栈溢出:属于缓冲区溢出的一种。栈溢出是由于C语言系列没有内置检查机制来确保复制到缓 冲区的数据不得大于缓冲区的大小,因此当这个数据足够大的时候,将会溢出缓冲区的范围
题目八十:
请问下列程序的输出是多少( )
#include<stdio.h> int main() { unsigned char i = 7; int j = 0; for(;i > 0;i -= 3) { ++j; } printf("%d\n", j); return 0; }
A: 2
B: 死循环
C: 173
D: 172
选择C。
题解:
本题就是找规律,计算什么时候能遇到0 unsigned char 8位数据位,范围在0-255,所以-2(11111110)时,变成254;同理-1(11111111)时,变成255;最 后减到0时,不满足循环条件,for停止。刚好173次。 7 4 1 ==> 共(7-1)/3+1=3次 (1-3=-2,即254,继续循环) 254 251 ... 5 2 ==> 共(254-2)/3+1=85次(2-3=-1,即255,继续循环) 255 252 ... 6 3 ==> 共(255-5)/3+1=85次(3-3=0,退出循环) 所以总共173次
关注我,后续有更多干货!!!