2009-10-17 45 views
0

在malloced字符串上使用strtok有什麼我應該知道的嗎?在分配的字符串上使用strtok()?

在我的代碼我有(籠統)

char* line=getline(); 
Parse(dest,line); 
free(line); 

其中getline()是返回一個char *一些malloc內存的功能。 和Parse(dest, line)是一個在線解析,將結果存儲在dest(已從其他信息中部分填充)的函數。

Parse()在線調用strtok()可變的次數,並做一些驗證。 每個標記(一個指向strtok()返回的指針)被放入一個隊列中,直到我知道我有多少。

然後將它們複製到dest中的malloc'd char **上。

現在free(line) 和一個函數,它自由的炭的每個部分* []在dest,既想出上的valgrind爲:

「地址0x5179450是8個字節大小的塊內38自由」 d「

或類似的東西。

我正在考慮重構我的代碼,不直接在char **上存儲標記,而是存儲它們的副本(通過mallocing space == strlen(令牌)+1,然後使用strcpy())。

+0

我相信這:http://stackoverflow.com/questions/1495368/strtok-and-memory-leaks,去回答我的問題一些whay。 – 2009-10-17 11:20:48

+0

strtok在本地修改字符串,在刪除符號的位置添加空值。並返回指向這些部分開始的指針 – 2009-10-17 11:31:56

回答

2

你問:

有什麼我應該知道的 使用上malloced字符串的strtok?

有很多事情要注意。首先,strtok()在處理它時修改該字符串,在找到分隔符的位置插入空值('\0')。這不是分配內存的問題(可以修改!);如果您嘗試將一個常量字符串傳遞給strtok(),則會出現問題。

其次,您必須擁有與malloc()calloc()(但realloc()可能與計數混亂)一樣多的free()的呼叫。

在我的代碼我有(籠統)

char* line=getline(); 
    Parse(dest,line); 
    free(line); 

除非Parse()分配它保留的空間,你不能使用dest結構(或者,更準確地說,是指針入行在dest結構內)呼叫free()free()釋放由getline()分配的空間,並在此之後使用指針產生未定義的行爲。請注意,未定義的行爲包括'出現工作,但只能巧合'的選項。

其中函數getline()是一個函數, 返回一個char *一些malloced 存儲器,和解析(目標寄存器,線)是 函數,它的在線分析, 存儲在dest結果(其 已部分填寫, 來自其他信息)。

解析()調用strtok()一個變量 在線次數,並做了一些 驗證。每個標記(指向 的指針是由strtok()返回的)將 放入隊列中,直到我知道有多少個I 。

注意,通過指針返回strtok()都是指針成getline()分配的空間單塊。你還沒有描述任何額外的內存分配。

然後將它們複製到dest中的malloc'd char **上。

這聽起來好像您將strtok()中的指針複製到指針數組中一樣,但您不會去複製這些指針指向的數據。

現在免費(線)和功能 免費的炭的每個部分* []在 DEST, 都拿出上的valgrind爲:

"Address 0x5179450 is 8 bytes inside a block of size 38 free'd" 

或類似的東西。

dest的「char *[]」部分的第一free()可能有一個指針指向line,因此釋放的存儲器的整體塊。所有對dest部分後續釋放是試圖釋放不malloc()返回的地址,並valgrind是想告訴你。該free(line)操作失敗,則是因爲在dest指針的第一free()已釋放該空間。

我正在考慮重構我的代碼 [要]存儲它們的副本[...]。

提出的重構可能是明智的;已被他人提及的功能strdup()將整齊可靠地完成工作。

需要注意的是重構之後,你仍然需要釋放行,但你不會釋放任何由strtok()返回的指針。它們只是指向由(由line標識)管理的空間的指針,並且將在您發佈line時全部發布。

請注意,您需要釋放每個分開分配的(strdup()'d)字符串以及通過dest訪問的字符指針數組。

或者,在撥打Parse()後不要立即撥打電話。有dest記錄分配的指針(line),釋放指針數組。不過,您仍然不會發布由strtok()返回的指針。

2

然後將它們複製到dest中的malloc'd char **。

字符串被複制,或指針被複制? strtok函數修改你給它的字符串,以便它可以讓你指向同一個字符串而不需要複製任何東西。當你從它得到令牌時,你必須複製它們。要麼只要任何一個令牌指針在使用中,要麼保持輸入字符串。

許多人建議您完全避免strtok,因爲它很容易出錯。此外,如果您使用線程並且CRT不支持線程,strtok可能會導致您的應用程序崩潰。

+1

+1以完全避免strtok()。 – 2009-10-17 19:40:34

2

有一個功能strdup分配內存,然後複製另一個字符串到它。

+0

我現在正在調整每個令牌,然後儲存。 我現在沒有記憶釋放錯誤,而且生活很好。 – 2009-10-17 12:53:44

+0

如果這回答您的問題,請點擊「接受」複選標記。對於您在這裏提出的其他問題,這樣做會很好。如果有更好的答案出現,您可以稍後撤消它。 – 2009-10-17 14:39:22

+1

雖然不是標準的C函數。 – AnT 2009-10-17 15:59:25

0

1在您的parse()中,strtok()只在每個匹配位置寫入'\ 0'。實際上這一步並不特別。使用strtok()很容易。當然它不能用於只讀存儲器緩衝區。

2對於parse()中獲得的每個子字符串,將其相應地複製到malloc()ed緩衝區。如果我舉一個簡單的例子,用於存儲子串,它看起來像下面的代碼,說概念,雖然它可能不完全一樣,你真正的代碼:

 
    char **dest; 
    dest = (char**)malloc(N * sizeof(char*)); 
    for (i: 0..N-1) { 
     dest[i] = (char*)malloc(LEN); 
     strcpy(dest[i], sub_strings[i]); 
    NOTE: above 2 lines could be just one line as below 
     dest[i] = strdup(sub_string[i]); 
    } 

3免費DEST,概念再次:

 
    for (i: 0..N-1) { 
     free(dest[i]); 
    } 
    free(dest); 

4調用free(線)沒有什麼特別的過了,它不會影響你的「目標」甚至有點。

「dest」和「line」使用不同的內存緩衝區,因此您可以在步驟3之前執行步驟4(如果首選)。如果您執行了上述步驟,則不會發生錯誤。似乎你在代碼的第2步中犯了錯誤。