2013-06-02 161 views
3

在第5行中,我读取整数并且isint在读取整数时获取1,如果不是整数则为0。如果isint是0我有一个循环要求用户给一个整数,我读直到用户给出一个整数。我尝试给出一个字符而不是一个整数的代码,但我有一个无限循环。该程序只是不等待给一个新的输入。我的代码有什么问题?为什么scanf在无效输入中陷入无限循环?

#include <stdio.h> 

int main(void) { 

    int arg1; 
    //int arg2; 
    int attacknum = 1; 
    int isint = 1; 

    //printf("Insert argument attacks and press 0 when you have done this.\n"); 
    printf("Attack %d\n", attacknum); 
    attacknum++; 
    printf("Give attacking argument:"); 
    isint = scanf("%d", &arg1); //line 5 

    while(isint == 0){ 
    printf("You did not enter a number. Please enter an argument's number\n"); 
    isint = scanf("%d", &arg1); 
    printf("is int is %d\n", isint); 
    } 
    return 0; 
} 
+0

printf(“is int is%d \ n”,isint)的输出是什么? – Xonar

+0

请提供您场景的控制台输出。 – zsawyer

回答

10

正如其他人所说,如果scanf无法解析输入,它会使其未被扫描。

一般来说scanf是交互式输入的一个糟糕的选择,因为这种行为,并且因为它与用户遇到的一次一行的界面不匹配。

您最好使用fgets将一行读入缓冲区。然后使用sscanf解析该行。如果你不喜欢这个输入,那就把整条线扔掉,再读一遍。

事情是这样的:

#include <stdio.h> 

int main(void) 
{ 
    char line[256]; 

    int arg1; 
    int isint; 

    while (1) { 
    printf("Give attacking argument:"); 
    fgets(line, sizeof line, stdin); 
    isint = sscanf(line, "%d",&arg1); 
    if (isint) break; 

    printf("You did not enter a number.Please enter an argument's number\n"); 
    } 

    printf("Thanks for entering %d\n", arg1); 

    return 0; 
} 

(对于生产代码,你要处理大排长龙,检查返回代码,还要检查该号码后尾随垃圾等)

其实,一个更好的方法是不使用scanf如果你只是想读一个整数,而是使用strtol。这给你一个方便的指针,指向数字后面的字符,并且你可以检查它是否是空格或nul。

+1

这仍然会接受像'123ab'这样的输入作为'123'。使用for循环在行内搜索无效字符是个不错的主意,请参阅相同的问题:http://stackoverflow.com/questions/20829672/why-this-example-is-stuck-in-an-infinite- loop-in-c – ilgaar

+0

检测是否存在尾随垃圾是一个好主意。如同在这个问题中那样,通过手动扫描字符串来做到这一点是一种非常漫长而不雅的方式。最好只使用['strtol'](http://man7.org/linux/man-pages/man3/strtol.3.html),它给你一个指向下列字符的指针。 – poolie

4

scanf面临着一个非数字字符也不会消耗任何输入和返回零个整数宣读。非数字将保留在下一个呼叫scanf的输入中,其行为与第一次呼叫相同,等等。

回答下面的问题。您可以使用fgetc解析至少一个字符,但这会为每个已输入字符提供错误消息。通常我认为你想跳过直到换行。为此,您可以使用poolie建议的fgets。或者您可以在scanf之后添加以下内容。

int ch; 
if (isint == 0) 
while ((ch = fgetc(stdin)) != EOF && ch != '\n') 
{ 
    /* Skip characters */ 
} 

P.S:在你的情况下,它可能是更好的把它只是在循环中的第一printf之前。

+0

你有什么建议来解决这个问题?我如何消费非数字? – Dchris

+0

@Dchris我加了一些建议。 –

+1

@Dchris你做了哪些研究?你是否认真对待这个问题?你为什么不看书? – Sebivor