gets和fgets函数及其区别,C语言gets和fgets函数详解
那么,究竟是什么原因导致 gets 函数这么不招人待见呢?
我们知道,对于 gets 函数,它的任务是从 stdin 流中读取字符串,直至接收到换行符或 EOF 时停止,并将读取的结果存放在 buffer 指针所指向的字符数组中。这里需要注意的是,换行符不作为读取串的内容,读取的换行符被转换为 null( /0 ) 值,并由此来结束字符串。即换行符会被丢弃,然后在末尾添加 null( /0 ) 字符。其函数的原型如下:
char* gets(char* buffer);
如果读入成功,则返回与参数 buffer 相同的指针;如果读入过程中遇到 EOF 或发生错误,返回 NULL 指针。因此,在遇到返回值为 NULL 的情况,要用 ferror 或 feof 函数检查是发生错误还是遇到 EOF。
函数 gets 可以无限读取,不会判断上限,所以程序员应该确保 buffer 的空间足够大,以便在执行读操作时不发生溢出。也就是说,gets 函数并不检查缓冲区 buffer 的空间大小,事实上它也无法检查缓冲区的空间。
如果函数的调用者提供了一个指向堆栈的指针,并且 gets 函数读入的字符数量超过了缓冲区的空间(即发生溢出),gets 函数会将多出来的字符继续写入堆栈中,这样就覆盖了堆栈中原来的内容,破坏一个或多个不相关变量的值。如下面的示例代码所示:
int main(void) char buffer[11]; gets(buffer); printf( 输出: %s/n ,buffer); return 0; }
示例代码的运行结果为:
aaa
输出: aaa
根据运行结果,当用户在键盘上输入的字符个数大于缓冲区 buffer 的最大界限时,gets 函数也不会对其进行任何检查,因此我们可以将恶意代码多出来的数据写入堆栈。由此可见,gets 函数是极其不安全的,可能成为病毒的入口,因为 gets 函数没有限制输入的字符串长度。所以我们应该使用 fgets 函数来替换 gets 函数,实际上这也是大多程序员所推荐的做法。
相对于 gets 函数,fgets 函数最大的改进就是能够读取指定大小的数据,从而避免 gets 函数从 stdin 接收字符串而不检查它所复制的缓冲区空间大小导致的缓存溢出问题。当然,fgets 函数主要是为文件 I/O 而设计的(注意,不能用 fgets 函数读取二进制文件,因为 fgets 函数会把二进制文件当成文本文件来处理,这势必会产生乱码等不必要的麻烦)。其中,fgets 函数的原型如下:
char *fgets(char *buf, int bufsize, FILE *stream);
该函数的第二个参数 bufsize 用来指示最大读入字符数。如果这个参数值为 n,那么 fgets 函数就会读取最多 n-1 个字符或者读完一个换行符为止,在这两者之中,最先满足的那个条件用于结束输入。
与 gets 函数不同的是,如果 fgets 函数读到换行符,就会把它存储到字符串中,而不是像 gets 函数那样丢弃它。即给定参数 n,fgets 函数只能读取 n-1 个字符(包括换行符)。如果有一行超过 n-1 个字符,那么 fgets 函数将返回一个不完整的行(只读取该行的前 n-1 个字符)。但是,缓冲区总是以 null( /0 ) 字符结尾,对 fgets 函数的下一次调用会继续读取该行。
也就是说,每次调用时,fgets 函数都会把缓冲区的最后一个字符设为 null( /0 ),这意味着最后一个字符不能用来存放需要的数据。所以如果某一行含有 size 个字符(包括换行符),要想把这行读入缓冲区,要把参数 n 设为 size+1,即多留一个位置存储 null( /0 )。
最后,它还需要第 3 个参数来说明读取哪个文件。如果是从键盘上读入数据,可以使用 stdin 作为该参数,如下面的代码所示:
int main(void) char buffer[11]; fgets(buffer,11,stdin); printf( 输出: %s/n ,buffer); return 0; }
对于上面的示例代码,如果输入的字符串小于或等于 10 个字符,那么程序将完整地输出结果;如果输入的字符串大于 10 个字符,那么程序将截断输入的字符串,最后只输出前 10 个字符。示例代码运行结果为:
aaaaaaaaaaaaaaaa
输出: aaaaaaaaaa
除此之外,C99 还提供了 fgets 函数的宽字符版本 fgetws 函数,其函数的一般原型如下面的代码所示:
wchar_t *fgetws(wchar_t * restrict s, int n, FILE * restrict stream);
该函数的功能与 fgets 函数一样。
21621.html
GCC操作系统相关文章
- C语言文件读写操作(详解)
- 【C语言:取整&4种函数】详解
- 蓝桥杯 名次判断(详解)----------------C语言—菜鸟级
- C语言位运算符详解「建议收藏」
- [C语言] 数据结构-预备知识跨函数使用内存详解编程语言
- [linux] C语言Linux系统编程-socket开发详解编程语言
- C语言之二维数组详解编程语言
- C语言之带有返回值的函数详解编程语言
- C语言之分支结构 if(二)详解编程语言
- C语言之字符集、ASCII码和sizeof运算符详解编程语言
- 一致性Linux C语言目录系统的一致性保证(linuxc目录存在)
- C语言_简单的阶乘函数详解编程语言
- C语言空(null)指针和NULL指针的区别详解
- 数组名作为函数参数传递,C语言数组作为函数参数传递详解
- 二维数组指针表示,C语言指针引用二维数组详解
- fgets函数及其用法,C语言fgets函数详解
- 关系运算符及其优先级,C语言关系运算符及其优先级详解
- static变量及其作用,C语言static变量详解
- 字符串查找函数,C语言字符串查找函数详解
- strlen函数与sizeof的区别,C语言strlen与sizeof的区别详解
- _Generic关键字及其语法和应用(C11标准),C语言_Generic详解
- fread和fwrite函数,C语言fread和fwrite函数详解
- strchr和strrchr函数及用法,C语言strchr和strrchr函数详解
- C语言求完数(完全数)(详解版)
- C语言实现Linux操作系统(c语言执行linux)
- 统计Linux中C语言应用程序的使用情况(statlinuxc)
- MySQL数据库函数C语言实现(c mysql数据库函数)
- 解析C语言中空指针、空指针常量、NULL&0的详解
- 基于C语言string函数的详解
- 使用C语言中的time函数获取系统时间