c语言每日一练(14)【加强版】

前言:
每日一练系列,每一期都包含5道选择题,2道编程题,博主会尽可能详细地进行讲解,令初学者也能听的清晰。博主有时会将一些难题综合成每日一练加强版,加强版是特殊的,它仅包含5道选择题,但这5道选择题都是博主精挑细选的,希望大家能够认真看看,相信一定能有所收获。每日一练系列会持续更新,上学期间将看学业情况更新。

有学习或者生活方面的问题都可直接私信博主询问,博主看到会回复,太久没回复就扣个1提醒下博主

五道易错选择题: 

1、以下正确的程序段是()
A、char str[20];scanf("%s",&str);

B、char *p;scanf("%s",p);

C、char str[20];scanf("%s",&str[2]);

D、char str[20],*p=str;scanf("%s",p[2]);

解析:选项A,&str得到的是整个数组的地址,也就是说它的权重是整个数组,那么&str+1就会跳过一整个数组进行操作,所以你想使用scanf("%s",&str);来进行字符串的修改会越界,A错误。扩展:有的编译器上面的scanf实现是通过强转成字符然后使用字符的特殊性(一个字符占一个字节的空间,也就是说字符型指针的权重是一个字节)挨个将不同类型的值进行修改实现scanf的。强转成字符型指针时,它的权重就不再重要,所以使用这类scanf函数A选项是没问题的,但这不具备普遍性,所以A可以认为是错误的。

选项B,空间没开辟好,会使用到野指针,有安全隐患,B错误。选项C,&str[2]可写作&*(str+2),&和*号抵消,来到了偏移量为2的地址,也就是说,它可以正常输入17个字符,形成一个长度为18的字符串,C没有犯语法错误,题目并没有要求程序实现的结果,所以C是正确的。

选项D,p是首地址,p[2]是首地址偏移量为2的地址所指向的字符,也就是说p[2]不是地址,它是字符,不符合scanf的使用要求,D错误。综上所述,答案选C

 2、设已有定义:char*st="how are you";下列程序段中正确的是()

A、char a[11],*p;strcpy(p=a+1,&st[4]);
B、char a[11];strcpy(++a,st);
C、char a[11];strcpy(a, st);
D、char a[],*p;strcpy(p=&a[1],st+2):

解析:st是一个数组指针,存放的是字符串how are you的首地址,由于是字符串的形式所以它的最后有个隐藏的,数数就可以知道这个字符串长3+1+3+1+3+1=12。

先看A选项,p=a+1,也就是p为数组首地址的下一个地址,因此p最多拷贝10个字符,而&st[4]可以写作&(*(st+4)),*(st+4)就是how 和 are 中间的空格,再&就是得到这个空格的地址,从这个位置往后数,显然小于10,故成功拷贝,A正确。

B选项,++a,a是地址啊,你怎么能对地址修改呢,B大错特错。C选项,12个字符拷贝进只能存放11个字符的数组,拷贝失败,C错误。

D选项,char a[],定义都定义错误了,想要不写字符数组长度的前提是,你得对它初始化,比方说char a[]="hello world";D选项定义都定义不明白,D错误。综上所述,答案选A

3、若有说明;int*p,m=5,n;以下正确的程序段的是()

A、p=&n;scanf("%d",&p);
B、p=&n;scanf("%d",*p);                                                                                                                  C、scanf("%d",&n);*p=n;
D、p=&n;*p=m;

解析:先分析代码,int*p,m=5,n;分别定义了一个指针变量p和两个整型变量m,n,其中m被初始化为5。

接着先看A选项,p=&n,也就是说p现在储存的是n的地址,然后再scanf("%d",&p);&p相当于对n的地址再取地址,因此scanf操作的是n的地址,它会将n的地址进行修改,但这显然错误,因为地址是不可被修改的,故A错误。

