scanf( )函数和gets( )函数都可用于输入字符串,但在功能上有区别。若想从键盘上输入字符串"hi hello",则应该使用__gets__函数。gets可以接收空格;而scanf遇到空格、回车和Tab键都会认为输入结束,所有它不能接收空格。char string[15]; gets(string); /*遇到回车认为输入结束*/
scanf("%s",string); /*遇到空格认为输入结束*/
所以在输入的字符串中包含空格时,应该使用gets输入。
scanf和gets获取字符串时的区别在C语言中,能构获取字符串的函数至少有两个:
1.scanf()
所在头文件:stdio.h
语法:scanf("格式控制字符串",变量地址列表);
接受字符串时:scanf("%s",字符数组名或指针);
2.gets()
所在头文件:stdio.h
语法:gets(字符数组名或指针);
两者在接受字符串时:
1.不同点:
scanf不能接受空格、制表符Tab、回车等;
而gets能够接受空格、制表符Tab和回车等;
2.相同点:
字符串接受结束后自动加'\0'。
例1:
#include <stdio.h>
main(){
char ch1[10],ch2[10];
scanf("%s",ch1);
gets(ch2);
}
依次键入asd空格fg回车,asd空格fg回车,则ch1="asd\0",ch2="asd fg\0"。
例2:
#include <stdio.h>
main(){
char ch1[10],ch2[10],c1,c2;
scanf("%s",ch1);
c1=getchar();
gets(ch2);
c2=getchar();
}
依次键入asdfg回车,asdfg回车,则ch1="asdfg\0",c1='\n',ch2="asdfg\0",c2需输入。
scanf :当遇到回车,空格和tab键会自动在字符串后面添加'\0',但是回车,空格和tab键仍会留在输入的缓冲区中。
gets:可接受回车键之前输入的所有字符,并用'\n'替代 '\0'.回车键不会留在输入缓冲区中
gets()用到读取字符串,用回车结束输入
scanf()可以读取所有类型的变量
1. 为什么 fflush(stdin) 是错的?
首先请看以下程序:
#include <stdio.h>
int main( void ){
int i;
for (;;)
for ( ; ; ) {
~~~~~~~~~~~~~~~~~~~~~~~~~``
C语言中有几个基本输入函数:
这里仅讨论输入函数在标准输入(stdin)情况下的使用。纵观上述各输入函数,
MINGW 4.4.3中FILE结构体源码: typedef struct _iobuf{char* _ptr;//指向当前缓冲区读取位置int _cnt;//缓冲区中剩余数据长度 各编译器实现可能不一样,这里获取字符系列函数只用到_ptr和_cnt。 MINGW 4.4.3中getchar()实现: __CRT_INLINE int __cdecl __MINGW_NOTHROW getchar (void){ 其中stdin为FILE指针类型,在MINGW 4.4.3中,getc()和getchar()实现为内联函数,fgetc()实现为函数。顺便说一句,C99标准中已经加入对内联函数的支持了。
=================分 割 线================= 提到缓冲区,就不得不提setbuf和setvbuf两个缓冲区设置函数,其声明如下: void setbuf(FILE * restrict stream, char * restrict buf);int setvbuf(FILE * restrict stream, char * restrict buf, int mode, size_t size); setvbuf的mode参数有:
setbuf(stream, buf);在:
注:BUFSIZ宏在stdio.h中定义。
这里还要提一下传说中的setbuf的经典错误,在《C陷阱和缺陷》上有提到:
问题是这样的:程序交回控制给操作系统之前C运行库必须进行清理工作,其中一部分是刷新输出缓冲,但是此时main函数已经运行完毕,buf缓冲区作用域在main函数中,此时buf字符数组已经释放,导致输出诡异乱码。 解决方案:可以将buf设置为static,或者全局变量,或者调用malloc来动态申请内存。 =================分 割 线================= 下面来看看几种流行的缓冲区清空方法:
由C99标准文档中: If stream points to an output stream or an update stream in which the most recentoperation was not input, the fflush function causes any unwritten data for that streamto be delivered to the host environment to be written to the file; otherwise, the behavior isundefined. 可以看出fflush对输入流为参数的行为并未定义。但由MSDN上的fflush定义: If the file associated with stream is open for output, fflush writes to that file thecontents of the buffer associated with the stream. If the stream is open for input,fflush clears the contents of the buffer. 可以看出fflush(stdin)在VC上还是有效地!鉴于各编译器对fflush的未定义行为实现不一样,不推荐使用fflush(stdin)刷新输入缓冲区。
由前面对setbuf函数的介绍,可以得知,setbuf(stdin, NULL);是使stdin输入流由默认缓冲区转为无缓冲区。都没有缓冲区了,当然缓冲区数据残留问题会解决。但这并不是我们想要的。
这里用到了scanf格式化符中的“*”,即赋值屏蔽;“%[^集合]”,匹配不在集合中的任意字符序列。这也带来个问题,缓冲区中的换行符’\n’会留下来,需要额外操作来单独丢弃换行符。
由代码知,不停地使用getchar()获取缓冲区中字符,直到 获取的字符c是换行符’\n’或者是文件结尾符EOF为止。这个方法可以完美清除输入缓冲区,并且具备可移植性。 |