2009-12-03 45 views
1

我有一個文本文件,最多可以有100個IP地址,每行1個。我需要將每個地址作爲一個字符串讀入一個名爲「list」的數組中。首先,我假設「列表」需要是一個二維字符數組。每個IP地址的長度爲11個字符,12,如果你有「\ 0」,所以我宣佈名單如下:如何在C中逐行讀取文件?

char list[100][12];

接下來,我試圖用fgets來讀取數據流:

for (i = 0; i < 100; i++) 
    { 
     if (feof(stream)) 
      break; 
      for (j = 0; j < 12; j++) 
      fgets(&list[i][j], 12, stream); 
     count++; 
    } 

要檢查,看看是否絲線正確讀取,我試圖將他們輸出:

for (i = 0; i < 5; i++) 
    { 
     for (j = 0; j < 11; j++) 
      printf("%c", list[i][j]); 
     printf("\n"); 
    } 

運行程序後,很清楚什麼是錯的。作爲初學者,我不確定是什麼,但我猜我正在讀錯文件。沒有錯誤。它編譯,但在兩行打印一個奇怪的地址。

編輯:

我替換此與fgets代碼:

for (i = 0; i < 100; i++) 
    { 
     if (feof(stream)) 
      break; 
     fgets(list[i], 12, stream); 
     count++; 
    } 

現在打印五根弦,但他們是從內存中 「隨機」 的字符。

+0

任何錯誤信息? – Nifle 2009-12-03 19:44:46

+1

您是否嘗試啓動調試器?如果通過查看源代碼無法弄清楚發生了什麼問題,這應該始終是您的第一步。 – 2009-12-03 19:45:28

+0

你說「......很明顯有什麼不對。」但你不會說這是什麼錯誤。沒有這個,很難說更多。 是否有錯誤?有沒有輸出,但不是你所期望的? – FrustratedWithFormsDesigner 2009-12-03 19:47:13

回答

6

首先,閱讀:

 for (j = 0; j < 12; j++) 
     fgets(&list[i][j], 12, stream); 

你有一個很大的問題就在這裏。這是試圖讀取字符串到您陣列中的每個連續的字符

總而言之,我認爲你會讓這件事情比需要的複雜得多。把你的數組想象成100個字符串,並且fgets將一次處理一個字符串。這意味着閱讀可以是這個樣子:

for (i=0; i<100 && fgets(list[i], 11, string); i++) 
    ; 

還有另外一個小細節處理:fgets()通常保持在每行的末尾新行。因此,您可能需要爲13個字符留出空間(地址11,新行1,NUL終止符1),否則您可能需要將數據讀入臨時緩衝區,並將其僅複製到您的list在你剝離新線之後。

在當前用於打印字符串的代碼中,您一次只能處理一個字符,這可以起作用,但不必要的困難。有幾個人建議使用%s printf轉換,這本身就很好。但是,要使用它,你必須簡化索引。打印第6個地址會是這個樣子:

for (i=0; i<6; i++) 
    printf("%s", list[i]); 
+0

謝謝,你的代碼有效;但是,打印時,由於某種原因,僅打印前三個地址。 – 2009-12-03 20:15:11

+0

我將緩衝區擴展到13,現在可以工作。 – 2009-12-03 20:16:44

+0

@ ttread31:是的,由於太短的緩衝區,每個地址都會被分爲兩部分,所以前六個「項目」實際上只有三個地址。 – 2009-12-03 22:29:32

4

您對fgets的呼叫最多可以從串流中讀取11個字符。所以你不想爲每個字符串的每個字符調用一次。考慮一下這些循環:在i = 0和j = 0的情況下,它可以讀取多達11個字符到&list[0][0]。然後在i = 0和j = 1的情況下,它讀取另外11個字符到&list[0][1]。這是錯誤的,原因有兩個 - 它覆蓋最後一次調用的結果,並且可能會寫入比列表[0]更多的字節。

+0

fgets是否不是逐行而是通過文件中的字符? – 2009-12-03 19:48:15

+0

是的,次循環是不必要的,因爲你每次讀12個字符時讀到fgets – 2009-12-03 19:48:49

+0

這似乎是一個邏輯問題。 – Ismael 2009-12-03 19:49:11

1

一個換行符使得與fgets停止閱讀,但它被認爲是一種有效的字符,因此它是包含複製到str中的字符串中。

您可能正在讀取第一個調用fgets中的前12個字符,然後第二個調用將捕獲換行符,然後第三個調用將獲得下一行。

