vlambda博客
学习文章列表

C语言笔记:如何优雅的输入?(一)



在刚接触C语言的时候,也许你遇到过这样的问题:


你终于敲完你的第一个代码:

#include <stdio.h>
int main(void){ printf("Hello World!\n");
return 0;}

你点了编译,没有任何问题。


但当你关掉编译器,去双击打开那个你自己创造出来的.exe文件时,窗口一闪而过。你还来不及看到:Hello World!

这是为什么呢?


如果你够聪明,你会上网查找原因。或者你的书上写着这样一段话:

C语言笔记:如何优雅的输入?(一)

C Primer Plus 第六版 中文版

于是你在你的代码中加了这段话,总算可以运行了。


接着,你学到了scanf()语句,你学会了通过输入数值来控制变量。

#include <stdio.h>
int main(void){ int x;
scanf("%d", &x); printf("x = %d\n", x);
return 0;}

就像上面这个代码一样。


但你又发现,在.exe文件中,就算你加了getchar(),在你输入数值后,屏幕依然一扫而过。


这时候你只好又查找相关资料,发现了这样一段话:

C语言笔记:如何优雅的输入?(一)

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()必须有参数,输出的字符就是这个参数。

#include <stdio.h>
int main(void){ putchar('s');
return 0;}

这样就可以输出一个字符s


那如何让getchar和putchar搭配使用呢?

#include <stdio.h>
int main(void){ char a;
a = getchar(); putchar(a);
return 0;}


getchar()的返回值就是从键盘输入的值。所以我们可以声明一个字符型变量a,让a等于getchar的值。随后我们通过putchar来输出这个字符。


可是一次只能输入一个字符很不过瘾啊,能不能通过getchar()和putchar()输出很多东西呢?

#include <stdio.h>
int main(void){ char a;
while (a=getchar()) { putchar(a); }
return 0;}


如果我们给原来的程序添加一个循环,我们这么做,就可以输入输出很长的一段话。


可这是为什么呢?


这是因为从键盘输入的字符会被放在一个叫作缓冲区的地方,使用的时候会对它挨个取出来。


上面scanf的例子也是如此。


这个程序怎么结束了?

[CTRL] + [Z]




我们还可以利用getchar做更多事情。

比如,我们要做一个猜数的小程序。


#include <stdio.h>
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;}


这是一个非常简陋的猜数游戏。我们运行一下试试:

C语言笔记:如何优雅的输入?(一)


发现了吗,程序出现了问题,每当我们输入n,都会越过一个判断下一个。


聪明的你,想到问题出在哪里了吗?


问题就出在,当我们输入了 n 以后,我们还按了一次回车,所在在缓冲区中还有一个回车没有处理。


但问题不仅仅在回车,这个问题比想象中要严重很多。

C语言笔记:如何优雅的输入?(一)


如果我们忽略了缓冲区,下场就是这样。

所以我们每次判断完,要清理一次缓冲区的东西。


怎么清理呢?

还记得我们在讲循环时,提到的continue吗?

#include <stdio.h>
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。

如果不是,就输出:我读不懂。

#include <stdio.h>
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,实际上还有很多问题等着我们。


我们下期再见!

拜拜。