深入了解scanf()/getchar()/gets()/getch,getche sunysl的专栏 博客频道 CSDN.NET

深入了解scanf()/getchar()/gets()/getch,getche - sunysl的专栏 - 博客频道 - CSDN.NET

深入了解scanf()/getchar()/gets()/getch,getche


1人阅读
评论(0)
收藏
举报

----------------------------------------------------
| 问题描述一:(分析scanf()和getchar()读取字符) |
----------------------------------------------------
scanf(), getchar()等都是标准输入函数,一般人都会觉得这几个函数非常简单,没什么特殊的。但是有时候却就是因为使用这些函数除了问题,却找不出其中的原因。下面先看一个很简单的程序:
程序1:
#include <stdio.h>
int main()
{
char ch1, ch2;
scanf("%c", &ch1);
scanf("%c", &ch2);
printf("%d %d/n", ch1, ch2);
return 0;
}
或者是:
#include <stdio.h>
int main()
{
char ch1, ch2;
ch1 = getchar();
ch2 = getchar();
printf("%d %d/n", ch1, ch2);
return 0;
}
程序的本意很简单,就是从键盘读入两个字符,然后打印出这两个字符的ASCII码值。可是执行程序后会发现除了问题:当从键盘输入一个字符后,就打印出了结果,根本就没有输入第二个字符程序就结束了。例如用户输入字符'a', 打印结果是97,10。这是为什么呢?
【分析】:
首先我们呢看一下输入操作的原理,程序的输入都建有一个缓冲区,即输入缓冲区。一次输入过程是这样的,当一次键盘输入结束时会将输入的数据存入输入缓冲 区,而cin函数直接从输入缓冲区中取数据。正因为cin函数是直接从缓冲区取数据的,所以有时候当缓冲区中有残留数据时,cin函数会直接取得这些残留 数据而不会请求键盘输入,这就是例子中为什么会出现输入语句失效的原因!
其实这里的10恰好是回车符!这是因为scanf()和getchar()函数是从输入流缓冲区中读取值的,而并非从键盘(也就是终端)缓冲区读取。而读 取时遇到回车(/n)而结束的,这个/n会一起读入输入流缓冲区的,所以第一次接受输入时取走字符后会留下字符/n,这样第二次的读入函数直接从缓冲区中 把/n取走了,显然读取成功了,所以不会再从终端读取!这就是为什么这个程序只执行了一次输入操作就结束的原因!

----------------------------------------------------
| 问题描述二:(分析scanf()和gets()读取字符串) |
----------------------------------------------------

首先我们看一下scanf()读取字符串的问题:
程序2:
#include <stdio.h>
int main()
{
char str1[20], str2[20];
scanf("%s",str1);
printf("%s/n",str1);
scanf("%s",str2);
printf("%s/n",str2);
return 0;
}
程序的功能是读入一个字符串输出,在读入一个字符串输出。可我们会发现输入的字符串中不能出现空格,例如:
测试一输入:
Hello world!
输出:
Hello
world!
【分析】到此程序执行完毕,不会执行第二次的读取操作!这个问题的原因跟问题一类似,第一次输入Hello world!后,字符串Hello world!都会被读到输入缓冲区中,而scanf()函数取数据是遇到回车、空格、TAB就会停止,也就是第一个scanf()会取出"Hello",而"world!"还在缓冲区中,这样第二个scanf会直接取出这些数据,而不会等待从终端输入。

测试二:
Hello[Enter]
Hello[输出]
world[Enter]
world[输出]
【分析】程序执行了两次从键盘读入字符串,说明第一次输入结束时的回车符被丢弃!即:scanf()读取字符串会舍弃最后的回车符!


我们再看一下gets()读取字符串的情况:
scanf来读取一个字符串时,字符串中是不可以出现空格的,一旦出现空格,后面的数据就会舍弃残留在缓冲区中。其实有另外一个函数是可以接受空格的,那就是gets(),下面我们看一下这个函数的应用,我们把程序2改动一下:
程序3:
#include <stdio.h>
int main()
{
char str1[20], str2[20];
gets(str1);
printf("%s/n",str1);
gets(str2);
printf("%s/n",str2);
return 0;
}
测试:
Hello world! [输入]
Hello world! [输出]
12345 [输入]
12345 [输出]
【分析】显然上一个程序的执行情况不同,这次程序执行了两次从键盘的读入,而且第一个字符串取了Hello world! 接受了空格符,而没有像上一个程序那样分成了两个字符串!所以如果要读入一个带空格符的字符串时因该用gets(), 而不宜用scanf()!


