2011-11-07 92 views
0

嗯,我有这样的代码,以找到一个房间的油漆质量。SCANF不断循环

void get_room_size(char room_id, int * length, int * width) { 
    while (*length <= 0 && *width <= 0) { 
     printf("Enter length and width of room %c in feet: ", room_id); 
     if (scanf("%d,%d", length, width)) { 
      if (*length <= 0) { 
       printf("###Error! Length must be a positive value!\n"); 
      } 
      if (*width <= 0) { 
       printf("###Error! Width must be a positive value!\n"); 
      } 
      printf("\n"); 
     } else { 
      printf("bad data"); 
      *length = 0; 
      *width = 0; 
     } 
    } 
} 

基本上,如果我进入

一,1

它会发疯,并不断循环。有什么问题?

+0

你有没有代码,可以读取“一个',所以它永远不会被读取。 –

回答

5

的原因,它是怎么回事“疯狂”如下。当scanf失败a作为数字读取(因为它不是数字,很明显),它不会前进文件指针。

这就是为什么你不应该一般使用scanf操作,故障可能离开文件指针在一个不确定的位置(例如,如果你只在3月12日的项目扫描)。

的另一个原因是,scanf意思是“扫描格式化”,你将很难找到什么比用户输入更多格式化

不管怎样,回到失败。由于文件指针不先进,下次你再来做fscanf,它会尝试读取a再次(又一遍)。

如果你想为处理用户输入一个体面的功能,那没有比这里:

#include <stdio.h> 
#include <string.h> 

#define OK  0 
#define NO_INPUT 1 
#define TOO_LONG 2 
static int getLine (char *prmpt, char *buff, size_t sz) { 
    int ch, extra; 

    // Get line with buffer overrun protection. 
    if (prmpt != NULL) { 
     printf ("%s", prmpt); 
     fflush (stdout); 
    } 
    if (fgets (buff, sz, stdin) == NULL) 
     return NO_INPUT; 

    // If it was too long, there'll be no newline. In that case, we flush 
    // to end of line so that excess doesn't affect the next call. 
    if (buff[strlen(buff)-1] != '\n') { 
     extra = 0; 
     while (((ch = getchar()) != '\n') && (ch != EOF)) 
      extra = 1; 
     return (extra == 1) ? TOO_LONG : OK; 
    } 

    // Otherwise remove newline and give string back to caller. 
    buff[strlen(buff)-1] = '\0'; 
    return OK; 
} 

这将用户的输入线,防溢保护(不像getsscanf无界"%s")。

这也刷新到行结束时,如果输入太长,这将影响下次输入操作停止线的其余部分。

然后,您可以sscanf缓冲你的心脏的内容没有任何的担忧重新文件指针。

下面的测试程序演示了如何使用这样的:

int main (void) { 
    int rc; 
    char buff[10]; 

    rc = getLine ("Enter string> ", buff, sizeof(buff)); 
    if (rc == NO_INPUT) { 
     // Extra NL since my system doesn't output that on EOF. 
     printf ("\nNo input\n"); 
     return 1; 
    } 

    if (rc == TOO_LONG) { 
     printf ("Input too long [%s]\n", buff); 
     return 1; 
    } 

    printf ("OK [%s]\n", buff); 

    return 0; 
} 

顺便说一句,你可能要重新审视你的逻辑,有效大小的房间。你现在有将允许一个房间由-42英尺:-)

输入为7这也是通常不是好的形式依靠输出值被设定为在进入特定的值。如果输入时长度和宽度为(例如)3和4,则此功能将立即退出,而不要求用户输入。

第一个问题可以通过使用||代替&&被固定。第二种方法是在函数开始时将变量初始化为0,以便输入循环。


为了完整起见,如果你把该原始片段上方具有以下(在include报表及getLine()功能)略作修改get_room_size()功能:

static void get_room_size(char room_id, int * length, int * width) { 
    char buff[100]; 
    *length = *width = 0; 
    while ((*length <= 0) || (*width <= 0)) { 
     printf("Enter length and width of room %c in feet: ", room_id); 
     int rc = getLine (NULL, buff, sizeof (buff)); 

     if (rc == NO_INPUT) { 
      printf ("\nEnd of file encountered.\n"); 
      return; 
     } 

     if (rc == TOO_LONG) { 
      printf ("\nInput too long, please retry.\n"); 
      continue; 
     } 

     if (sscanf(buff, "%d,%d", length, width) != 2) { 
      *length = *width = 0; 
      printf ("\nInput not in desired form (<number>,<number>), " 
       "please retry.\n"); 
      continue; 
     } 

     if ((*length <=0) || (*width <= 0)) { 
      *length = *width = 0; 
      printf ("\nBoth length and width must be greater than zero, " 
       "please retry.\n"); 
     } 
    } 
} 

和非常简单的测试main(),你”我将看到一个完整的程序,展示如何去做。

int main (void) { 
    int len, wid; 
    get_room_size ('x', &len, &wid); 
    printf ("Length is %d, width is %d.\n", len, wid); 
    return 0; 
} 
+0

读取一个字符串,然后尝试将其解析为一个int。 –

0

您的scanf采取两个整数。 A是一个字符,认为你想要 scanf(“%c”,* room_id); scanf(“%d”,length);

我reccommend你单独做他们

+0

我怀疑房间ID是已知的,因为它已经被传入(并且_not_作为可以被改变并传回的指针),并且它被用在'printf'中。 – paxdiablo

0

试试这个:

... 
     if (scanf("%d,%d", length, width) == 2) { 
      if (*length <= 0) { 
       printf("###Error! Length must be a positive value!\n"); 
      } 
      if (*width <= 0) { 
       printf("###Error! Width must be a positive value!\n"); 
      } 
      printf("\n"); 
     } else { 
      printf("bad data"); 
      *length = -1; 
      *width = -1; 
     } 
+0

这仍然会在'a,1'上循环,因为它不会超过原始代码的前进文件指针。 – paxdiablo

+0

关键是要正确检查scanf()的状态! – paulsm4

-1

你不把&在scanf()语句,因此如何其读

if (scanf("%d,%d", &length, &width)) 
+0

在你的scanf()语法中试试这个家伙的错误。 –

+1

这不是问题...... scanf已指向长度和宽度。 – TheAJ