C/C++
学习笔记
1 -
深入了解
scanf()/getchar()
和
gets()
等函数
----------------------------------------------------
|
问题描述一:
(分析
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);