首先自问自答,错!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
2.
3.int main()
4.{
5. FILE *fp;
6. char name[40];
7.
8. fgets(name, 40, stdin);
9.
10. if ( (fp = fopen(name, "rb")) == NULL)
11. {
12. perror("open file");
13. return -1;
14. }
15.
16. fclose(fp);
17. return 0;
18.}
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
2.
3.int main()
4.{
5. FILE *fp;
6. char name[40], buf[40];
7.
8. fgets(buf, 40, stdin);
9. memcpy(name, buf, strlen(buf) - 1);
10.
11. if ( (fp = fopen(name, "rb")) == NULL)
12. {
13. perror("open file");
14. return -1;
15. }
16.
17. fclose(fp);
18. return 0;
19.}
以上转载于
http://blog.csdn.net/qwb492859377/article/details/48323443
接下来是 ACM中使用gets()函数所遇到的问题
有没有这样的经历,用gets会稀里糊涂的wa, 但是用scanf又对了
bool safe_gets(char *S){
2. int n = strlen(S);
3. if(!gets(S)) return false;
4. if(n && S[n - 1] =='\r') S[n - 1] = 0;
5. return true;
6.}
int mygets(char s[])
{
int i = 0;
char c;
while((c = getchar()) && c != '\n' && c != EOF)
if(isalpha(c) || isdigit(c) || c == '.' || c == ',' || c == ' ')
s[i++] = c;
s[i] = '\0';
return i > 0 || c != EOF;
}