C语⾔的字符串输⼊gets()函数
C语⾔的字符串输⼊gets()函数
字符串简介
字符串(character string)是⼀个或多个字符的序列。如下所⽰:
"Zing went the strings of my heart!"
双引号不是字符串的⼀部分。双引号告知编译器它括起来的是字符串。C语⾔没有专门⽤于存储字符串的变量类型,字符串都被存储在char 类型的数组中。字符串常量"x"和字符常量'x'不同,区别之⼀在于'x'是基本类型(char),⽽"x"是派⽣类型(char数组);区别之⼆是"x"实际上由两个字符串组成:'x'和空字符\0。
字符串输⼊函数gets()
在c语⾔中读取字符串有多种⽅法,⽐如scanf() 配合%s使⽤,但是这种⽅法只能获取⼀个单词,即遇到空格等空字符就会返回。如果要读取⼀⾏字符串,⽐如:
I love you!
这种情况,scanf()就⽆能为⼒了。这时我们最先想到的是⽤gets()读取.
gets()函数从标准输⼊(键盘)读⼊⼀⾏数据,所谓读取⼀⾏,就是遇到换⾏符就返回。gets()函数并不读取换⾏符'\n',它会把换⾏符替换成空字符'\0',作为c语⾔字符串结束的标志。
gets()函数经常和puts()函数配对使⽤,puts()函数⽤于显⽰字符串,并⾃动在字符串后⾯添加⼀个换⾏标志'\n'。
gets()的缺陷
gets()函数存在⼀个严重的缺陷,这个缺陷就是:它不会检查数组是否能够装得下输⼊⾏。
⽰例分析:
/*  getsputs.c  -- using gets() and puts() */
#include <stdio.h>
#define STLEN 81
int main(void)
{
char words[STLEN];
puts("Enter a string, please.");
gets(words);  // typical use
printf("Your string twice:\n");
printf("%s\n", words);
puts(words);
puts("Done.");
return 0;
}
下⾯是某些编译器(⾄少是旧式编译器)中的运⾏⽰例:
Enter a string, please.
I want to learn about string theory![⽤户输⼊]
Your string twice:
I want to learn about string theory!
I want to learn about string theory!
Done.
下⾯是在另⼀个编译器中的输出⽰例:
Enter a string, please.
warning:this program uses gets(),which is unsafe.
I want to learn about string theory![⽤户输⼊]
c语言编译器怎么用?
Your string twice:
I want to learn about string theory!
I want to learn about string theory!
Done.
编译器在输出中插⼊了⼀⾏警告信息。这是怎么回事?问题出在gets()唯⼀的参数是words,它⽆法检查是否装得下输⼊⾏。数组名会转换成该数组⾸元素的地址,因此gets()函数只知道数组的开始处,并不知道数组中有多少个元素。
如果输⼊的字符串过长,会导致缓冲区溢出(buffer overflow),即多余的字符超出了指定的⽬标空间。gets()函数就会访问未被分配的内存空间,如果这些内存未被使⽤,不会⽴即出现问题;如果这⽚空间已经存有数据,就会擦除掉程序中的其他数据,会导致程序中⽌。
正式由于gets()函数的这个缺陷,在C99标准中,已经不再建议使⽤gets()函数,⽽在C11中更是直接抛弃了这个函数。然⽽在实际应⽤中,编译器为了兼容以前的代码,⼤部分都继续⽀持gets()函数。
gets()被抛弃,那我们⽤什么来代替它的功能呢?
C11标准新增了gets_s()函数可以代替gets()函数,但是,该函数是stdio.h输⼊输出函数系类中的可选扩展,因此,即使编译器⽀持C11标准,也有可能不⽀持gets_s()函数。
其实我们可以⽤c语⾔中的fgets()函数来代替gets()
接下来的博客会会继续分析其他字符串输⼊函数。