簡體   English   中英

getline()/ strsep()組合導致分段錯誤

[英]getline() / strsep() combination causes segmentation fault

運行下面的代碼時,我遇到了分段錯誤。

它應該基本上讀取超過3M行的.csv文件並在之后執行其他操作(與問題無關),但在207746次迭代后它返回分段錯誤。 如果我刪除了p = strsep(&line,"|"); 只打印整line ,它將打印> 3M線。

int ReadCSV (int argc, char *argv[]){

    char *line = NULL, *p;
    unsigned long count = 0;

    FILE *data;
    if (argc < 2) return 1;
    if((data = fopen(argv[1], "r")) == NULL){
        printf("the CSV file cannot be open");
        exit(0);
    }


    while (getline(&line, &len, data)>0) {

        p = strsep(&line,"|");  

        printf("Line number: %lu \t p: %s\n", count, p);
        count++;
    }

    free(line);
    fclose(data);

    return 0;
}

我想它與內存分配有關,但無法弄清楚如何修復它。

getlinestrsep組合經常會引起混淆,因為兩個函數都會將指針傳遞給指針作為初始參數。 如果再次將通過strsep的指針傳遞給getline ,則在第二次迭代時會冒未定義行為的風險。

考慮一個例子: getlineline分配101個字節,並在其中讀取一個100個字符的字符串。 請注意, len現在設置為101.您調用strsep ,它會找到'|' 在字符串中間,使其指向line到曾經被認為是line+50 現在你再次打電話給getline 它看到另一個100個字符的行,並得出結論可以將它復制到緩沖區中,因為len仍然是101.但是,由於line指向緩沖區的中間,因此寫入100個字符將成為未定義的行為。

在調用strsep之前復制line

while (getline(&line, &len, data)>0) {
    char *copy = line;
    p = strsep(&copy, "|");  
    printf("Line number: %lu \t p: %s\n", count, p);
    count++;
}

現在,在循環迭代之間保留傳遞給getline line

查看表達式getline(&line, &len, data)並閱讀聯機幫助頁

如果在調用之前將* line設置為NULL並且將* len設置為0,則getline()將分配用於存儲該行的緩沖區。 即使getline()失敗,該緩沖區也應由用戶程序釋放。

第一次循環時應該是這種情況(盡管我們看不到len聲明的位置,讓我們假設您的真實代碼正確執行此操作)

或者,在調用getline()之前,*行可以包含一個指向malloc(3)分配緩沖區* len字節大小的指針。 如果緩沖區不足以容納該行,則getline()使用realloc(3)調整其大小,根據需要更新* line和* len。

好的,所以如果line != NULL它必須指向由大小為lenmalloc分配的緩沖區。 第一次調用getline (如上所述)分配的緩沖區滿足此要求。

注意這不是不夠好, line某處該緩沖區,它必須是開始。

現在看表達strsep(&line,"|")和閱讀的手冊頁

...通過用空字節('\\ 0')覆蓋分隔符來終止此令牌,並更新*行以指向令牌

因此,第一個參數( line )被更改,以便您可以使用相同的第一個參數再次調用strsep ,並獲取下一個標記。 這意味着line不再是getline的有效參數,因為它不是malloc緩沖區的開頭(長度len現在也是錯誤的)。

在實踐中,要么

  1. getline將嘗試將len個字節讀入您給它的緩沖區,但由於您按line第一個令牌的長度提前line ,因此它會寫入已分配塊的末尾。 這可能只會損壞堆而不是立即死亡
  2. getline將嘗試重新分配你給它的緩沖區,但由於它不是一個有效的分配塊,你會再次受到堆損壞。

雖然我們在這里,你也不檢查p是非NULL,但是破壞line是主要問題。

哦,如果您認為問題與分配有關,請嘗試使用valgrind - 它通常會發現事情首先出錯。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM