为什么这个c程序陷入无限循环?

时间:2017-06-07 10:27:40

标签: c loops while-loop scanf

#include <stdio.h>

int main()
{
  int sum=0;
  char s[10];

  while(scanf("%[^\n]s", s)!=EOF)
  {
    printf("%s", s);

  }

  return 0;
}

这个while循环落入任何字符串输入的无限循环。

2 个答案:

答案 0 :(得分:6)

鉴于

while(scanf("%[^\n]s", s)!=EOF)
{
   printf("%s", s);
}

你问“为什么这个c程序会陷入无限循环?”

因此,您必须了解scanf()的工作原理。 scanf()使用您的格式字符串来解析stdin的输入,这是一个流,逐个字符地提供

假设您在stdin中有以下内容:

foo\n
bar\n
<<EOF>>

现在,您的格式字符串具有此转换%[^\n],这意味着“匹配除换行符之外的任何内容并复制到char缓冲区”。跟随它的s只是一个文字s,因为它前面没有% ...所以它会匹配文字s,如果有的话一。换句话说,这没关系。

现在,第一次调用scanf(),它将匹配foo并使用它。它返回1,因为它匹配一个元素。之后,stdin看起来像这样:

\n
bar\n
<<EOF>>

请注意,不匹配的换行符仍然存在。您的下一个电话会以格式字符串开头,以匹配除换行符之外的任何内容,但下一个字符是换行符。 scanf()不匹配,因此会返回0。它无法返回EOF,因为您可以看到,EOF尚未到达。这是你的无限循环。

所以,你必须修复你的格式字符串。首先,删除从不匹配任何内容的s。它在这里并没有真正受到伤害,但它仍然是错误的。然后,您可以利用scanf()空白匹配。空格是 space tab newline 。如果您的格式字符串包含空格,scanf()将匹配一样多的空格(这也可以是无)。因此,一个简单的解决方法就是用空格开始你的格式字符串,这将“吃掉”剩下的换行符:

while(scanf(" %[^\n]", s)!=EOF)
{
   printf("%s", s);
}

现在这仍然是危险代码,因为只要没有换行符,[^\n]就匹配任意数量的字符,但是你的缓冲区只有9个字符的空间加上终止{{1 }}。因此,您必须告诉0不要超过该限制,这可以通过将数字放在scanf()和转换规范之间来完成:

%

此代码将以安全的方式执行您想要的操作,但假设您希望匹配更具体的内容,例如:数字,你得到一些意想不到的输入:等待while(scanf(" %9[^\n]", s)!=EOF) { printf("%s", s); } ,你会再次拥有无限循环,因为有输入不匹配,所以你永远不会到达EOF(如上面有无与伦比的换行符)。因此,请始终检查成功匹配的数量。在这里你只需要一个匹配,所以循环应该如下所示:

EOF

实际上,要阅读整行,您不需要while (scanf(" %9[^\n]", s) == 1) { printf("%s", s); } ,只需使用scanf()就会更容易。您的代码可能看起来很简单(换行符也会被读入fgets()):

s

请注意此处的第二个参数while (fgets(s, 10, stdin)) { printf("%s", s); } 10会自动说明终止fgets()字符,因此您只需指定缓冲区的大小。

最后一个提示:当没有格式化时,这可能甚至更简单而不使用0

printf()

答案 1 :(得分:-1)

int main()
{
    int sum = 0;
    char s[10];

    int ret = scanf("%[^\n]s", s);
    while (ret != EOF)
    {
        printf("%s", s);
        memset(s,0,10);
        ret = scanf("%[^\n]s", s);
    }

    return 0;
}

通过调试,您可以看到while块中的第二个ret值为0,即不等于EOF,因此无限循环。

man scanf:

返回值

成功完成后,这些函数将返回成功匹配和分配的输入项的数量;如果早期匹配失败,此数字可以为零。

这意味着另一个scanf匹配失败,除了第一个。

但为什么?

stdio有缓存,匹配只从stdin读取“\ n”,但是当你输入“Enter”时,它输入“\ n \ r”,所以,“\ r”将在stdin中缓存并成为其他scanf的输入值,但无法匹配输入,因此匹配失败。并且scanf返回0,并转到无限循环。

但是如果你只为每个输入输入“\ n”,那就OK了!

您可以按“Alt”并同时按“0”+“1”+“0”,然后释放“Alt”,控制台只会输入“\ n”,您将获得正确的结果,程序会好的,不会进入无限循环!

这是我的测试结果:enter image description here