C语言gets和fgets函数详解

C语言中gets与fgets的介绍

本文转载自http://c.biancheng.net/view/379.html
以及https://www.cnblogs.com/aexin/p/3908003.html 中的部分内容

gets介绍

对于 gets 函数,它的任务是从 stdin 流中读取字符串,直至接收到换行符或 EOF 时停止,并将读取的结果存放在 buffer 指针所指向的字符数组中。这里需要注意的是,换行符不作为读取串的内容,读取的换行符被转换为 null(’\0’) 值,并由此来结束字符串。即换行符会被丢弃,然后在末尾添加 null(’\0’) 字符。其函数的原型如下:
char* gets(char* buffer);
从键盘上输入字符,直至接受到换行符或EOF时停止,并将读取的结果存放在buffer指针所指向的字符数组中。读取的换行符被转换为null值,做为字符数组的最后一个字符,来结束字符串。
如果读入过程中遇到 EOF 或发生错误,返回 NULL 指针。因此,在遇到返回值为 NULL 的情况,要用 ferror 或 feof 函数检查是发生错误还是遇到 EOF。

注意:gets函数由于没有指定输入字符大小,所以会无限读取,一旦输入的字符大于数组长度,就会发生内存越界,从而造成程序崩溃或其他数据的错误。

如果函数的调用者提供了一个指向堆栈的指针,并且 gets 函数读入的字符数量超过了缓冲区的空间(即发生溢出),gets 函数会将多出来的字符继续写入堆栈中,这样就覆盖了堆栈中原来的内容,破坏一个或多个不相关变量的值。如下面的示例代码所示:

int main(void)
{
    char buffer[11];
    gets(buffer);
    printf("输出: %s\n",buffer);
    return 0;
}

示例代码的运行结果为:
aaa
输出: aaa

根据运行结果,当用户在键盘上输入的字符个数大于缓冲区 buffer 的最大界限时,gets 函数也不会对其进行任何检查,因此我们可以将恶意代码多出来的数据写入堆栈。由此可见,gets 函数是极其不安全的,可能成为病毒的入口,因为 gets 函数没有限制输入的字符串长度

fgets介绍

相对于 gets 函数,fgets 函数最大的改进就是能够读取指定大小的数据,从而避免 gets 函数从 stdin 接收字符串而不检查它所复制的缓冲区空间大小导致的缓存溢出问题。当然,fgets 函数主要是为文件 I/O 而设计的(注意,不能用 fgets 函数读取二进制文件,因为 fgets 函数会把二进制文件当成文本文件来处理,这势必会产生乱码等不必要的麻烦)。
fgets 函数的原型如下:

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

即:fgets(str, N, stdin) ; str 是指字符数组,N指
最大读入字符数,stdin 表明读取的哪个文件,如果是从键盘上读入数据,可以使用 stdin 作为该参数。

fgets只能读取N-1个字符,包括最后的换行符(’\n’),读完结束后系统将自动在最后加’\0’(gets读完结束后系统自动会将’\n’置换成’\0’)。

说到这里就有俩种情况了:

一:当你从键盘上输入 <=N-1 个字符(包括’\n’)时,那么字符串str会以 ‘\n\0’ 结尾。这就造成了strlen(str)比你想象的大 1 ,当然你可以通过下面代码将’\n’去掉。

if(str[strlen(str) - 1] == '\n') {      // 去掉换行符
     str[strlen(str) - 1] = '\0';   
 }

二:当你从键盘上输入>N-1个字符(包括’\n’)时,那么字符串str会以’\0’结尾。

代码示例:

int main(void)
{
    char buffer[11];
    fgets(buffer,11,stdin);
    printf("输出: %s\n",buffer);
    return 0;
}

对于上面的示例代码,如果输入的字符串小于或等于 10 个字符,那么程序将完整地输出结果;如果输入的字符串大于 10 个字符,那么程序将截断输入的字符串,最后只输出前 10 个字符。示例代码运行结果为:

aaaaaaaaaaaaaaaa (共16个)
输出: aaaaaaaaaa (共10个)

  • 3
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值