在c语言中读取字符串有多种方法,
其一,scanf() 配合%s使用,但是这种方法只能获取一个单词,顾名思义,回车和空格都会打断scanf的输入。
想 I LIKE GITHUB 这种情况,scanf()就无能为力了。这时我们最先学到的是gets
gets()
gets()函数位于stdio库中,他会读入空格而不中断,gets()函数并不读取换行符'\n',它会吧换行符替换成空字符'\0',作为c语言字符串结束的标志。
gets()函数经常和puts()函数配对使用,puts()函数用于显示字符串,并自动在字符串后面添加一个换行标志'\n'
gets()函数存在一个严重的缺陷,这个缺陷就是:它不会检查数组是否能够装的下输入行:
比如:
我们定义了一个数组char a[100],这时候我们调用gets(a),来从标准输入读取字符串,我们看到gets()函数的参数为数组名,我们都知道,数组名就相当于一个指针,也就是数组的首地址。这时如果我们的输入大于5个字符,比如 I like you 。gets()函数会从a所指地址开始,依次填入每个字符,但是数组a只分配了5个字节的空间,填满这五个空间后,gets()函数就会访问未被分配的内存空间,如果这片空间已经存有数据,这时程序就会发生错误,而中断。
正由于gets()函数的这个缺陷,在C99标准中,已经不再建议使用gets()函数,而在C11中更是直接抛弃了这个函数。
fgets()
gets()有缺陷,那我们用什么来代替它的功能呢?
C11标准新增了gets_s()函数可以代替gets()函数,但是,该函数是stdio.h输入输出函数系类中的可选扩展,因此,即使编译器支持C11标准,也有可能不支持gets_s()函数。
其实我们可以用c语言中的fgets()函数来代替gets()
我们先看一下函数原型声明:
char *fgets(char *a, int asize, FILE *stream);
注意一下第二个参数asize,这个参数就限制了读取的字符的个数,这就可以解决gets()函数的缺陷。
我们知道fgets() 函数主要用于读取文件,如果要读取键盘,则stream参数应该为stdin,
如果asize设置为n,那么fgets()函数最多读取n-1个字符,之所以用“最多”这个词是因为,如果在之前遇到了换行符,fgets函数也会返回,fgets只会帮你保障字符串输入不发生gets()函数访问未被分配的内存空间这种错误。
还有一点就是,fgets()函数会读取换行符(这一点和gets函数不同),当读取结束后,fgets函数会为a在末尾添加一个空字符作为字符串的结束。
总结:
gets函数没有限制读入的个数,这很可能会导致程序向未知的内存空间写入数据,而导致程序出错。
fgets函数中第二个参数限制了读取的个数,这也解决了gets函数存在的问题,但要注意fgets函数只会读取n-1个字符(如果遇到换行符会更少),并在最后添加字符串结束标志,而且,fgets也会将换行符读入。