【问题标题】:Why is my program got into an infinite loop?为什么我的程序会陷入无限循环?
【发布时间】:2023-03-22 22:16:01
【问题描述】:

我想扫描一行,直到按下换行符。我知道gets() 功能,但我想通过scanf() 学习它。问题是,我的程序陷入了一个无限循环,它扫描用户的输入,然后无限打印出来,每次扫描后它应该打印一次。谁能解释它为什么会这样?

#include<stdio.h>
int main()
{
    char str[100];
    while(str[0]!='\0')
    {
        scanf("%[^\n]",str);
        printf("%s\n",str);
    }
}

【问题讨论】:

  • 第一次测试str[0]时,它是未初始化的。 scanf 返回一个值;使用它。
  • scanf("%[^\n]",str); 第一次保持换行符。第二次及之后,被拒绝。第一次也是str[0]!='\0',使用未初始化变量。
  • “我知道 gets() 函数” - 但您知道它已过时且不应使用吗?
  • 上次我检查过,scanf 不接受正则表达式。这就是你正在做的事情。
  • 啊。我以前从未见过。谢谢指正。

标签: c string while-loop scanf infinite-loop


【解决方案1】:

如果你坚持使用scanf,那么改变格式说明符:

" %[^\n]" 

前面的空格将跳过任何以前的“悬空”\n

您还应该在检查 str 数组的内容之前对其进行初始化,最好使用 do-while-loop 代替。

这样的东西应该可以工作

char str[100] = {0};
do
{
    scanf(" %[^\n]",str);
    printf("%s\n",str);
}
while(str[0]!='q');

我个人更喜欢将fgets(...)sscanf(...) 结合使用 检查scanf的返回值也是一个好习惯,有一个返回值是有目的的。

添加另一个while条件,循环直到“q”或“quit”

【讨论】:

  • 感谢您指出格式说明符中的空格会吃掉剩下的 \n。
  • while(str[0]!='\0'); 毫无意义。
  • @BLUEPIXY 如此真实 /facepalm
【解决方案2】:

由于%[^\n] 不接受换行符,所以在第二个循环中不接受输入。

这可能会满足您的需求。

#include<stdio.h>

int main(void){
    char str[100];

    while(1== scanf("%99[^\n]%*c",str)){//%*c consumes newline. Also In case of only newline terminates the loop
        printf("%s\n",str);
    }
}

【讨论】:

  • 非常好。我不知道你可以指定 %*c。太棒了!
【解决方案3】:

BLUEPIXY 是绝对正确的。 scanf() 的第一个返回是将 \n 留在输入缓冲区中。随后的scanf() 调用将立即返回,而不会从stdin 读取任何字符,因为scanf()\n 上停止读取。于是出现了一个循环。避免循环的一种方法是在调用scanf() 后从输入中读取\n,如下所示:

#include <stdio.h>

int main()
{
    char str[100] = {0};

    do
    {
        scanf("%[^\n]",str);
        getchar();
        printf("%s\n",str);
    }while( str[0] != '\0' );
}

您似乎对输入的工作原理有一些错误的看法。所以我会在下面解释。

您不需要在循环中执行此操作,因为当您指定字符串格式时,scanf() 不会一次读取并返回一个字符。终端的输入是buffered。当您要求scanf() 返回一个字符串时,终端只会在收到newline 时将输入字符串发送给scanf()。当这种情况发生时,scanf() 返回没有newline 的字符串。

您需要做额外的工作才能关闭终端线路缓冲。下面的示例代码显示了如何关闭终端 I/O 缓冲。

#include <stdio.h>
#include <unistd.h>
#include <termios.h>

int main()
{
    struct termios old_tio, new_tio;
    unsigned char c;

    /* get the terminal settings for stdin */
    tcgetattr(STDIN_FILENO,&old_tio);

    /* we want to keep the old setting to restore them a the end */
    new_tio=old_tio;

    /* disable canonical mode (buffered i/o) and local echo */
    new_tio.c_lflag &=(~ICANON & ~ECHO);

    /* set the new settings immediately */
    tcsetattr(STDIN_FILENO,TCSANOW,&new_tio);

    do {
         c=getchar();
         printf("%c ",(char)c);
    } while(c!='q');

    /* restore the former settings */
    tcsetattr(STDIN_FILENO,TCSANOW,&old_tio);

    return 0;
}

【讨论】:

  • 感谢您的反对。我意识到我最初的回答并没有真正回答这个问题。我相信我的回答现在有效。
猜你喜欢
  • 2017-11-08
  • 2016-04-08
  • 2010-11-01
  • 2020-07-13
  • 2019-12-23
  • 2020-01-08
  • 2019-10-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多