嘗試使用與fgets有15個字符的限制,擴大你的緩衝區。

1

第二個循環是沒有必要的,它會損壞你的記憶。你應該做這樣的事情,

for (i = 0; i < 100; i++) 
{ 
if (feof(stream)) 
break; 
fgets(&list[i][j], 12, stream); 
count++; 
} 

To check to see if the strings were read properly, I attempt to output them: 

for (i = 0; i < 5; i++) 
{ 
printf("%s\n", list[i]); 
} 
1

爲(i = 0;我< 100;我++){

if (feof(fp)) 
     break; 

    fscanf(fp,"%s\n",list[i]); 

}

1

不要使用feof()爲您的循環條件;直到你試圖讀取文件末尾之後纔會返回true,這意味着你的循環執行的次數太多了。檢查您輸入調用的結果(無論您使用fgets()fscanf()),看看它是否成功,然後檢查如果feof()你有一個錯誤的條件。

if (fgets(buffer, sizeof buffer, stream) != NULL) 
{ 
    // process the input buffer 
} 
else if (feof(stream) 
{ 
    // handle end of file 
} 
else 
{ 
    // handle read error other than EOF 
} 

fgets()讀取整個字符串,而不是單個字符,所以你不希望傳遞的每個個性的地址在您的字符串。說它像這樣代替:

if (fgets(list[i], sizeof list[i], stream) != NULL) 
{ 
    // process input address 
} 

而現在,對於波特的關於數組和指針通常的高談闊論......

當數組表達式出現在大多數情況下,表達的類型隱式轉換而來「的T N元件陣列」到‘指針T’,和表達式的值是數組的第一元素的地址。此規則的例外是當陣列表達是sizeof&運營商的操作數,或它是一個字符串文字正被用作在聲明的初始化。當你聽到人們說「數組和指針是同一件事」時,他們正在篡改這條規則。數組和指針是完全不同的動物,但它們可以在某些情況下互換使用。

請注意,在上面的代碼中,我通過了list[i]作爲沒有任何裝飾的fgets()的第一個參數(例如&運算符)。即使的list[i]類型是「炭的12個元素的數組」,在這種情況下它是隱式轉換爲類型「字符指針」,並且該值將是list[i][0]地址。請注意,我也將相同的表達式傳遞給sizeof運算符。在這種情況下,數組表達式的類型是而不是轉換爲指針類型,並且sizeof運算符返回數組類型(12)中的字節數。

只是釘了下去:

 
Expression  Type    Implicitly converted to 
----------  ----    ---- 
list   char [100][12] char (*)[12] (pointer to 12-element array of char) 
list[i]   char [12]  char * 
list[i][j]  char    N/A 

這一切都意味着,fgets()將讀取到下一個12個字符(只要不打新行或EOF第一),並將其存儲在開始list[i][0]。請注意,fgets()將在您的字符串末尾寫入一個終止nul字符(0)。另請注意,如果fgets()遇到換行目標陣列中有空間,並且終止nul,fgets()將在nul字符之前存儲終止換行符。所以,如果你輸入的文件有一個像

1.1.1.1\n 

線,在讀取後您的輸入緩衝區的內容將是"1.1.1.1\n\0xxx"其中x是一些隨機值。如果你不想換行那裏,你可以使用strchr()功能找到它,然後用0覆蓋它:

char *newline; 
... 
if ((newline = strchr(input[i], '\n')) != NULL) 
{ 
    *newline = 0; 
} 

因爲在接下來的換行符fgets()停止,因爲你的輸入緩衝區的大小爲12個字符,您可能會遇到這樣的情況:您將新行作爲文件中的下一個輸入字符;在這種情況下,fgets()將只寫入新行到輸入緩衝區,所以你會有一些空的條目,這可能不是你想要的。您可能需要在輸入緩衝區中添加一個額外的字節以避免這種情況。

全部放在一起:

char list[100][13]; 
... 
for (i = 0; i < 100; ++) 
{ 
    if (fgets(list[i], sizeof list[i], stream) != NULL) 
    { 
    char *newline = strchr(list[i], '\n'); 
    if (newline != NULL) 
     *newline = 0; 
    printf("Read address \"%s\"\n", list[i]); 
    count++; 
    } 
    else if (feof(stream)) 
    { 
    printf("Reached end of file\n"); 
    break; 
    } 
    else 
    { 
    printf("Read error on input; aborting read loop\n"); 
    break; 
    } 
}