2013-05-22 133 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++中的優先級高於=