文章目录
这个问题转载自n_s_X14,但是作者在文章最后留了一个问题,现在在这里给大家解释一下原因。
文章的源码为:
#include <stdio.h>
int main(void){
char m[40];
char n;
printf("please input first str:\n"); //提示用户输入第一个字符串
scanf("%s",m); //获取用户第一个输入字符串
printf("you input str is :%s\n",m); //输出用户的输入的第一个字符串
printf("input second char :\n"); //提示用户输入第二个字符
scanf("%c",&n); //获取用户的第二个字符
printf("now you input second char is :%c\n",n);//输出用户输入的第二个字符
return 0;
}
Output:
please input first str:
abc
you input str is :abc
input second char :
now you input second char is :
Program ended with exit code: 0
问题:我们第一次输入abc后成功打印出来了you input str is :abc
,但是执行到printf("input second char :\n");
时,还没等到第二次输入就打印出来了。这是为什么??
原因:
其实在我们第一次输入并按下回车的时候,控制台一共获得了四个字符,分别是:a、b、c、回车(enter)。但是因为scanf()方法遇到非字符的时候会结束从控制台的获取,所以在输入’abc’后,按下 ‘回车(enter)’ 的同时,将’abc’这个值以字符串的形式赋值给了类型为 ‘char’ 的 ‘m’ 数组,将使用过后的字符串: ‘回车(enter)’ 保存在控制台输入的缓冲区,然后继续执行下一段输出代码,然后又要求用户输入。此时,因为上一次被使用过后的字符串被保存在缓冲区,现在scanf()方法从控制台的缓冲区获取上一次被使用过后的字符串,并只截取第一个字符: ‘回车(enter)’ ,此时控制台缓冲区才算使用完了。所以在看似被跳过的输入,其实已经scanf()方法已经获取了我们的输入了,这个输入就是一个 ‘回车(enter)’ 。
解决问题: 使用getchar()方法,清除掉abc后面的缓存(回车enter)。
#include <stdio.h>
int main(void){
char m[40];
char n;
printf("please input first str:\n"); //提示用户输入第一个字符串
scanf("%s",m); //获取用户第一个输入字符串
printf("you input str is :%s\n",m); //输出用户的输入的第一个字符串
getchar();
printf("input second char :\n"); //提示用户输入第二个字符
scanf("%c",&n); //获取用户的第二个字符
printf("now you input second char is :%c\n",n);//输出用户输入的第二个字符
return 0;
}
Output:
please input first str:
abc
you input str is :abc
input second char :
de
now you input second char is :d
Program ended with exit code: 0
文章结束时留了一个问题:如果在第一次输入ab后加一个空格再回车,又会出现原来的问题,即程序只输出了ab后就自动跳过下一次的输入之间退出了,控制台输出如下图所示。
原因:
scanf("%s",&m);
,我们用%s作为转换说明,%s的作用是“把输入解释成字符串。从第一个非空白字符开始,到下一个空白字符之前的所有字符都是输入。”所以scanf把输入的ab空格+回车
就理解为ab+回车
(ab后面没有空格),但是依然以ab空格+回车
的形式存储在缓存区。ab空格+回车
,在缓存区是这样存放的:
其中,第三格存放的为空格键。
当程序运行完 getchar();
后,只清除了第三格中的空格键,因为一次执行getchar();
只清除一个缓存,留下了第四格中的回车键,因此再次出现了同样的问题。
解决问题:那么就是说只要运行两次getchar();
,清除掉第三格和第四格就可以正常了。
#include <stdio.h>
int main(void){
char m[40];
char n;
printf("please input first str:\n"); //提示用户输入第一个字符串
scanf("%s",m); //获取用户第一个输入字符串
printf("you input str is :%s\n",m); //输出用户的输入的第一个字符串
getchar(); //第一次清除缓存
getchar(); //第二次清除缓存
printf("input second char :\n"); //提示用户输入第二个字符
scanf("%c",&n); //获取用户的第二个字符
printf("now you input second char is :%c\n",n);//输出用户输入的第二个字符
return 0;
}
Output:
由此可见,当我们第一次输入ab空格+回车后,程序正常运行。
进一步:如果我们输入的是a空格b+回车
,scanf("%s",m);
这一步只能读取到a,因为a后面有空格。但是a空格b+回车
在缓冲区这样存放:
因此,如果想要程序正常运行则需要在输出用户的输入的第一个字符串后加入三次getchar();
操作,即删除掉第二,第三,第四格的内容。
问题:如果我们输入a空格bbbbbbbb+回车
,那可能需要无数个getchar();
来清除缓存,这时应该怎么办??
解决方法:加入while循环while(getchar()!='\n') continue;
#include <stdio.h>
int main(void){
char m[40];
char n;
printf("please input first str:\n"); //提示用户输入第一个字符串
scanf("%s",m); //获取用户第一个输入字符串
printf("you input str is :%s\n",m); //输出用户的输入的第一个字符串
while(getchar()!='\n') //通过while循环删除缓存
continue;
printf("input second char :\n"); //提示用户输入第二个字符
scanf("%c",&n); //获取用户的第二个字符
printf("now you input second char is :%c\n",n);//输出用户输入的第二个字符
return 0;
}
这时,我们输入a空格bbbbbbbb+回车
,程序正常运行。
解析:
while(getchar()!='\n')
continue;
可以看出这段代码代替了无数个getchar(),他的作用是跳过剩余的输入行
第一次while循环消除第二格缓存,第二次while循环消除第三格缓存……直到第八次。最后一次同样,getchar()也消除了回车。
while(getchar()!='\n')
可以拆分成两步,
getchar()
方法(这里getchar();只是取得了’\n’但是并没有赋给任何字符变量,所以不会有影响,相当于清除了这个字符)。假设程序要求用getchar()处理字符输入,用scanf()处理数值输入,这两个函数都能很好的完成任务,但是不能混合使用。 因为getchar()读取每个字符,包括空格、制表符和换行符;而scanf()在读取数字时则会跳过空格、制表符和换行符。
例: 要求用户输入一个字母和两个数字,输出以第一个数字为行数,第二个数字为列数,以字母为内容的数列,要求可以不断输入直至键入回车退出程序:
#include <stdio.h>
void display(char cr,int lines,int width);
int main(int argc, const char * argv[]) {
int ch;
int rows,cols;
printf("Enter a character and two integers:\n");
while((ch=getchar())!= '\n'){
scanf("%d %d", &rows,&cols);
display(ch, rows, cols);
printf("Enter another character and two integers;\n");
printf("Enter a newline to quit.\n");
}
printf("Bye.\n");
return 0;
}
void display(char cr,int lines,int width){
int row,col;
for(row=1; row<= lines; row++){
for(col =1; col<=width; col++){
putchar(cr);
}
putchar('\n');
}
}
output:
我们发现,在第一次输入成功打印后,程序自动退出。这明显不符合我们的题目要求。
原因是,输入的c23其实是c23+换行符
,scanf()函数把这个换行符留在了缓存中。getchar()不会跳过换行符,所以在进入下一轮迭代时,还没来得及输入字符,它就读取了换行符,然后将其赋值给了ch。而ch是换行符正式终止循环的条件。
如何改进??
#include <stdio.h>
void display(char cr,int lines,int width);
int main(int argc, const char * argv[]) {
int ch;
int rows,cols;
printf("Enter a character and two integers:\n");
while((ch=getchar())!= '\n'){
if( scanf("%d %d", &rows,&cols)!=2 ){
break;
}
display(ch, rows, cols);
while(getchar()!='\n'){
continue;
}
printf("Enter another character and two integers;\n");
printf("Enter a newline to quit.\n");
}
printf("Bye.\n");
return 0;
}
void display(char cr,int lines,int width){
int row,col;
for(row=1; row<= lines; row++){
for(col =1; col<=width; col++){
putchar(cr);
}
putchar('\n');
}
}
Output:
题外话:
scanf()中转化符的问题
问题:从上面两张图片中可以看出,当scanf("%d",&c);
改为scanf("%c",&c);
时,控制台中出现了图二的问题。character为什么为空白??
原因: 如果格式是%c,那么任何字符都是它想要的,所以第二个程序中的第二个scanf(“%c”)会得到‘+’后面的空格’ ‘。如果格式是%d,则会忽略任何空白字符(空格、回车、制表符等),忽略的意思是,从缓冲区里删除,但并不保存;如果遇到数字,则拿出并保存给后面的整数,也就是说%d的时候,scanf想要的字符是数字和空白符。所以第一个程序里的第二个scanf(“%d”)忽略掉了空格,正确输入了数字。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/180329.html原文链接:https://javaforall.cn