2017-09-07 40 views
-2

只是一个简单的程序,需要10个整数并告诉我哪个最大。这是我第一次使用C语言编写,尽管我之前编写过Java,Python和Ruby。如果我输入一个字符而不是一个整数,它将只进入一个无限循环。它将当前变量设置为-8995460(或类似的东西),然后重复那个无限广告。我在某个地方犯了一个愚蠢的错误,还是我对C不了解?程序被困在无限循环中,无法找出原因

int main(void) 
{ 
    int counter = 0; 
    int largest = 0; 
    while (counter != 10) 
    { 
     int current; 
     printf("%s", "Enter non-negative number: "); 
     scanf_s("%d", &current); 
     if ((current >= 0) && (isdigit(current))) 
     { 

      if (current > largest) 
      { 
       largest = current; 
      } 
      counter++; 
     } 
     else 
     { 
      puts("Invalid number. Number must be positive. \n"); 
     } 

    } 
    printf("%d", largest); 
} 
+0

您是否检查'scanf'返回的值?你为什么认为'current'包含有效数据? –

+0

直到你写出10位数的** ASCII代码** ... –

+0

@WilliamPursell yes我在描述中说过它会返回一个非常大的负值(-8995460) – Andrew

回答

0

As @SomeProgrammerDude pointed outisdigit检查一个字符是否是数字。你传递一个整数。它会将该整数解释为字符,因此它会认为10是换行符,而43+。如果你给它50它会通过,因为那是字符2。如果scanf失败,请检查current,因为那将包含垃圾。相反,请检查返回值scanf,它会告诉您它匹配了多少个项目。

int counter = 0; 
int largest = 0; 

// It's safer to check for X < BOUND than X != BOUND in case 
// X happens to go over the BOUND. 
while (counter < 10) { 
    int current; 
    printf("%s", "Enter non-negative number: "); 

    // What if `scanf` didn't get a number? 
    if(scanf("%d", &current) != 1) { 
     puts("That doesn't look like a number"); 
    } 
    // What if it isn't positive? 
    else if(current < 0) { 
     puts("Invalid number. Number must be positive. \n"); 
    } 
    // Now that all the error conditions have been checked... 
    else { 
     if (current > largest) 
     { 
      largest = current; 
     } 
     counter++; 
    } 
} 
printf("%d", largest); 

但仍然存在问题。如果你得到一个无效的数字,代码将进入无限循环。这是many, many, many problems with scanf之一,特别是this one

问题是scanf不读取行,它的读数与您告诉的一样多。如果它读不了那么多,它就把它留在缓冲区中。如果scanf失败,则会在stdin上留下输入。当你再次阅读时,你会看到相同的输入并再次失败。如果线路上有任何额外输入,如10 foo它将读取10,然后将foo保留在缓冲区中,以便在下一次拨打电话时读取scanf

一般的解决方案是逐行读取输入并解析行。使用fgets读取该行并使用sscanf扫描字符串。

int counter = 0; 
int largest = 0; 
char line[255]; 
while (counter < 10) { 
    int current; 

    printf("%s", "Enter non-negative number: "); 
    fgets(line, sizeof(line), stdin); 

    if(sscanf(line, "%d", &current) != 1) { 
     puts("That doesn't look like a number"); 
    } 
    ...and the rest is the same... 
} 

这保证你永远不会陷入无限循环。尽管如果输入大于line,它可能需要循环几次以获得所有输入。

+0

这是...烦人的哈哈。谢谢你的解释。 – Andrew

+0

@Andrew不客气。 'scanf'只是许多诱人但是很危险的标准C函数之一。 – Schwern

3

您阅读整数不是一个字符。 isdigit检查字符是否是数字。如果current是一个单位数字,那么由于是一个单位数字,所以肯定是一个“数字”。

正因为如此,在isdigit函数总是返回0(除非你输入对应的当前字符编码值数位的小数值),这等于在C假的,所以你永远不会增加counter

对于您的问题,我会使用"%u"格式到scanf来读取一个无符号的十进制数,并检查scanf返回以查看输入是否正确。

请注意,如果输入不正确,它将留在输入缓冲区中,以便下一次拨打scanf,除非您将其删除。删除它的唯一便携方法是逐字读取字符,直到您阅读换行符。

+0

好吧,但是当我删除isdigit时,我仍然遇到同样的问题。 O我不知道它会把它留在输入缓冲区中。所以我需要从scanf中删除不正确的东西。谢谢 – Andrew

1

isdigit()用于检查一个字符的ASCII码是否为 等效的ASCII编码,从0-9开始。你应该只用 和一个字符变量。

scanf(“%d”,& current)将始终读取一个整数到变量current。你不需要检查它。如果 在输入中输入一个字符,将会出现无限循环,因为scanf() 无法将字符存储在任何变量中,即它没有得到所期望的内容。

您可以通过编写 的scanf( “%S”,& STR),其中str是一个字符数组(串),而不是scanf_s( “%d”,&电流)绕过这个无限循环的问题。 现在您可以检查第一个字符,即isdigit(str [0])。 如果不是数字,则跳过它 使用atoi()函数将其转换为数字。

#include<stdio.h> 
#include<ctype.h> 
#include<stdlib.h> 
#define BUF_LEN 256 
int main() 
{ 
    int counter = 0; 
    int largest = 0; 
    while (counter != 10) 
    { 
     char str[BUF_LEN]; 
     printf("%s", "Enter non-negative number: "); 
     scanf("%s", str); 
     if (isdigit(str[0]))//If first character is a digit then we asume that str contains a valid number. You should actually check it for all the characters in the string. 
     { 
      int current = atoi(str);//Convert string to integer (ASCII to Integer). 
      if (current > largest) 
      { 
       largest = current; 
      } 
      counter++; 
     } 
     else 
     { 
     puts("Invalid number. Number must be positive. \n"); 
     } 

    } 
    printf("%d", largest); 
}