【问题标题】:error handler in C programC 程序中的错误处理程序
【发布时间】:2014-08-06 20:55:49
【问题描述】:

我是一名 C 编程初学者,并试图在这里编写一个原始数字猜谜游戏。 (我保证这不是学校作业)。但是由于我在尝试完成整个功能时遇到了一些麻烦,我想也许我需要一点帮助。所以基本上我已经完成了这个程序的主要猜测部分:告诉用户他的猜测太高或太低或者是正确的答案。但是,如果用户输入了一些无效值,如字符或小数(他们应该只输入 1-100 的整数),我的程序只会提示用户猜测超出范围并自动循环此消息直到猜测次数用完了。我检查了我的代码,但无法弄清楚。如果有人可以给我一个线程,我将不胜感激! 代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define MAX_NUMBER 100

int main(void) {
    int randNum;
    srand((int)time(0));
    randNum = rand() % 100 + 1;

    long guessNum;
    char guessStr[80];
    guessNum = atoi(guessStr);
    int count = 0;

    do {
        printf("\nplz enter a guess from integer 1 to 100: %d", randNum);
        scanf("%ld", &guessNum);

        if (guessNum < randNum && guessNum >= 1) {
            printf("your guess is lower than the selected number");
            count++;
            printf("\nyou have %d times left to try", 100 - count);
        }
        if (guessNum > randNum && guessNum <= 100) {
            printf("your guess is higher than the selected number");
            count++;
            printf("\nyou have %d times left to try", 100 - count);
        }
        if (guessNum < 1 || guessNum > 100) {
            printf("your guess is out of the range, plz pick between 1-100");
            count++;
            printf("\nyou have %d times left to try", 100 - count);
        }
        if (guessNum == randNum) {
            printf("congrats you got the right answer");
            count++;
            printf("\nyou used %d times to make the right guess", count);
        }

    } while (count < MAX_NUMBER);
    printf("\nthe guess time is used out!");

    return 0;
}

【问题讨论】:

  • 你应该检查scanf的返回值——它会告诉你是否输入了一个有效的整数。
  • 这绝对是错误的:guessNum = atoi(guessStr);
  • 如果猜对了,你应该做点什么让你退出循环或程序。
  • @DrewMcGowen 感谢您的提示!我不知道我们能做到这一点:)

标签: c error-handling do-while


【解决方案1】:

如果scanf 检测到与转换说明符不匹配的输入(例如在需要数字的地方看到一个字母),它将在该点停止扫描并将该字符留在输入流中,在那里它会犯规进行下一次阅读,然后再进行下一次阅读。

有几种方法可以解决这个问题。

首先scanf返回成功转换和赋值的次数;例如,如果scanf 能够从输入流中读取整数值,scanf( "%d", &amp;value ); 将返回 1。因此,作为开始,我们可以检查一下:

if ( scanf( "%d", &guessNum ) == 1 )
{
  // test the value of guessNum
}
else
{
  // input wasn't a valid integer; consume input until we see a newline
  char c;
  while ( ( c = getchar() ) != '\n' )
    ;
}

这样做的一个问题是,如果您输入类似12r 的内容,scanf 将转换并分配12,同时将r 留在输入流中。理想情况下,您希望将整个输入视为错误而拒绝。您可以在输入之后立即读取字符,如下所示:

char follow;
int itemsRead = scanf( "%d%c", &guessNum, &follow );
if ( itemsRead == 2 && isspace( follow ) )
{
  // test value of guessNum
}
else
{
  // input was not an integer followed by a newline
  while ( getchar() != '\n' )
    ;
}

这可以保护您免受12r 等情况的影响。但是,仍然存在弱点。信不信由你,scanf( "%d" ) 不会

这样的输入而窒息
123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890

即使这样的值不能用原生的int 类型表示。同样,您希望能够彻底拒绝这种糟糕的输入。

第三种方法是将输入读取为文本,然后使用atoistrtolsscanf 之类的内容进行转换。我的首选方法是使用strtol,如下所示:

char input[MAX_INPUT_LEN]; // where MAX_INPUT_LEN is appropriate for a signed
                           // integer value; a 32-bit int can represent up to
                           // 10 decimal digits, plus the sign, plus the
                           // 0 terminator.

if ( fgets( input, sizeof input, stdin ) )
{
  if ( !strchr( input, '\n' ) ) // if newline is not present in the input buffer
  {
    fprintf( stderr, "Input too long!\n" );
    while ( getchar() != '\n' )
      ;
  }
  else
  {
    char *follow; // will point to first non-digit character in input
    int tmp = strtol( input, &follow, 10 ); // convert input string to equivalent
                                            // integer value; 
    if ( !isspace( *follow ) && *follow != 0 )
    {
      fprintf( stderr, "%s is not a valid integer value\n", input );
    }
    else
    {
      guessNum = tmp;
      // test value of guessNum
    }
  }
}

您会希望根据自己的需要对其进行调整(理想情况下,将大部分废话隐藏在其自己的函数中),但您应该明白这一点。

【讨论】:

  • 嗨,John 感谢您提供非常详细的解释。关于这两种特殊情况的很好的提示(上划线输入和字母数字组合输入)。我很担心他们,但现在很清楚:) 你的第三种方法非常好!这实际上也是我希望解决这个问题的方式,但是我不知道如何正确地做到这一点:) 我曾经在 Java 中这样做,它更容易。并且评估scanf的值非常酷,感觉就像在Java中使用boolean的更简洁的方式来检查scanner的值。
  • @user1579701:请注意,我在第三个示例中有错字(没有正确取消引用 follow 变量)。
【解决方案2】:

你应该使用这样的循环:

    for (int readNums = 0; readNums == 0; ) {
        printf("plz enter a guess from integer 1 to 100: %d\n", randNum);
        readNums = scanf("%ld", &guessNum);
    }

您可以消除guessStr 以及所有对它的引用,因为您实际上并没有使用它。此外,通常的 C 习惯用法是将循环退出条件放在循环的顶部。对于您的程序,这意味着您现有的 do ... while() 循环将变成这样:

while(count < MAX_NUMBER)
{ 
/* your code here */
}

最后,在游戏结束时,您会想要一种真正退出的方式。你可以这样做:

    /* other guess handling code here... */

    if(guessNum == randNum)
    {
        printf("congrats you got the right answer\n");
        count++;
        printf("you used %d times to make the right guess\n", count);
        break;
    }
}
if (guessNum != randNum)
    printf("the guess time is used out!\n");

还要注意,我使用了另一个 C 习惯用法,即将\n 放在字符串的末尾而不是开头。

【讨论】:

  • 是的,我知道我没有在程序中使用guessStr。但我只是在想,也许我应该将 guessNum 从整数转换为字符,以便它可以处理错误输入字母异常。问题是我不知道如何正确转换它所以我只是把它留在那里:)
猜你喜欢
  • 2016-08-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-21
  • 2014-06-17
相关资源
最近更新 更多