详解C语言gets()函数与它的替代者fgets()函数

所属分类: 软件编程 / C 语言 阅读数: 39
收藏 0 赞 0 分享

 在c语言中读取字符串有多种方法,比如scanf() 配合%s使用,但是这种方法只能获取一个单词,即遇到空格等空字符就会返回。如果要读取一行字符串,比如:

I love BIT

这种情况,scanf()就无能为力了。这时我们最先想到的是用gets()读取.

gets()函数从标准输入(键盘)读入一行数据,所谓读取一行,就是遇到换行符就返回。gets()函数并不读取换行符'\n',它会吧换行符替换成空字符'\0',作为c语言字符串结束的标志。

gets()函数经常和puts()函数配对使用,puts()函数用于显示字符串,并自动在字符串后面添加一个换行标志'\n'

gets()函数存在一个严重的缺陷,这个缺陷就是:它不会检查数组是否能够装的下输入行:

比如:

我们定义了一个数组char src[5],这时候我们调用gets(src),来从标准输入读取字符串,我们看到gets()函数的参数为数组名,我们都知道,数组名就相当于一个指针,也就是数组的首地址。这时如果我们的输入大于5个字符,比如 I love BIT,gets()函数会从src所指地址开始,依次填入每个字符,但是src只分配了5个字节的空间,填满这五个空间后,gets()函数就会访问未被分配的内存空间,如果这片空间已经存有数据,这时程序就会发生错误,而中断。

正式由于gets()函数的这个缺陷,在C99标准中,已经不再建议使用gets()函数,而在C11中更是直接抛弃了这个函数。

gets()被抛弃,那我们用什么来代替它的功能呢?

C11标准新增了gets_s()函数可以代替gets()函数,但是,该函数是stdio.h输入输出函数系类中的可选扩展,因此,即使编译器支持C11标准,也有可能不支持gets_s()函数。

其实我们可以用c语言中的fgets()函数来代替gets()

我们先看一下函数原型声明:

char *fgets(char *buf, int bufsize, FILE *stream);

注意一下第二个参数bufsize,这个参数就限制了读取的字符的个数,这就可以解决gets()函数的缺陷。

我们知道fgets() 函数主要用于读取文件,如果要读取键盘,则stream参数应该为stdin,

需要注意的是,如果bufsize设置为n,那么fgets()函数最多读取n-1个字符,之所以用“最多”这个词是因为,如果在之前遇到了换行符,fgets函数也会返回。

还有一点就是,fgets()函数会读取换行符(这一点和gets函数不同),当读取结束后,fgets函数会为buf在末尾添加一个空字符作为字符串的结束。

可以看一个简单的小例子:

#include <stdio.h>
#include <stdlib.h>
#define LEN 6
int main(int argc,char* argv[])
{
char src[LEN];
printf("please enter:\n");
fgets(src,LEN,stdin);
printf("your enter is:\n");
fputs(src,stdout);
}

在这个程序中,我把数组的长度设置为6,先看一组输入和输出:

输入为zhan和回车('\n'),一共五个字符,fgets会读取这五个字符,然后在末尾添加字符串结束标志'\0';

我们知道fputs()函数并不会自动添加换行,但是输出结果却换行输出了Press any....,这就说明了fgets()函数是会读取换行符的。

在看一组输入输出:

这次我输入了zhang和回车换行,fgets函数依然是读取5个字符(LEN-1个),这时fgets()读入zhang,已经是五个字符了,所以回车换行并不会读入,最后fgets()添加字符串结束标志'\0',所以我们看到输出时,Press any...并没有换行输出,而是和zhang在同一行。

最后看一组输入和输出:

相信不用解释大家也都明白了。

总结一下就是:

gets函数没有限制读入的个数,这很可能会导致程序向未知的内存空间写入数据,而导致程序出错。

fgets函数中第二个参数限制了读取的个数,这也解决了gets函数存在的问题,但要注意fgets函数只会读取n-1个字符(如果遇到换行符会更少),并在最后添加字符串结束标志,而且,fgets也会将换行符读入。

以上所述是小编给大家介绍的详解C语言gets()函数与它的替代者fgets()函数的相关知识,希望对大家有所帮助,如果大家想了解更多,敬请关注脚本之家!

更多精彩内容其他人还在看

C++广播通信实例

这篇文章主要介绍了C++实现广播通信的方法,实例讲述了C++ socket广播通信的原理与实现方法,需要的朋友可以参考下
收藏 0 赞 0 分享

C++计算ICMP头的校验和实例

这篇文章主要介绍了C++计算ICMP头的校验和的方法,代码简单实用,对于校验ICMP报文来说有不错的实用价值,需要的朋友可以参考下
收藏 0 赞 0 分享

C++设置超时时间的简单实现方法

这篇文章主要介绍了C++设置超时时间的简单实现方法,涉及系统函数setsockopt对套接口的操作,具有一定的实用价值,需要的朋友可以参考下
收藏 0 赞 0 分享

C++实现ping程序实例

这篇文章主要介绍了C++实现ping程序实例,涉及C++对于ICMP数据包的发送与回显处理,具有一定的实用价值,需要的朋友可以参考下
收藏 0 赞 0 分享

C++之boost::array的用法

这篇文章主要介绍了C++之boost::array的用法,以实例的形式简单讲述了静态数组的容器boost::array的使用技巧,具有一定的参考借鉴价值,需要的朋友可以参考下
收藏 0 赞 0 分享

C++之Boost::array用法简介

这篇文章主要介绍了C++之Boost::array用法简介,较为详细的分析了Boost::array中的常见用法,并用实例的形式予以总结归纳,需要的朋友可以参考下
收藏 0 赞 0 分享

VC文件目录常见操作实例汇总

这篇文章主要介绍了VC文件目录常见操作实例汇总,总结了VC针对文件目录的各种常用操作,非常具有实用价值,需要的朋友可以参考下
收藏 0 赞 0 分享

VC打印word,excel文本文件的方法

这篇文章主要介绍了VC打印word,excel文本文件的方法,是VC操作文本文件中非常实用的技巧,需要的朋友可以参考下
收藏 0 赞 0 分享

VC++获得当前进程运行目录的方法

这篇文章主要介绍了VC++获得当前进程运行目录的方法,可通过系统函数实现该功能,是非常实用的技巧,需要的朋友可以参考下
收藏 0 赞 0 分享

VC中SendMessage和PostMessage的区别

这篇文章主要介绍了VC中SendMessage和PostMessage的区别,较为全面的分析了SendMessage和PostMessage运行原理及用法上的不同之处,非常具有实用价值,需要的朋友可以参考下
收藏 0 赞 0 分享
查看更多