C语言笔记:如何优雅的输入?(一)
在刚接触C语言的时候,也许你遇到过这样的问题:
你终于敲完你的第一个代码:
int main(void)
{
printf("Hello World!\n");
return 0;
}
你点了编译,没有任何问题。
但当你关掉编译器,去双击打开那个你自己创造出来的.exe文件时,窗口一闪而过。你还来不及看到:Hello World!
这是为什么呢?
如果你够聪明,你会上网查找原因。或者你的书上写着这样一段话:
C Primer Plus 第六版 中文版
于是你在你的代码中加了这段话,总算可以运行了。
接着,你学到了scanf()语句,你学会了通过输入数值来控制变量。
int main(void)
{
int x;
scanf("%d", &x);
printf("x = %d\n", x);
return 0;
}
就像上面这个代码一样。
但你又发现,在.exe文件中,就算你加了getchar(),在你输入数值后,屏幕依然一扫而过。
这时候你只好又查找相关资料,发现了这样一段话:
C Primer Plus 第六版 中文版
资料告诉你,要加两次getchar()
(如果你从来没有遇到过这种问题,只能说明你没有打开过.exe文件,或者你是在控制台运行的程序。)
那个时候你还不知道getchar是什么,但隐隐约约你会知道,getchar跟字符有关系。
本期推送,我将给大家介绍getchar的正确用法。
如果你英文够好的话,你就会知道getchar的英文意思是获取字符。
从谁哪里获取字符呢?
键盘。
既然获取的是字符,也就说明一次只能获取一个。或者是字母,或者是数字,或者是一些其他的键盘上的按键,例如:空格,回车,ESC……
在上面Hello World!程序中,如果不加getchar, ./exe程序执行完printf()函数以后,立马return 0。也就是不会停下来等你。
所以我们加一个gecthar(),等待用户键盘输入一个字符。在这里getchar起到了一个暂停的作用。
后来的有关scanf的程序中,请回想你究竟输入了什么?
如果你想让x等于214,你输入的就一定是:2 1 4 [回车]
如果你只输入214,键盘还会等待你继续输入的,所以你必须要输入一个回车按键。
于是,你的214传给了x, 但是你的回车传给了getchar()。毕竟回车也算一个字符。
所以,想让程序暂停下来,你就必须输入两个回车,否则程序自动return 0;
既然我们可以输入字符,能不能输出字符呢?
就像我们有scanf做输入,我们也有printf做输出。
有的,输出字符的函数叫作:putchar()
puthcar()和getchar不一样,putchar()必须有参数,输出的字符就是这个参数。
int main(void)
{
putchar('s');
return 0;
}
这样就可以输出一个字符s
那如何让getchar和putchar搭配使用呢?
int main(void)
{
char a;
a = getchar();
putchar(a);
return 0;
}
getchar()的返回值就是从键盘输入的值。所以我们可以声明一个字符型变量a,让a等于getchar的值。随后我们通过putchar来输出这个字符。
可是一次只能输入一个字符很不过瘾啊,能不能通过getchar()和putchar()输出很多东西呢?
int main(void)
{
char a;
while (a=getchar()) {
putchar(a);
}
return 0;
}
如果我们给原来的程序添加一个循环,我们这么做,就可以输入输出很长的一段话。
可这是为什么呢?
这是因为从键盘输入的字符会被放在一个叫作缓冲区的地方,使用的时候会对它挨个取出来。
上面scanf的例子也是如此。
这个程序怎么结束了?
[CTRL] + [Z]
我们还可以利用getchar做更多事情。
比如,我们要做一个猜数的小程序。
int main(void)
{
int guess = 1;
printf("这是一个非常简陋的猜数游戏\n");
printf("请你心里想一个数\n");
printf("如果我猜对了,你就打y, 如果我猜错了,你就打n\n");
printf("这个数字是:%d 吗?\n", guess);
while (getchar() != 'y') {
guess += 1;
printf("这个数字是:%d 吗?\n", guess);
}
printf("我真厉害。\n");
return 0;
}
这是一个非常简陋的猜数游戏。我们运行一下试试:
发现了吗,程序出现了问题,每当我们输入n,都会越过一个判断下一个。
聪明的你,想到问题出在哪里了吗?
问题就出在,当我们输入了 n 以后,我们还按了一次回车,所在在缓冲区中还有一个回车没有处理。
但问题不仅仅在回车,这个问题比想象中要严重很多。
如果我们忽略了缓冲区,下场就是这样。
所以我们每次判断完,要清理一次缓冲区的东西。
怎么清理呢?
还记得我们在讲循环时,提到的continue吗?
int main(void)
{
int guess = 1;
printf("这是一个非常简陋的猜数游戏\n");
printf("请你心里想一个数\n");
printf("如果我猜对了,你就打y, 如果我猜错了,你就打n\n");
printf("这个数字是:%d 吗?\n", guess);
while (getchar() != 'y') {
guess += 1;
printf("这个数字是:%d 吗?\n", guess);
while (getchar() != '\n')
continue;
}
printf("我真厉害。\n");
return 0;
}
我们在程序的第14行添加一个循环,这个循环如果在缓冲区寻找下一位,如果不是回车,就继续执行循环,如果时回车就跳出循环,到下一次等待键盘的输入。
我们通过这个方法,就可以做到清理缓冲区中余下的东西。
其实运行的结果还是有一些问题。我们说的是猜数输入n,但输入了It's not
程序依然判断不是,等到遇到了y才是。
所以我们还要对程序进行改进,要判断字符是否为n。
如果不是,就输出:我读不懂。
int main(void)
{
int guess = 1;
char a;
printf("这是一个非常简陋的猜数游戏\n");
printf("请你心里想一个数\n");
printf("如果我猜对了,你就打y, 如果我猜错了,你就打n\n");
printf("这个数字是:%d 吗?\n", guess);
while ((a = getchar()) != 'y') {
if (a == 'n'){
guess += 1;
printf("这个数字是:%d 吗?\n", guess);
}
else
printf("我读不懂!\n");
while (getchar() != '\n')
continue;
}
printf("我真厉害。\n");
return 0;
}
所以我们再在原程序中添加一个if-else
这样我们的程序总算是没有问题了。
在以后的推送中,我们不仅仅要认识这getchar和putchar,实际上还有很多问题等着我们。
我们下期再见!
拜拜。