【问题标题】:undefined behaviour while using fgetc(stdin)使用 fgetc(stdin) 时未定义的行为
【发布时间】:2018-08-21 06:36:25
【问题描述】:

在问这个问题之前,我已经阅读:fgetc(stdin) in a loop is producing strange behaviour。我正在编写一个程序来询问用户是否要退出。这是我的代码:

#include<stdio.h>
#include<stdlib.h>

int ask_to_exit()
{
    int choice;
    while(choice!='y'||choice!='n')
    {   printf("Do you want to continue?(y/n):");
        while((fgetc(stdin)) != '\n');
        choice = fgetc(stdin);
        if(choice=='y') return 0;
        else if(choice=='n') return 1;
        else printf("Invalid choice!\n");
    }
}

int main()
{
    int exit = 0;
    while(!exit)
    {
        exit = ask_to_exit();
    }
    return 0;
}

由于 fflush(stdin) 是未定义的行为,我没有使用它。在遵循另一个问题中的解决方案后,我仍然收到错误消息。下面是上述程序的试运行:

$./a.out
Do you want to continue?(y/n):y<pressed enter key>
<pressed enter key>
Invalid choice!
Do you want to continue?(y/n):y<pressed enter key>
<pressed enter key>
Invalid choice!
Do you want to continue?(y/n):n<pressed enter key>
<pressed enter key>
Invalid choice!
Do you want to continue?(y/n):n<pressed enter key>
n<pressed enter key>
<program exits>

【问题讨论】:

  • 使用choice变量而不初始化它!
  • 这有关系吗??我正在检查 while(choice!='y'||choice!='n') ,所以即使它没有初始化,它也不会是 'y' 或 'n',所以它应该可以工作,对吧?
  • do... while() 循环更适合这种情况,而不是while 循环。
  • 是的,这很重要。使用未初始化的局部变量是未定义的行为
  • choice!='y'||choice!='n'总是为真。如果是一个,那不可能是另一个。如果两者都不是,仍然是正确的。如果是两者,请致电您的大学天体物理系,因为您发现了一个虫洞。

标签: c stdin fgetc fflush


【解决方案1】:

我在您的代码中看到以下问题。

  1. 您在初始化之前使用的是choice
  2. 在将任何内容读入 choice 之前,您正在跳过一行输入。

@WhozCraig 注意到的错误:

choice!='y'||choice!='n' 始终为真。

我建议:

int ask_to_exit()
{
   int choice;
   while ( 1 )
   {
      printf("Do you want to continue?(y/n):");
      choice = fgetc(stdin);
      if ( choice == 'y' )
      {
         return 0;
      }
      if ( choice == 'n' )
      {
         return 1;
      }

      printf("Invalid choice!\n");

      // Skip rest of the line.
      int c;`
      while( (c = fgetc(stdin)) != EOF && c != '\n');

      // If EOF is reached, return 0 also.
      if ( c == EOF )
      {
         return 0;
      }
   }
}

【讨论】:

  • 返回值没问题,0y返回,这使得while(!exit)为真,所以程序继续。为n 返回1 导致while(!exit) 为假,程序退出。
【解决方案2】:

您需要在检查choice 的值之前获取一些输入,否则它将被未初始化。而且,在抓取第一个字符之前,您正在耗尽剩余的输入,您应该在之后进行:

int ask_to_exit()
{
    int choice;

    do
    {
        printf("Do you want to continue?(y/n):");
        choice = fgetc(stdin);

        while (fgetc(stdin) != '\n');

        if (choice == 'y') {
            return 0;
        } else if (choice == 'n') {
            return 1;
        } else {
            printf("Invalid choice!\n");
        }
    } while (1);
}

输出:

Do you want to continue?(y/n):g
Invalid choice!
Do you want to continue?(y/n):h
Invalid choice!
Do you want to continue?(y/n):j
Invalid choice!
Do you want to continue?(y/n):k
Invalid choice!
Do you want to continue?(y/n):m
Invalid choice!
Do you want to continue?(y/n):y
Do you want to continue?(y/n):y
Do you want to continue?(y/n):y
Do you want to continue?(y/n):n
Press any key to continue . . .

【讨论】:

  • 那个||应该是&amp;&amp;
  • 更改后|| to && 还是一样的问题。
  • @WhozCraig...true 这是正确的逻辑,但由于yn 都会导致函数返回,所以一个简单的true 进行while 检查实际上是最好的
  • 检查这个:ideone.com/LFCbwn。它与您建议的代码相同。仍然无法正常工作。
  • 您尝试了我的确切代码还是只是修改了您的代码以匹配我的?也许您忘记将while (fgetc(stdin)... 代码移到choice = fgetc(stdin); 之后
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-08-17
  • 2014-02-06
  • 2014-05-13
  • 1970-01-01
  • 2014-05-01
  • 2015-10-12
相关资源
最近更新 更多