2016-08-22 64 views
0

我需要閱讀下列文本文件:如何使用這兩種scanf函數和與fgets讀取文件

2 2 
Kauri tree 
Waterfall 
0 0 W S 
0 1 E N 

我想用scanf獲得第一行,並使用fgets第二和第三然後再使用scanf作爲其餘行。

我寫了這樣的代碼:

#include <stdio.h> 

#define NUM_OF_CHAR 2 

int main() 
{ 
    int node, edge; 
    scanf("%d %d", &node, &edge); 

    FILE* fp; 
    fp = stdin; 

    char* str[NUM_OF_CHAR]; //should be char str[NUM_OF_CHAR]; 

    for (int i = 0; i < node; i++) { 
     fgets(str[i], 2, fp);  //should be fgets(str, 2, fp); 
    } 
    printf("%s", str[0]);   //printf("%s", str); 
} 

我進入輸入是:

2 2 
hello 

Segmentation fault

我看到了類似的問題在這裏,一個人提到我可以撥打fgets一次獲取第一行,但忽略它,然後再次使用fgets獲得第二行。但我不知道該怎麼做。

+0

使用fgets(),然後使用strtok()來分割字符串。 –

+0

至於你的*當前*問題,你得到的崩潰,現在想一下。你聲明瞭一個指向'char'的指針數組,但是你絕不會使這些指針實際上*指向任何地方。 –

+0

嗨馬特。感謝回覆。我對c是新手。我不知道如何使用strtok()。我現在會查找它。 – chrisgjh

回答

2

函數內定義的局部變量w生病,除非明確初始化,否則具有不確定的值。對於指針來說,這意味着他們指向一個看似隨機的位置。使用任何未初始化的變量,除了初始化它,導致undefined behavior

這裏發生的是fgets將使用(未初始化的和看似隨機的)指針,並用它寫入它指向的內存。這種記憶在大多數情況下不屬於你或你的程序,甚至可能會覆蓋一些其他重要的數據。這可能導致崩潰或其他奇怪的行爲或結果。

最簡單的辦法就是讓str字符數組的數組,就像

#define NUM_OF_STRINGS 2 
#define STRING_LENGTH 64 
... 
char str[NUM_OF_STRINGS][STRING_LENGTH]; 
... 
fgets(str[i], sizeof str[i], stdin); 

你需要確保上述STRING_LENGTH足以適應各種串包括換行符和一個字符串結束。在我上面顯示的64的情況下,這意味着你可以有最多62個字符的行。


至於另一個問題,我指出,第一個電話fgets讀空行。

如果輸入存儲在內存中的一個緩衝區,然後scanffgets從這個緩衝區讀取輸入

2 2 
hello 

。緩衝區會,與上面的輸入,像這樣

 
+----+----+----+----+----+----+----+----+----+ 
| 2 | 2 | \n | h | e | l | l | o | \n | 
+----+----+----+----+----+----+----+----+----+ 

scanf呼叫念想

 
+----+----+----+----+----+----+----+ 
| \n | h | e | l | l | o | \n | 
+----+----+----+----+----+----+----+ 

所以兩個數字輸入緩衝器看起來以後有什麼在最先調用fgets循環將會看到是換行符。所以它讀取換行符然後完成,將字符串"hello\n"保留在第二個調用fgets的緩衝區中。

有幾種方法可以解決這個問題。我個人更喜歡使用fgets來讀取線條,如果您需要對線條進行簡單分析,那麼請使用sscanf(請注意前導s,同樣請see here for a good reference of all scanf variants)這樣做。

另一種方法是簡單地從輸入中只讀一個字符,然後丟棄它們。當你閱讀換行符時,停止循環並繼續執行程序的其餘部分。

+0

謝謝。你讓我真的很容易理解。 – chrisgjh

1

看看下面的例子,其中註釋說明了一些要點:

#include <stdio.h> 

#define NUM_OF_CHAR 2 
#define LEN_OF_STR 20 

int main() 
{ 
    int node, edge; 
    FILE* fp; 
    fp = stdin; 
    char strbuf[LEN_OF_STR]; 
    // stream is available after that 
    // reading numbers 
    fscanf(fp, "%d %d", &node, &edge); 
    // reading strings 
    for (int i = 0; i < node; i++) { 
     // reading line from input stream 
     fgets(strbuf, LEN_OF_STR, fp); 
    } 
    // cleaning input buffer 
    while (getchar() != '\n'); 
    // reading lines with data 
    char str[NUM_OF_CHAR]; 
    int a, b; 
    for (int i = 0; i < node; i++) { 
     // reading two numbers and two characters 
     fscanf(fp, "%d %d %c %c", &a, &b, &str[0], &str[1]); 
     // do something with dada, e.g. output 
     printf("%d %d %c %c\n", a, b, str[0], str[1]); 
    } 
    return 0; 
} 

當你與scanf讀取數據或fscanf您可以檢查結果,例如:

if (4 == fscanf(fp, "%d %d %c %c", &a, &b, &str[0], &str[1])) 
    { 
     // actions for correct data 
    } 
    else 
    { 
     // actions for wrong input 
    } 

這裏格式線有4說明符 - 「%d%d%c%c」,因此我們檢查爲「比較返回值與4」

+2

檢查'scanf'的返回值是*必須* – 4386427

+0

這實際上適用於我。謝謝 – chrisgjh

1

我已經解決了我的問題。我不應該使用char*指針,並使其指向一個數組。傳遞給fgets函數的第一個參數應該是char*,所以我應該只使用一個數組。

此外,由於scanf已經掃過第一行,如果我接下來使用fgets,它會自動獲得下一行。

#include <stdio.h> 

#define NUM_OF_CHAR 100 

int main() 
{ 
    int node, edge; 
    scanf("%d %d", &node, &edge); 

    FILE* fp; 
    fp = stdin; 

    char str[NUM_OF_CHAR] = {'\0'}; 

    for (int i = 0; i < node; i++) { 
     fgets(str, NUM_OF_CHAR, fp); 
    } 
    printf("%s", str); 
}