--------------------------------------------------------
| 问题描述三:(getchar()暂停程序,查看程序执行结果)|
--------------------------------------------------------
不知道大家有没有遇到过这样的问题,有的编译器程序执行完后的结果界面不会停下而是一闪就没了,以至于看不到执行结果。所以很多人在程序最后加上 getchar()语句,目的是想让程序执行完后停下来,等待从终端接收一个字符再结束程序。可是发现有时候这样根本没用,程序照样跳出去了。这是为什么 呢?
【分析】原因跟上面例子讲的一样,是因为输入缓冲区中还有数据,所以getchar()会成果读到数据,所以就跳出了!

 

------------------
| 【总结】 |
------------------

第一:要注意不同的函数是否接受空格符、是否舍弃最后的回车符的问题!
读取字符时:
scanf()以Space、Enter、Tab结束一次输入,不会舍弃最后的回车符(即回车符会残留在缓冲区中);
getchar()以Enter结束输入,也不会舍弃最后的回车符;
读取字符串时:
scanf()以Space、Enter、Tab结束一次输入
gets()以Enter结束输入(空格不结束),接受空格,会舍弃最后的回车符!

第二:为了避免出现上述问题,必须要清空缓冲区的残留数据,可以用以下的方法解决:
方法1:C语言里提供了函数清空缓冲区,只要在读数据之前先清空缓冲区就没问题了!
这个函数是fflush(stdin)。
方法2:自己取出缓冲区里的残留数据。
(说实话这个语句我也没看懂,呵呵!为什么格式控制是这样的!希望高手指点一下!)
scanf("%[^/n]",string);

|----------- 文章为作者原创,转载请注明出处或作者! ------------ |

 

getch,getche和getchar区别

首先不要忘了,要用getch()必须引入头文件conio.h,以前学C语言的时候,我们总喜欢用在程序的末尾加上它,利用它来实现程序运行完了暂停不 退出的效果。如果不加这句话,在TC2.0的环境中我们用Ctrl+F9编译并运行后,程序一运行完了就退回到TC环境中,我们根本来不及看到结果,这时 要看结果,我们就要按Alt+F5回到DOS环境中去看结果,这很麻烦。而如果在程序的结尾加上一行getch();语句,我们就可以省掉会DOS看结果 这个步骤,因为程序运行完了并不退出,而是在程序最后把屏幕停住了,按任意键才退回到TC环境中去。

那我们来看看getch()到底起的什么作用,getch()实际是一个输入命令,就像我们用cin>>的时候程序会停下来等你输入,和 cin不同的是,getch()的作用是从键盘接收一个字符,而且并不把这个字符显示出来,就是说,你按了一个键后它并不在屏幕上显示你按的什么,而继续 运行后面的代码,所以我们在C++中可以用它来实现“按任意键继续”的效果,即程序中遇到getch();这行语句,它就会把程序暂停下来,等你按任意 键,它接收了这个字符键后再继续执行后面的代码。

你也许会问,为什么我们在C++中就没有在程序的末尾加上getch(),解释是,软件总是不断更新的,不好的地方当然要进行改正,getch()加 在程序末尾,它又不赋值给任何变量,所以它在这个地方完全是垃圾代码,程序无关。C++中考虑到这一点,于是在每次程序运行完了并不退出,而是自动把屏 幕停下来,并显示“press any key...”叫你按任意键退出,这就好比C++在它的环境中运行程序,在程序的末尾自动加上了一行getch();语句,并且在这行语句前还添加了一行 输出语句cout<<"press any key...";来提示你程序结束了,按任意键继续。实际上我们编译好的程序在程序结束了本身是不会停下来的,我们可以在编译产生的Debug目录中找到 这个编译好的应用程序(扩展名exe),在文件夹中双击运行它,你会发现屏幕闪了一下MS-DOS窗口就关闭了,因为程序运行完就自动退出了,回到了 windows环境,当然,如果我们在DOS环境中运行这个程序,我们就可以直接在看到DOS屏幕上看到程序运行结果,因为程序运行完后并不清屏。

还有一个语句,和getch()很相似,getche(),它也需要引入头文件conio.h,那它们之间的区别又在哪里呢?不同之处就在于getch()无返回显示,getche()有返回显示。怎么说呢?我举个例子你就明白了。

--------------------------------------