B选项,scanf("%d",*p);p是n的地址,*p即是n,你scanf("%d",n);没有取地址,无法进行值的修改,B错误。C选项,scanf("%d",&n);这一步没有问题,简单的修改n变量的值,*p=n就很有问题,因为你p并没有初始化为空指针,所以此时p是一个野指针,你对野指针解引用并赋值会造成不可预知的后果,所以C错误。

D选项,先是令p=&n;也就是说,p现在存有n的地址,你再解引用p对p地址所指向的值修改就相当于对n进行修改,并没有语法上的错误,D正确。综上所述,答案选D 

4、以下程序段中,输出信息不能正确反映变量大小关系的是()
A、

if (x > y) printf(" x > y ");//1
if (x < y) printf("x < y ");//2
else printf(" x = y ");//3

A选项解析: 根据if,else的就近匹配原则,代码2和代码3匹配,我们可以先假设x>y走一遍,当x>y时,执行代码1,但走到代码2时会因为else走先代码3,所以它会同时打印出x>y和x=y,因此A不能正确反映变量大小关系。

B、

if (x >= y)//1
if (x > y) printf("x > y");//2
else printf("x = y");//3
else printf("x < y");//4

B选项解析: 先就近原则判断,得出:1和4匹配,2和3匹配。那么当x>y时,先进入代码1,满足条件,进入代码1下的if判定,再判定,满足条件,进入代码2,打印x>y,正确。当x=y时,满足1,进入1下的判定,不满足,走到代码3,打印x=y,正确。当x<y时,代码1不满足,直接走到代码4,打印x<y,正确。综上所述,可以正确反映变量的大小关系。

C、

if (x > y) printf(" x > y ");//1
if (y > x) printf(" x < y ");//2
if (x == y) printf(" x = y ");//3

C选项解析:当x>y直接打印x>y,正确。当x=y时,x>y和y>x均不满足条件,均不打印对应内容,走到代码3打印x=y,正确。x<y同理。综上所述,可以正确反映变量的大小关系。 

D、

if (x > y) printf(" x > y ");//1
else if (x < y) printf(" x < y ");//2
else printf(" x = y ");//3

 D选项解析:观察代码,1和2匹配,2和3匹配。当x>y时,走1打印x>y,后面的else if不执行,再下面的else是和2的if匹配的,自然也不执行。当x=y时,走1判定为假,走2,判定为假,走到3,打印x=y,正确。当x<y时,走1判定为假,走2,判定为真,打印x<y,后面的else不执行,正确。综上所述,可以正确反映变量的大小关系。

根据上述,得答案为A 

 看到这里的友友相信已经有点疲劳了,我们就最后来道简单点的题。

5、有以下程序,程序运行时输入:-1 -2 0 1 2 <回车>,则输出结果是()

#include <stdio.h>
int main()
{
	int x, a = 1, b = 1;
	while (1)
	{
		scanf("%d", &x);
		if (x > 0) { a *= x; break; }//1
		if (x < 0) { b *= x; continue; }//2
		printf("%d,%dn", a, b);
	}
}

A、2,2
B、1,2
C、-1,1
D、-2,1 

解析:观察代码可以发现,这是个死循环。当x>0时会跳出循环,当x<0时循环会强制继续,这两种情况都走不到printf,只有当x=0时才会打印出a和b,输入-1 -2 0 1 2<回车>,就相当于在数据流中存放了-1,空格,-2,空格,0,空格,1,空格,2,空格。而scanf会将空格当作结束标志,也就是说如果循环正常运行,x将被依次赋予为-1,-2,0,1,2 。

当x=1时,走代码2,令b*=1,所以b=-1。当x=-2时,走代码2,令b*=x,所以b=2。当x=0时,直接打印出a,b,此时a=1,b=2,所以打印出1,2。而当x=1时会走到代码1跳出循环,后面的2依然存放在数据流中,不会赋值给x,当程序结束之后会被清除,对于此题并无影响。至此,程序结束,最终输出1,2,答案选B

好了,今天的练习到这里就结束了,感谢各位友友的来访,祝各位友友前程似锦O(∩_∩)O