fgets() 的异常行为

Anomalous behaviours of fgets()

输入格式

第一行包含两个整数N和M,中间用一个space隔开,其中N代表人数,M代表话题数。接下来是 N 行。 每行包含一个长度为 M 的二进制字符串。如果第 i 行的第 j 个字符为 1,则第 i 个人知道第 j 个主题;否则,他不知道这个话题。

约束条件

2≤N≤500 1≤M≤500

代码

int main() 
{
    int i,j,k,m,n;
    char *str='[=10=]';
    //n - no of persons
    //m - no of topics

    //Read the m and n from console
    scanf("%d %d\n",&n,&m);

    //Allocate the memory
    str=malloc(501);


    for(i=0;i<n;i++)
    {
        fflush(stdin);
        if(fgets(str,501,stdin)!=NULL)
        {
            if(strlen(str)>0 && str[strlen(str)-1]=='\n')
                str[strlen(str)-1]='[=10=]';
        }
        printf("%s\n",str);
    }


    //Free used variables
    free(str);

    return 0;

}

示例输入 1 -

4 5
10101
11100
11010
00101

示例输出 1 -

10101
11100
11010
00101

结果:预期输出与打印输出匹配。

示例输入 2 -

4 500 
11100110111100111011001010001110110100111111100111110111100111000110110011111111001001010111111111011011110000111001101011110101011100111011001011110100011011001110110111110010111010100001111011111110110111010101101001111100010111011110011111100110011101110111100110010110111111011010110110011101001011110101110100110011010101111011101111010100011101110110101110101101010110101010111111111001100001110100011010110101110110111111111111111001100101110111110110011010011101110100010111110000000110110110    
10101010101001110011110110011101111001011001110101011101111110101011011110010100110011110111111010100001111111111010101111110110111101110101111111100010011011101010111011111010111001111110101110111011100010110101001001001101110111110111011111111101110010100110110011111100101010100001111111111010011001111101010011111110111011001001110111010111111111011011010011101101000010101010011110100111111110101011110011110001110111111011101100011100101100101111111110011101001110101011111001111100111110010001    
11111101101110110110111101101111111111110001110100111001010111011011011111011111111010010101111011000101001101110100111111111001110111111101000011110100010001010111101010111111111010111011011110000111010111101011110111100110010000001111111101101110110010010111010111100010100000010011111001100101101011101111000101110110011111110110111111111011010011001000111101101001011101011010010111100001111011001111111001110110011011111011101001001011001111111001011111011111010111010011111010100110110111111100    
11111000011111101111111101001100011011111110011110110111011111111100110100011100011111011111011111001010010110110111111000100110111101111000111101100001110000101010011001101101100011000001111010001111101011000110001111110100101001011011111010001101101110011110101001011100111100011111011110001110100100111111111110100110111011101111000011001101111000101011111001101010111100110011101100100010011111111111011110011100011111111011011110011011101110111110011111011111111101111011110111001111010001111001

示例输出 - 2

11100110111100111011001010001110110100111111100111110111100111000110110011111111001001010111111111011011110000111001101011110101011100111011001011110100011011001110110111110010111010100001111011111110110111010101101001111100010111011110011111100110011101110111100110010110111111011010110110011101001011110101110100110011010101111011101111010100011101110110101110101101010110101010111111111001100001110100011010110101110110111111111111111001100101110111110110011010011101110100010111110000000110110110
10101010101001110011110110011101111001011001110101011101111110101011011110010100110011110111111010100001111111111010101111110110111101110101111111100010011011101010111011111010111001111110101110111011100010110101001001001101110111110111011111111101110010100110110011111100101010100001111111111010011001111101010011111110111011001001110111010111111111011011010011101101000010101010011110100111111110101011110011110001110111111011101100011100101100101111111110011101001110101011111001111100111110010001

预期输出 2 - 它应该包含 4 行文本而不是输出中的 2 行。

1) 用 fflush(stdin); 清理输入缓冲区是一种不好的做法(它在任何系统中都不起作用)。如果你真的需要清理 stdin;

,最好使用像 while(getchar()!='\n'); 这样的循环

2) 如果您的行中没有 '[=14=]' 字符,则使用 strlen(str) 获取字符串大小可能会失败,因此表达式 str[strlen(str)-1]='[=15=]'; 可能会导致意外结果(据我了解,您想要如果输入很大以放置在 str 中,则设置字符串结尾 - 最好使用 str[500]='[=17=]'; 而不要使用 strlen()... 如果输入短于 500 fgets 放置 '[= 14=]' 最后);

3) 在 malloc(size) 之后你应该在使用分配的内存之前检查返回值。

  1. scanf("%d %d\n",&n,&m); 中删除 '\n''\n' 使输入复杂化。 Any whitespace 作为 scanf() 指令,如 '\n'' ''\t' 等匹配 任意个白-space。所以 scanf() 不会 return 直到 non-white-space 在 2 个数字之后输入。

  2. 不要将 scanf()fgets() 混用。而是使用 fgets() 并限定输入:

    char buf[50];
    fgets(buf, sizeof buf, stdin);  // Should also check `fgets() results
    if (2 != sscanf(buf,  "%d%d", &n, &m) || n < 2 || n > 500 || [more tests]) {
      puts("Bad input");
      return 1;
    }
    
  3. 移除fflush(stdin);.

  4. printf("%s\n",str); 放在前面的 if(fgets... 块中。

  5. 分配 502,而不是 501。+1 用于 '\n',+1 用于 '[=27=]'。这就是您上一个测试用例失败的原因。代码试图读取包含 500 char'\n' 的行,即 501 char。传递给 fgets() 的 501 为 500 char 和终止空字符 '[=27=]'.

  6. 分配了空间
  7. char *str='[=34=]';很奇怪。建议 char *str = NULL;

  8. 建议循环

    str = malloc(502);
    for(i=0;i<n;i++) {
      if(fgets(str,502,stdin)!=NULL) {
        if (strlen(str)>0 && str[strlen(str)-1] == '\n')
          str[strlen(str)-1] = '[=11=]';
        }
        printf("%s\n",str);
      }
    

您需要空间容纳 500 个字符 用于终止 \n 终止 0 .您只有 500 个字符加上终止零的空间,因此 fgets 不会读取最后的硬 return。由于它保留在输入缓冲区中,因此它会在 \n 的下一次迭代中被读取(并且它应该显示在您的输出中)。

将缓冲区大小增加到 502 以修复。更好的选择是读取第一行并根据该点的字符数分配行缓冲区大小。