虽然循环卡在无限循环中,我不知道为什么

时间:2015-09-23 17:02:52

标签: c while-loop infinite-loop

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

int main(int argc, char * argv[])
{
   printf("This program tests your integer arithmetic skills.\n"
          "You should answer the questions following the same \n"
          "rules that computers do for integers arithmetic, not \n"
          "floating-point arithmetic. Hit the 'Enter' key after \n"
          "you have typed in your input. When you wish to finish \n"
          "the test, enter -9876 as the answer to a question.\n"
          "\n");

   int n1, n2, answer, user_answer, a, b, int_per;
   char op, c;
   float per, count, count_r, count_w;

   count = 0;
   count_r = 0;
   count_w = 0;

   printf("What is your question? ");
   scanf("%d %c %d", &n1, &op, &n2);


   do
   {
      count++;

      printf("What is %d %c %d ? ", n1, op, n2);

      if (op == '+')
      {
         answer = n1 + n2;
      }
      else if (op == '-')
      {
         answer = n1 - n2;
      }
      else if (op == '%')
      {
         answer = n1 % n2;
      }
      else if (op == '/')
      {
         answer = n1 / n2;
      }
      else if (op == '*')
      {
         answer = n1 * n2;
      }

      c = scanf("%d", &user_answer);

      if (user_answer == answer)
      {
         printf("Correct!\n\n");
         count_r++;

      }
      else if (user_answer == -9876)
      {
         count = count - 1;
         break;  
      }
      else if (c != 1)
      {
         printf("Invalid input, it must be just a number\n\n");
         printf("What is %d %c %d ? ", n1, op, n2);
      }
      else if (user_answer != answer)
      {
         printf("Wrong!\n\n");
         count_w++;
      }

   } while(user_answer != -9876);

   per = (count_r / count) * 100;

   a = (int) count_r;
   b = (int) count_w;
   int_per = roundf(per);

   printf("\nYou got %d right and %d wrong, for a score of %d%c\n", a,
          b, int_per, 37);

   return EXIT_SUCCESS;

}

上面的代码应该循环询问问题然后回答,直到用户输入-9876作为答案然后程序终止并给他们他们的分数。这一切都有效除了!!一件事。当用户在输入中输入非数字时。当发生这种情况时,应该说“无效输入,请再试一次”然后再问同样的问题。例如

你的问题是什么?的 9 + 9

什么是9 + 9? 嗯,8

输入无效,请再试一次

什么是9 + 9?

所以...用户输入了“嗯”而不是再次提示用户使用相同的问题然后正确扫描它只是跳进一个无限循环。我想知道如何解决这个问题。

由于

3 个答案:

答案 0 :(得分:2)

在通话中

c = scanf("%d", &user_answer);

%d转换说明符期望看到一个十进制数字字符序列;它将告诉scanf跳过任何前导空格,然后读取十进制数字字符直到第一个非十进制数字符,然后转换并将结果保存到user_answer。如果输入 1 2 a 输入scanf将读取并使用{{1 }和'1'字符,将值'2'分配给12并返回1(对于一次成功的转换和分配),在输入流中保留user_answer和换行符。

当您键入'a'时,第一个非空白字符不是十进制数字,因此"hmmm"将其保留到位,不会向scanf分配任何内容,并返回{ {1}}。对具有user_answer转化说明符的0的所有剩余调用都将执行相同的操作。

因此,您需要确保scanf成功,如果没有,请在进行另一次阅读之前清除输入流中的所有字符,如下所示:

"%d"

在我的第一个示例中,您会注意到scanf转换说明符接受了输入if ( (c = scanf( "%d", &user_answer ) ) == 0 ) { /** * input matching failure, clear stray characters from input stream * up to the next newline character */ while ( getchar() != '\n' ) ; // empty loop } else if ( c == EOF ) { // error occurred during input operation } else { // do something with user_answer } ;它转换并将%d分配给"12a",将12字符留在输入流中以填充下一个读取。理想情况下,你想完全拒绝这些形式错误的输入。您可以执行以下操作:

user_answer

另一种选择是将输入作为文本读取,然后使用'a'库函数将其转换为结果类型:

/**
 * Repeatedly prompt and read input until we get a valid decimal string
 */
for( ;; ) 
{
  int c, dummy;
  printf("What is %d %c %d ? ", n1, op, n2);

  if ( ( c = scanf("%d%c", &user_answer, &dummy ) == 2 )
  {
    /**
     * If the character immediately following our numeric input is
     * whitespace, then we have a good input, break out of the read loop
     */
    if ( isspace( dummy ) )
      break;
    else
    {
      fprintf( stderr, "Non-numeric character follows input, try again...\n" );
      while ( getchar() != '\n' )
        ; // empty loop body
    }
  }
  else if ( c == 1 )
  {
    /**
     * No character following successful decimal input, meaning we
     * hit an EOF condition before any trailing characters were seen.  
     * We'll consider this a good input for our purposes and break
     * out of the read loop.
     */
    break;
  }
  else if ( c == 0 )
  {
    /**
     * User typed in one or more non-digit characters; reject the input
     * and clear out the input stream
     */
    fprintf( stderr, "Non-numeric input\n" );

    /**
     * Consume characters from the input stream until we see a newline.
     */
    while ( ( getchar() != '\n' )
      ; // empty loop body
  }
  else
  {
    /**
     * Input error or EOF on read; we'll treat this as a fatal
     * error and bail out completely.
     */
    fprintf( stderr, "Error occurred during read, panicking...\n" );
    exit( 0 );
  }
}

这是我首选的方法。

其中一个混乱将取代线

strtol

在阅读了你可能正在思考的所有内容之后,“C中的交互式输入确实是一种痛苦”。你是对的。

答案 1 :(得分:1)

如果在读取输入时出错,则应在尝试读取更多用户输入之前清除错误状态并跳过其余部分。

替换行:

  else if (c != 1)
  {
     printf("Invalid input, it must be just a number\n\n");
     printf("What is %d %c %d ? ", n1, op, n2);
  }

通过

  else if (c != 1)
  {
     printf("Invalid input, it must be just a number\n\n");

     // Clear the error states.
     clearerr(stdin);

     // Skip the rest of the line
     skipRestOfLine(stdin);

     printf("What is %d %c %d ? ", n1, op, n2);
  }

其中skipRestOfLine()可以实现为:

void skipRestOfLine(FILE* stream)
{
   int c;
   while ( (c = fgetc(stream)) != '\n' && c != EOF );
}

答案 2 :(得分:-1)

scanf("%d%c%d",&n1, &op, &n2) use this code