2013-05-22 87 views
0

我一直在学习C,并且已经从C Primer书中重新编写了一个程序。我希望有一组新的眼睛可能会发现我遇到的一个问题。正如你可以看到我的输出与预期的输出,我想摆脱“0是一个数字”的行。我相信对while循环的重新设计是个问题,但我似乎无法摆脱它,尽管我尝试了各种变化。整数验证输出

输出:

Enter some integers. Enter 0 to end. 
    1 two 3 0 4 
    1 is a number. 
    two is not an integer 
    3 is a number. 
    0 is a number. 

预期输出:

Enter some integers. Enter 0 to end. 
    1 two 3 0 4 
    1 is a number. 
    two is not an integer 
    3 is a number. 
#include <stdio.h> 
#include <ctype.h> 

int get_int(void); //validate that input is an integer 

int main(void) 
{ 
    int integers; 

    printf("Enter some integers. Enter 0 to end.\n"); 
    while (integers != 0) 
    { 
     integers = get_int(); 
     printf("%d is a number\n", integers); 
    } 
    return(0); 

} // end main 

int get_int(void) 
{ 
    int input; 
    char ch; 

    while (scanf("%d", &input) != 1) 
    { 
     while (!isspace(ch = getchar())) 
      putchar(ch); //dispose of bad input 
     printf(" is not an integer\n"); 
    }  
    return input; 
}// end get_int 
+3

请注意,您当前编写的循环不能保证完全执行。在执行循环之前''integers'可能包含0。使用未初始化的变量会导致错误。如果你使用优化和警告进行编译,GCC会报告('gcc -O3 -Wall'应该这样做;我经常使用'-Wextra')。顺便说一下,在Solaris上,IIRC的堆栈大部分为零,因此在进入程序时'整数'为零的可能性相当大。 –

回答

6

我会做的是移动电话,以get_int到while循环的条件:

int main(void) 
{ 
    int integers; 

    printf("Enter some integers. Enter 0 to end.\n"); 
    while ((integers = get_int()) != 0) 
    { 
     printf("%d is a number\n", integers); 
    } 
    return(0); 

} // end main 

您现有的代码存在的问题是,在拨打get_int()并打印该值之间,您不检查是否返回了0的定位标记。

另一种选择是在之间添加一个if (integers == 0) { break; }条件,但在我看来,在条件下进行赋值更清晰。

+0

我已经知道自己以这种方式编写这个循环,但如果最初的处理和条件比这更复杂,我认为内部“break”语句更清晰。一个例子出现很多是for(;;){c = getchar(); if(c == EOF || c == terminator)break; ...} - 你可以*完全在while条件下编写它,但只需在'&&'左边分配和测试'c'并在右边再次测试它,就像迷惑人。 – zwol

2

你是正确的怀疑,你需要重新装备的while循环。你有尝试过这样的吗?

for (;;) 
{ 
    integers = get_int(); 
    if (integers == 0) break; 
    printf("%d is a number\n", integers); 
} 

此外,您get_int将得到更好的写有fgets(或getline如果可用)和strtolscanf诱人方便,但几乎总是比它的价值更麻烦。

+1

这是Knuth的“循环半结构”构造之一,您可以在'Knuth loop-and-a-half'上找到关于Google搜索的更多信息。 –

1

考虑你的循环的核心:

integers = get_int(); 
printf("%d is a number\n", integers); 

无论什么get_int()返回时,printf线将被执行。这条线需要单独if

integers = get_int(); 
if (integers != 0) printf("%d is a number\n", integers); 
+0

但是在循环体中重复循环条件是丑陋的。你所做的工作,但它是丑陋的! –

+0

@JonathanLeffler在我发布答案之前,我有一个想法。解决这个问题有多种方式:使用break(按照Zack) - 添加一行,添加一个条件,使用break(难以跟踪流imho);从代码纯化的角度来看,添加一个有条件的(就我而言)丑陋的,但容易让有人学习语言的人学习或John Ledbetter的解决方案(从代码纯化者的角度来看是理想的,但将许多功能融入其中这对于学习者来说可能更难以掌握)。买者自负! –

+0

http://www-cs-faculty.stanford.edu/~eroberts//papers/SIGCSE-1995/LoopExits.pdf提出了一个非常有说服力的论点,IMNSHO对于中间突破比任何替代品。 – zwol

2

最简单的方法是把你的条件,分配到while循环。现在你的代码依赖于在循环中设置的integer,然后再次循环检查它是否为零。

while((integer = get_int()) != 0) 

将允许您在分配整数的同时检查。不要忘记括号,否则你的整数值将是integer = (get_int != 0)的结果,因为!=在C和C++中的优先级高于=