getchar()实际上并不从用户那里获取输入

时间:2012-03-05 19:03:17

标签: c++ input validation stdin getchar

我正在编写一个灵活的命令行(但不是很长时间!)C ++中的菱形方形生成器。我刚刚写完用户输入的一半。但是,在最后一个命令中,输入“slip”并且换行符自动输入到getchar()。我采取了预防措施,以确保它不是任何溢出,即,冲洗stdin,并且,好的措施,stdout。问题依然存在。这是我的代码:

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

int main () {
    unsigned  long seed = 0, x = 0, y = 0, initial = 0, range = 0;
    int smooth = 0, fail = 1;
    char flagchar1 = 'n';
    printf("Welcome to my diamond-square generator! This isn't full-feature yet, so I'm just gonna have you input the variables one by one. ");
    do {
        printf("Please input the seed (this is a positive integer):\n");
        fail = scanf("%lu", &seed);
        while (fail == 0) {
            printf("Try again, smartass.\n");
            fail = scanf("%lu", &seed);
        }
        fail = 1;
        printf("Now input the x, or horizontal, size of your grid:\n");
        fail = scanf("%lu", &x);
        while (fail == 0) {
            printf("An integer. Not a string. An integer. You can do that, can't you?\n");
            fail = scanf("%lu", &x);
        }
        fail = 1;
        printf("Now input the y, or vertical, size of your grid:\n");
        fail = scanf("%lu", &y);
        while (fail == 0) {
            printf("What was that supposed to be? An integer, please.\n");
            fail = scanf("%lu", &y);
        }
        fail = 1;
        printf("Now input about how high you'd like the grid to be (this goes from a scale of 1 to 256):\n");
        fail = scanf("%lu", &initial);
        while (initial == 0 || initial > 256 || fail == 0) {
            printf("ahahahahaha how HIGH do you have to be just to HAVE that hieght........\n");
            fail = scanf("%lu", &initial);
        }
        fail = 1;
        printf("Now input the range of the heights on your grid (this must be equal to or less than 256):\n");
        scanf("%lu", &range);
        while (range >= 256 || fail == 0) {
            printf("What did I say about being equal to or less than 256? Give me something reasonable to work with here.\n");
            fail = scanf("%lu", &range);
        }
        fail = 1;
        printf("Just one more variable to go! Now, I need you to input the smoothness of your grid. Smaller numbers make spikier grids. You can make this negative, but beware!\n");
        fail = scanf("%d", &smooth);
        while (fail == 0) {
            printf("That... was not a number.\n");
            fail = scanf("%d", &smooth);
        }
        fail = 1;
        printf("\nOkay. Are these the values you want?\n   Seed:       %lu\n   Width:      %lu\n   Length:     %lu\n   Height:     %lu\n   Range:      %lu\n   Smoothness: %d\nDo you want to keep these? Type Y/n.\n", seed, x, y, initial, range, smooth);
        fflush(stdin);
        fflush(stdout);
        flagchar1 = getchar();
    } while (flagchar1 != 'y' && flagchar1 != 'Y' && flagchar1 != '\n');
}

这是我的输出,程序已经结束(如果我从&& flagchar1 != '\n'删除while(),程序只会重复整个执行循环):

    Welcome to my diamond-square generator! This isn't full-feature yet, so I'm just gonna have you input the variables one by one. Please input the seed (this is a positive integer):
    12345678
    Now input the x, or horizontal, size of your grid:
    40
    Now input the y, or vertical, size of your grid:
    30
    Now input about how high you'd like the grid to be (this goes from a scale of 1 to 256):
    1288
    ahahahahaha how HIGH do you have to be just to HAVE that hieght........
    128
    Now input the range of the heights on your grid (this must be equal to or less than 256):
    30
    Just one more variable to go! Now, I need you to input the smoothness of your grid. Smaller numbers make spikier grids. You can make this negative, but beware!
    10

Okay. Are these the values you want?
  Seed:       12345678
  Width:      40
  Length:     30
  Height:     128
  Range:      30
  Smoothness: 10
Do you want to keep these? Type Y/n.

发生了什么,我该如何解决?

P.S。我知道我的输入验证基本上没用。对此的帮助也非常感谢。

5 个答案:

答案 0 :(得分:2)

让你的循环结束如下:

    // Ignore remaining characters on current line.
    int ch;
    while( (ch = getchar()) != EOF && ch != '\n')
      ;
    // fetch first character on next line
    flagchar1 = getchar();
} while (flagchar1 != 'y' && flagchar1 != 'Y' && flagchar1 != '\n');

在您最后一次致电'\n'后,您将离开scanf进入stdin。

您不得依赖fflush(stdin)有任何特定行为。在输入流上调用fflush的结果是未定义的。见Using fflush(stdin)

答案 1 :(得分:0)

代码的行为与您告诉的完全相同。如果用户输入'y','Y'或输入,则while循环中的其中一个条件将为false,这将导致其退出。

你想要的是:

while (flagchar1 == 'y' || flagchar1 == 'Y' || flagchar1 == '\n');

编辑:我也会删除fflush(stdin)并用fgets()替换getchar()。这将保证读取整行,而不必使用fflush,这可能是问题。

答案 2 :(得分:0)

我猜你在Linux上?这适用于Windows中的VS.它提示,从键盘读取,如果检查包含正确的'y'或'Y'。

我可能会建议您尝试将最后一次扫描更改为:

fail = scanf("%d ", &smooth);

您也可以尝试调用fpurge()而不是fflush(),但这是非标准的,我认为格式字符串末尾的空格可以满足您的需求。

尾随空格将要求scanf消耗输入数据中的任何额外空格(包括换行符)。 fflush()可能不会做你想要的输入。

我怀疑你所使用的系统确实在流中留下了回车符,如果你将flagchar1作为一个int打印,你会得到10?

答案 3 :(得分:0)

建议:

  1. 使用C ++流。
  2. 在比较字符之前使用tolowertoupper
  3. 使用std::string
  4. 使用fgets, gets, fflush, strcmp,的C语言在这个领域有很多问题。 C ++语言解决了std::stream类中的许多问题。

    由于您未使用C ++功能,因此应将 C ++ 标记更改为 C

答案 4 :(得分:-1)

尝试

} while(flagchar1!='y'|| flagchar1!='Y'|| flagchar1!='\ n');

而不是

} while(flagchar1!='y'&amp;&amp; flagchar1!='Y'&amp;&amp; flagchar1!='\ n');