fgets、gets、scanf函数读入字符串比较

时间:2022-04-22 13:31:28

首先,说说这个函数的使用方法。代码如下:

char str[10];
fgets(str, 10, stdin);//stdin表示从输入流中读入,也可以是其他文件指针。
gets(str);
scanf("%s", str);
其中fgets函数是安全的,gets和scanf函数都是不安全的。当输入的字符 大于等于10时,会数组越界。编译不会保存,甚至运行时也不会保存。但极可能因为对str数组越界写入,导致更改了其他变量的值。

在上述代码中fgets的第二个参数10制定了最多读入的字符小于10。也就是说,上述fgets函数调用最多从stdin(标准输入流,通常是键盘)中读入9个字符。之所以要空出一个,是因为C语言中字符串有一个结束标志'\0',fgets为str中空出的这一个数组元素,就是为'\0'准备的。


其次,如果输入的字符小于数组长度,fgets、gets、scanf函数读入的是怎样的字符串。

首先:fgets读入的是带'\n'的字符串。也就是说,在不超过第二个参数的情况下,fgets从第三个参数(文件指针,输入流)中不断的读入字符。直到遇到'\n',并将'\n'从输入流中取出

其次:gets函数不检测读入的字符的个数。仅仅是不断的从标准输入流(键盘)中读入字符,直到遇到'\n'。与fgets不同的是,虽然gets函数也会将'\n'从输入流中取出,但却只是取出,然后丢掉。并不保存在目标字符串中(上述代码中既是str)。

最后:scanf函数不检测读入的字符的个数。仅仅是不断的从标准输入流(键盘)中读入字符,直到遇到“空白符。和fgets/gets不同的是,scanf从输入流中取出“空白符”。

空白符:换页符、纵向制表符、横向制表符('\t')、空格(' ')、换行符('\n')、回车符('\r')


鉴于scanf和gets函数对'\n'的不同态度,将他们混合使用是不恰当的。例如下述代码:

int n;
char str[80];
scanf("%d", &n);
gets(str);
printf("%s\n", str);
运行上述代码,输入1958 ustc,str的值为" ustc",程序输出"ustc"及一个换行;输入1958↙ustc,str的值为"\n",(其中↙表示键盘输入回车),程序输出两个换行。推荐的解决方案如下:

scanf("%d ", &n);//
%d后有一个空格,这样就过滤掉了'\n'以及可能出现的'\r'——输入流被重定向到文件时会有这样的情况,详见后文。


关于回车('\r')和换行(‘\n’)。网上流传着如下的说法:

在计算机还没有出现之前,有一种叫做电传打字机(Teletype Model 33)的玩意,每秒钟可以打10个字符。但是它有一个问题,就是打完一行换行的时候,要用去0.2秒,正好可以打两个字符。要是在这0.2秒里面,又有新的字符传过来,那么这个字符将丢失。 
于是,研制人员想了个办法解决这个问题,就是在每行后面加两个表示结束的字符。一个叫做“回车”,告诉打字机把打印头定位在左边界;另一个叫做“换行”,告诉打字机把纸向下移一行。
这就是“换行”和“回车”的来历,从它们的英语名字上也可以看出一二。
后来,计算机发明了,这两个概念也就被般到了计算机上。那时,存储器很贵,一些科学家认为在每行结尾加两个字符太浪费了,加一个就可以。于是,就出现了分歧。
Unix系统里,每行结尾只有“<换行>”(即'\n');Windows系统里面,每行结尾是“<回车><换行>”,即“\r\n”;Mac系统里,每行结尾是“<回车>”('\r')。一个直接后果是,Unix/Mac系统下的文件在Windows里打开的话,所有文字会变成一行;而Windows里的文件在Unix/Mac下打开的话,在每行的结尾可能会多出一个^M符号。

以上摘自:http://javaeye-mao.iteye.com/blog/211354

<CR><LF>的说法源于打印机打字   
       <CR>(Carriage   return):  \r   (return)   0x0d   
       <LF>(Line   feed):   \n   (new   line)   0x0a  


      这个东西的说法来自打字机,以前的打字机要新起一行的时候有两步:   
    
      1.   打字的机头回到开始位置,这就是回车   
      2.   纸张往上推进一行,这就是换行   


以上摘自:http://blog.163.com/fullsee@126/blog/static/14202144320104704030821/


要时刻牢记的是,'\r'是空白符,scanf函数不会读入它。但是fgets和gets函数会读取它!尤为重要的是,ACM的在线评测系统(OJ),通常是运行在Linux下,采用文件重定向的方式重文件中读取输入。我们也可以通过freopen函数将输入输出流重定向到文件,以减少程序调试时的输出。详见利用freopen函数重定向输入输出,辅助程序调试

在Windows环境下,生成的文件中的换行,通常都是【CR】【LF】,即"\r\n"。非常坑爹的是:即便是文件重定向了,在Windows下,fgets、gets函数并不会读入'\r'。但是在Linux下,如果文件中换行是"\r\n",那么悲剧的是,fgets和gets会读入'\r'。因为如前所述,Linux系统下的换行,是不包含的'\r'的,所以Linux系统并不会像Windows系统那样对''\r'采取特殊的处理!很多同学利用gets函数读入字符串后,默认字符串最后一位是字符串结束符标志'\0',在程序中没有考虑到'\r'的情况。最后导致在Windows下能够调试通过,但是提交到ACM平台却通不过的抓狂场景。


在USTCOJ上,题1362的测试数据的输入文件中换行是'\n'。而题1365的测试数据的输入文件中换行是'\r\n'。

最后,如果想要知道一个文件中的换行是怎样的,可以通过Notepad++软件打开,“视图”->“显示符号”->“显示所有字符”。显示效果如下图:

fgets、gets、scanf函数读入字符串比较