2014-04-08 80 views
0

我想使用getline()和realloc()將文件讀入一個字符串數組。過去我使用非常類似的代碼來標記字符串,並且一切正常。我會考慮樣本輸入文件Realloc覆蓋數組的內容?

1 
2 
3 
4 
5 

下面的代碼:

char** read_input(const char* input_file, char* line){ 

    FILE *fp; 
    size_t len = 0; 
    size_t nums = 0; 
    ssize_t read; 
    char** res = NULL; 

    if ((fp = fopen(input_file, "r")) == NULL){ 
     printf("Incorrect file\n", strerror(errno)); 
     exit(EXIT_FAILURE); 
    } 

    while ((read = getline(&line, &len, fp)) != -1){ 
     if ((res = realloc(res, sizeof(char*) * ++nums)) == NULL) 
      exit(EXIT_FAILURE); 

     char to_strip[sizeof(read) * sizeof(char)]; 
     strcpy(to_strip, line); 
     if (line[read - 1] == '\n') 
      to_strip[read - 1] = 0; 
     else 
      line[read] = 0; 

     res[nums - 1] = to_strip; 
    } 
    free(line); 

    if ((res = realloc(res, sizeof(char*) * (nums + 1))) == NULL) 
     exit(EXIT_FAILURE); 

    res[nums - 1] = 0; 

    return res; 
} 

循環後,如果我打印數組的內容,我得到:

5 
5 
5 
5 
5 

儘管事實上如果我在循環中調用print,在每次分配res之後,我都會得到正確的數字。這實在讓我感到困惑,因爲除了使用realloc之外,我看不出什麼可能是錯誤的,但我認爲realloc保存了數組內容。謝謝。

回答

2

您忙於調用未定義的行爲,因爲您每次都在重新分配的數組中存儲一個指向to_strip的指針,並且指針在循環的每次迭代中超出範圍,並且在每次迭代時都會被覆蓋,這就是爲什麼您最後看到相同的值。如果您打印的是循環中的所有值而不是僅顯示當前值,則首先看到1,然後看到2 2,然後看到3 3 3,然後看到4 4 4 4,最後看到5 5 5 5 5。如果您在打印結果之前從此函數返回之後做了足夠的工作,則會看到垃圾,因爲該空間將用於其他用途。

您需要製作存儲在重新分配的陣列中的行的副本。最簡單的就是使用strdup()

res[nums - 1] = strdup(to_strip); 

不要忘記釋放繩線,以及指針指向字符串數組。

不要忘記在返回之前關閉您打開的文件。

line傳入函數似乎很奇怪。它必須是空指針或指向可傳遞給realloc()的空間。由於您在返回之前的空間free(),調用函數需要知道您已經釋放了它傳遞給您的空間 - 因爲您不知道它有多大,所以您告訴getline()它的大小爲零,所以它有即將面世。沒有這個參數,界面會更乾淨。在函數的開始處使用本地的char *line = 0;

+0

這已經解決了這個問題,謝謝。在這種情況下使用strdup()是有意義的,我想我應該回顧一下指針,我有一段時間沒有用過它們。 – wdonahoe

1

這是一個問題:

ssize_t read; 

char to_strip[sizeof(read) * sizeof(char)]; 
strcpy(to_strip, line); 

sizeof(read) - 大概4或8 - 是一個奇怪的量分配爲要複製一個字符串到緩衝區中。我想你的意思是char to_strip[ read + 1 ];。但是,以後你也行:

res[nums - 1] = to_strip; 

哪個地方的指針to_stripres。但是,在for循環的末尾不再存在,所以這些將是野生指針。如果你的意圖是存儲從文件中讀取的所有文本供以後訪問,那麼你將需要爲每一行分配內存。

喬納森·萊弗勒的建議strdup可能是最簡單的解決方案;感謝他清理我的錯誤使用getline

您也可以完全廢除to_strip,因爲您可以直接覆蓋\nline

+0

重複調用'getline()'不會有泄漏;它只是分配額外的空間,如果它已經得到的是不夠的。該函數的接口很奇怪(請參閱我的答案中的註釋),但是沒有大的泄漏。 –

+0

也許我誤解了'getline()'的行爲,我認爲它是'malloc'爲讀取行的新存儲。這是否在任何標準的功能?其實我不知道OP代碼中的char * line參數應該是什麼。 –

+1

請參閱POSIX ['getline()'](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getline.html)。它被告知它有多少空間以及它在哪裏。如果這對於當前線路來說足夠大,那就用它了;如果不是,則分配更多空間,並且用新大小更新大小和指針參數。因此,它會調整大小,直到它讀取最長的行,並且不需要在其後重新分配。 –