2011-02-08 65 views
3

這是一個家庭作業分配一些給定的字符串。我提示用戶輸入他們想要排序的字符串數量scanf,根據該數字分配數組,然後使用fgets獲取字符串本身。scanf和fgets的問題

一切工作正常,如果字符串的數量是硬編碼的,但增加了scanf讓用戶決定把事情搞砸。下面的代碼:

#include <assert.h> 
#include <stdio.h> 
#include <stdlib.h> 

#define LENGTH 20 // Maximum string length. 

int main(void) 
{ 
    int index, numStrings = 0; 
    char **stringArray; 
    printf("Input the number of strings that you'd like to sort: "); 
    assert(scanf("%d", &numStrings) == 1); 
    stringArray = (char **)malloc(numStrings * sizeof(char *)); 

    for (index = 0; index < numStrings; index++) 
    { 
     stringArray[index] = (char *)malloc(LENGTH * sizeof(char)); 
     assert(stringArray[index] != NULL); 
     printf("Input string: "); 
     assert(fgets(stringArray[index], LENGTH, stdin) != NULL); 
    } 

    // Sort strings, free allocated memory. 

    return 0; 
} 

而這裏的控制檯的樣子:

 
Input the number of strings that you'd like to sort: 3 
Input string: Input string: foo 
Input string: bar 

它會跳過循環的第一次迭代,導致在數組的開頭空字符串。我的問題是,爲什麼會這樣做,我該如何解決?


這裏是控制檯看起來與傳遞給scanf格式字符串"%d\n"

 
Input the number of strings that you'd like to sort: 3 
foo 
Input string: Input string: bar 
Input string: baz 

所以,我可以輸入的所有字符串的,但對於一個字符串的第一個提示是放錯了地方。

+4

請勿對可能合理預期失敗的函數(如讀取用戶輸入的輸入函數)進行`assert()`。這比忽略錯誤要好。它不如處理錯誤理智。 – 2011-02-08 04:08:25

+0

@Jonathan感謝您的建議。 – gdejohn 2011-02-08 04:30:22

回答

3

真正的答案(在我的謙虛,但永遠是這麼正確的意見:P)是不要使用scanf。使用fgets來讀取第一行(即數字),然後使用sscanfstrtoul來解析該字符串。這樣,當有人沒有以很好的格式輸入數據時,你就有能力處理錯誤,並且你不必破解scanf缺乏可靠的空白處理。

此外,從未使用過int來存儲大小,除非您希望有大量長度爲-4的數組。該標準將無符號類型size_t指定爲無符號類型,其大小足以存儲對象大小和數組索引。使用任何其他類型不能保證工作。

6

你必須告訴scanf函數通過把\ n在scanf函數給揍成\ n:

scanf("%d\n", &numStrings) 

沒有它,scanf函數會讀取剩餘換行符[從當輸入按鈕被擊中]作爲在迴路中的第一行

+1

還有一些意見可以添加到Foo Bah的答案中:代碼中的一個問題是,您不應該在`assert`中使用任何副作用; `assert`內的東西不能在發佈模式下運行。您可能還想在`printf`後加`fflush(stdout);`以確保在用戶被要求輸入之前打印提示。 – 2011-02-08 03:54:16