作者:解学武
C语言gets()被删除了,改用fgets()!
在《C语言的五套标准:C89、C99、C11、C17和C23》一节里提到,作为上世纪 70 年代的产物,C语言历经了多个版本的迭代,增加很多新语法的同时,也剔除了当下认为不再适用的语法,这其中就包括 gets() 函数。
gets() 算得上是 C 语言里“元老级”的输入函数,C语言诞生的时候就有它了。在 C99 标准中,gets() 被标记为“不推荐使用(deprecated)”的函数,甚至在后来的 C11 标准里被正式移除了。
当 gets() 函数从键盘读取字符时,会一直读,直至遇到换行符
举个简单的例子:
对于这种异常情况,一些 C语言编译器(IDE)会给出警告信息。比如在 VS2022 运行上面的实例,运行结果为:
![图 VS提示运行异常](/uploads/allimg/250104/2-25010422052c08.gif)
图:VS 提示程序执行异常
fgets() 函数的使用也非常简单,这里直接将上文实例中的 gets() 改用 fgets() 函数:
和 gets() 对比不难发现,使用 fgets() 函数时需要指定最多读取的字符个数,这样就有效的避免了“gets()函数无限制读取字符”的安全隐患。
再次运行程序,结果为:
值得一提的是,尽管新的 C 语言标准已经移除了 gets() 函数,但很多 C 语言编译器(IDE)仍然保留着 gets() 函数,程序里使用 gets() 函数,大概率也能成功运行!
声明:当前文章为本站“玩转C语言和数据结构”官方原创,由国家机构和地方版权局所签发的权威证书所保护。
gets() 算得上是 C 语言里“元老级”的输入函数,C语言诞生的时候就有它了。在 C99 标准中,gets() 被标记为“不推荐使用(deprecated)”的函数,甚至在后来的 C11 标准里被正式移除了。
接下来,我将带领读者了解 gets() 被移除的原因,以及 gets() 函数的替代方案。注意,虽然 gets() 函数在 C11 标准中被移除了,但很多 C语言编译器(或者 IDE)仍旧保留着 gets() 函数。
gets()被移除的原因
gets() 函数从最初的“不推荐使用”到最后被移除,原因其实很简单,就是它不安全!当 gets() 函数从键盘读取字符时,会一直读,直至遇到换行符
'\n'
为止,丝毫不关心已经读取到的字符数量。存在的安全隐患是,一旦存储字符串的空间不足,那么字符串里的一部分就会“溢出”到指定空间的外面,非法抢占一块内存空间。如果被抢占的空间里存放着程序运行所需要的重要数据,由于这部分数据被溢出的字符覆盖了,会导致程序运行过程不可控,又或者运行崩溃。举个简单的例子:
#include <stdio.h> int main() { char buffer[10]; // 定义一个长度为10的字符数组。 printf("请输入一些字符: "); gets(buffer); // 使用gets函数读取输入 printf("你输入的内容是: %s\n", buffer); return 0; }上面代码中,buffer 数组最多存储 10 个字符。如果用户输入的字符数量超过 10 个(比如 "https://xiexuewu.github.io/c/"),gets() 函数依然会将所有字符一股脑塞进 buffer 数组,那么超出长度的字符会覆盖掉 buffer 数组后面内存空间中存放的数据,很可能导致程序运行不可控。
对于这种异常情况,一些 C语言编译器(IDE)会给出警告信息。比如在 VS2022 运行上面的实例,运行结果为:
请输入一些字符: https://xiexuewu.github.io/c/
你输入的内容是: https://xiexuewu.github.io/c/
![图 VS提示运行异常](/uploads/allimg/250104/2-25010422052c08.gif)
图:VS 提示程序执行异常
用fgets()函数替代gets()函数
C14 标准将 gets() 函数彻底移除了,如果想在程序中读取一行字符,除了用 scanf() 函数以外,还可以考虑 fgets() 函数,且更推荐使用后者。fgets() 函数的使用也非常简单,这里直接将上文实例中的 gets() 改用 fgets() 函数:
#include <stdio.h> int main() { char buffer[10]; // 定义一个长度为10的字符数组。 printf("请输入一些字符: "); fgets(buffer, 10, stdin); // 使用gets函数读取输入 printf("你输入的内容是: %s\n", buffer); return 0; }仔细观察第 6 行中的 fgets() 函数,fgets() 的括号里有三份数据,依次是:
- buffer:和 gets() 函数一样,要指定一块存储字符串的空间;
- 10:指定最多读取的字符个数;
- stdin:指定从哪里读取字符,当它的值设为 stdin 时,表示从键盘读取字符。关于 FILE,会在《C语言文件操作》一章中讲解。
和 gets() 对比不难发现,使用 fgets() 函数时需要指定最多读取的字符个数,这样就有效的避免了“gets()函数无限制读取字符”的安全隐患。
再次运行程序,结果为:
请输入一些字符: https://xiexuewu.github.io/c/
你输入的内容是: https://x
‘\0’
。
总结
从 C99 标准开始,就不再推荐使用 gets() 函数了,当程序中需要读取一行字符时,可以用 fgets() 函数代替 gets() 函数。值得一提的是,尽管新的 C 语言标准已经移除了 gets() 函数,但很多 C 语言编译器(IDE)仍然保留着 gets() 函数,程序里使用 gets() 函数,大概率也能成功运行!
声明:当前文章为本站“玩转C语言和数据结构”官方原创,由国家机构和地方版权局所签发的权威证书所保护。