首先自问自答,错!fgets()里面同样有陷阱!
其实http://www.cplusplus.com/reference/clibrary/cstdio/gets/说得很清楚了
Notice that gets does not behave exactly as fgets does with stdin as argument:
First, the ending newline character is not included withgets while with fgets it is.
Second, gets does not let you specify a limit on how many characters are to be read, so you must be careful with the size of the array pointed by str to avoid buffer overflows.
先来看看gets()的问题(对应于英文的Second,很多人很熟悉了吧):
也许老谭没有讲,也许K&R C没有讲。但是只要你愿意再深入C一点,你翻开《CSAPP》,你翻开《C专家编程》
里面都会很严肃地告诉你,gets()函数有重大隐患,曾引起了无数的内存溢出攻击。
因为gets不对输入长度进行检查和限制,如果输入长度超出了字符数组,gets会向内存继续写入,产生意想不到的问题。
好的,这个时候这些书,或者大神们都会告诉你,用fgets()替代gets()。
那么是不是简单限制字数就完了呢?情况不是这样的。
再说gets()的烦人之处(对应于英文的First):
当下的很多命令行系统都是采取行扫描方式,一次回车,送一次输入。
通常来说这个回车符都是不会读取到变量里的。可是fgets是个例外。
做一个简单打开文件示例时这个问题凸显了出来:
#include <stdio.h> int main() { FILE *fp; char name[40]; fgets(name, 40, stdin); if ( (fp = fopen(name, "rb")) == NULL) { perror("open file"); return -1; } fclose(fp); return 0; }
printf打印name字符串没有发现问题。输出是“test.s”。
于是用GDB调试这段代码,在跟踪name内容时,发现了问题:
(gdb) s
test.s
10 if ( (fp = fopen(name, "rb")) == NULL)
1: name = "test.s\n\000\261\205\004\bP\204\004\b\000\000\000\000\333;\026\000$\263*\000\364\257*\000U<\026\000\231\205\004\b"
果然\n一并被吞了进去。
修改如下:
#include <stdio.h> int main() { FILE *fp; char name[40], buf[40]; fgets(buf, 40, stdin); memcpy(name, buf, strlen(buf) - 1); if ( (fp = fopen(name, "rb")) == NULL) { perror("open file"); return -1; } fclose(fp); return 0; }
(如果你又更好的办法去\n,欢迎留言)
(完)