最近在学C的时候, 偶然观察到scanf()的一些“有趣”的表现。我总结了一下,写成此文。
首先是test1()。
一眼看去,程序期望用户输入两次数据。先是 scanf(),后是fgets()。但其实只要输入一次(
输入和输出结果在test1()后面
)。
scanf() 重stdin中读取数据,所以应该是scanf()将换行符留在stdin中了。
接下来我们尝试在调用
scanf()后将stdin中残余的字符清掉。第一反应是fflush()。但很可惜fflush()对于input stream的行为是未定义的(我看到在ubuntu man page上说fflush()可清空input stream,但运行结果显示
fflush()不起作用)。查询一下,下列代码能满足清空input stream的需求:
while ((c = getchar()) != '\n' && c != EOF)
; /* discard */
具体看test2()。这提示我们以后用scanf()的时要谨防它留下的垃圾。
然后我再想fgets()是否会像scanf()一样留下“垃圾”。test3()的结果表明不会。
有趣的是scanf()自己会防范这些“垃圾”。看test4()。
最后test5()表明,scanf()会读取字符串,知道遇到换行符或EOF,然后在字符串的后面加上“\0”结束符。
/*
* discuss_scanf_fgets.c
*
* Created on: Jun 6, 2014
* Author: damonhao
*/
#include <stdio.h>
#include <string.h>
void test1()
{
char buf[20];
scanf("%s", buf);
printf("%d\n", strlen(buf));
char buf2[20];
fgets(buf2, 20, stdin);
printf("%d\n", strlen(buf2));
printf("%s", buf2);
}
/*
dddd //input
4 //output
1
*/
void test2()
{
char buf[20];
scanf("%s", buf);
printf("%d\n", strlen(buf));
// fflush(stdin); doesn't work for input stream, this behaviour is undefined;
//clean input stream;
char c;
while ((c = getchar()) != '\n' && c != EOF)
; /* discard */
char buf2[20];
fgets(buf2, 20, stdin);
printf("%d\n", strlen(buf2));
}
/*
dddd
4
dddd
5
*/
void test3()
{
char buf2[20];
fgets(buf2, 20, stdin);
printf("%d\n", strlen(buf2));
char buf[20];
scanf("%s", buf);
printf("%d\n", strlen(buf));
}
/*
dddd
5
dddd
4
*/
void test4()
{
char buf[20];
scanf("%s", buf);
//scanf("%2s", buf);
printf("%d\n", strlen(buf));
char buf2[20];
scanf("%s", buf2);
printf("%d\n", strlen(buf2));
}
/*
dddd
4
dddd
4
*/
void test5()
{
char buf2[] = "xxxxxxxxxxxxxxxxxx";
scanf("%s", buf2);
printf("%d\n", strlen(buf2));
printf("%s", buf2);
}
/*
dddd
4
dddd
*/
int main()
{
test1();
return 0;
}
参考文章 :
前段时间忙着找工作,博客好久没有更新了,要坚持!!