#include <stdio.h>
#include <conio.h>
void main()
{
char ch;
for(int i=0;i<5;i++)
{
ch=getch();
printf("%c",ch);
}
}

--------------------------------------

这里输入输出我用的是C的函数库,没有用C++的iostream.h,这个我等会再说。首先这是个连续5次的循环来实现5次停 顿,等待我们输入,我们编译并运行这个程序,假设我们分别输入abcde,屏幕上显示的结果是abcde,这个abcde并不是在ch=getch(); 中输出的,我们把printf("%c",ch);这行语句去掉,就会发现我们按5次任意键程序就结束了,但屏幕上什么都没有显示。

(这里要注意一点,就是关于回车的问题,当我们输入a[Enter]之后,屏幕上会另起一行显示a,要注意,其实这里显示的不只是a,而是 a[Enter],这里[Enter]也算一个字符,所以当我们继续输入b[Enter]后,显示b,当再输入c[Enter]时,5个字符已满,多出一 个[Enter],所以屏幕上只显示c,我用的是C-Free,可以看到:

a
a
b
b
c
c请按任意键继续. . .

这里“请按任意键继续. . .”就跟c显示在了同一行,可知c后的[Enter]并没有输出,然后就退出了。为了验证这个,我们可以在第一行先输入一个[Enter],可以看到光标 到了第3行,然后我们再输入abcde,回车之后,只输出了abcd,因为这4个,加上前一个[Enter],5个字符已满。)

然后我们在把代码中的getch()换成getche()看看有什么不同,我们还是分别输入abcde,这时屏幕上显示的结果是 aabbccddee,我们把printf("%c",ch);这行语句再去掉看看,显示的结果就是abcde了,说明程序在执行 ch=getche();这条语句的时候就把我们输入的键返回显示在屏幕上,有无回显就是它们的唯一区别。

(读到此,有一处未明,就是二者显示的差别,前者输入abcde后,回车把abcde显示在下一行,而后者,输入a后,马上就显示a,输入b后马上显示b。我觉得按程序的执行顺序来说,后者应该是正确的,即getche有回显,输入后马上执行printf语句。

后苦苦思索,方才明白,我们在前者,也就是使用getch时,我们之所以能看到我们输入的abcde,就是printf语句的功劳,因为如果没有这句,我们就什么也看不到了,到此方大彻大悟啊,^_^)

好了,我们再来说说为什么不用C++函数库的原因。你可以试试把这个程序改成C++的形式(原来程序很乱,我依然用C写的):

--------------------------------------

#include <stdio.h>
#include <conio.h>
void main()
{
char ch='1';
while(ch=='1')
{
printf("/n按 1 继续循环,按其他键退出!");
ch=getch();
}
printf("/n退出程序!");
}

--------------------------------------

我们可以在这个循环体中添加我们想要的功能,程序中按*继续循环,其他任意键退出,而且利用getch()无回显的特性,我们不管按什么,都不会在屏 幕上留下痕迹,使我们的界面达到美观效果,如果还有更好的办法实现这个功能,我可能就不会在这里提这么多了。如果你真的有更好的办法,请一定告诉我,谢 谢!

下面我把别人网页上的几个例子转载如下:

--------------------------------------

//例一:这个例子是为了说明getch()和getche()的区别 #include #include

//这里讲个小故事:因为这个代码是在别人网页上的,别人用的C环境,可能是不需要conio.h头文件就可以用getch();(我就不清楚了),也可能是忘了写,网页上的源代码没有#include这一行,

void main()

{

char c, ch;

c=getch();

putchar(c);

ch=getche();

putchar(ch);

printf("/n/n");

}

--------------------------------------

//例二:这个例子是演示交互输入的过程中完成暂停功能

#include <stdio.h>
#include <conio.h>
void main()
{
char c, s[20];
printf("Name:");
gets(s);
printf("Press any key to continue.../n/n");
getch();
printf("/n/n");
}

--------------------------------------

//例三:getchar()函数也是从键盘上读入一个字符,并带回显。它前面两个函数的区别在于:

//getchar()函数等待输入直到按回车才结束,回车前的所有输入字符都会逐个显示在屏幕上。

//但只有第一个字符作为函数的返回值。

#include <stdio.h>
void main()
{
char c;
c=getchar(); //getchar()在这里它只返回你输入字符串的第一个字符,并把返回值赋值给c
putchar(c);
}

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/jiazhen198239/archive/2007/11/08/1873473.aspx

原文地址:https://www.cnblogs.com/lexus/p/2547257.html