大家学习C语言一般的学校都会选择windows下的VC++6.0作为开发环境吧。VC本身确实很强大,在十几年前来看的话,这里不展开吐槽了。
只是想说VC本身使用并不支持C99,更不用说C11了。而落后必然导致一些问题。在此只讲一个不安全的函数gets()及其解决方法
tips:关于C99 啥的可以看一下ANSI C
我们先来看一下函数原型
char *gets(char *string);
gets()函数从流中读取字符串,直到出现换行符或读到文件尾为止,最后加上NULL作为字符串结束。所读取的字符串暂存在给定的参数string中。若成功则返回string的指针,否则返回NULL。
初学c语言时觉得gets真的很好用,与scanf相比可以输入在字符串中输入空格。最近使用linux下的vim却发现gets函数没有了,而且这个函数很危险。
从上面的说明我们可以看到,直到出现换行符或文件尾才结束读取,那么如果我输入了一个长长的字符串呢?
结果是很可怕的。。。
你输入的字符串将一直被写入缓存区,超出了原本的存储空间,覆盖其他的数据,造成程序崩溃,被其他人将恶意代码写入,甚至让别人能取得权限等等。。
所以在C11中,gets函数被删除了。
那么用什么替代gets呢?
答案是fgets
char *fgets(char *buf, int bufsize, FILE *stream);
函数成功将返回buf,失败或读到文件结尾返回NULL.
我们只需要将原本是文件指针的地方改成stdin. buf是写入的数组名,bufsize为写入的字符数。
注意fgets最多只会读入bufsize-1个字符,默认最后一位为NULL,这也是保证了不会写入过多的字符。
例子
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main(void)
{
char str[10];
fgets(str,10,stdin);
fputs(str,stdout);
printf("\n");
}
- 函数参数为10,当我们输入超过了10个字符,由输出可知,str数组中存放了kangkangh 9个字符加一个NULL
- 当输入恰好为参数buf-1个时,str数组内容和第1种一样。
当输入不足9时str数组在NULL之前多存放了一个/n(在gets函数中这个输入的换行符会被转换成NULL存入数组)。
小彩蛋
大家注意到了吗? fputs函数默认不换行,而puts函数则不同
总结
gets函数可能导致及其危险的后果,所以还是用fgets来替代它吧。
后记
对于gets函数,微软有一个‘安全’的替代函数gets_s,可以在VS上使用,但可移植性太差,读者若感兴趣可自行搜索了解,本文不多介绍。