gets() fgets()

首先自问自答,错!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.}  

我的目录下有一个叫test.s的文件。但是我输入之后却出现了错误信息open file: No such file or directory。

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又对了

 windows的换行符是\r\n,linux的换行符只有\n,在windows系统下用gets会吞掉每一行最后面的\r\n,但是linux下用gets只会吞掉最后一个\n 
 那么问题来了,如果数据是在windows环境下构造的,换行符用的是\r\n,但是服务器是linux,管理员直接把windows下生成的数据没经过任何处理就移动到了linux的服务器里 ,
 那么在oj的测评时,每一行的最后都会多一个\r,所以有时候会稀里糊涂的wa
所以,这里的gets()的使用一定要注意,能不用就不用,但是这里也有一种处理方法
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;  
}  





你可能感兴趣的:(c/c++)