2012-02-03 61 views
1

我試圖通過流的內容循環來動態生成列表中的節點,給出了我讀取的每一行的內容。我有如下定義的結構:無法指定字符指針循環中的結構

struct info { 
    char *mystring; 
    char *file; 
    int line_no; 
    struct info *next; 
}; 

我用這個循環通過流迭代:

while(1) {  
     char t [KMAX]; 
     char* file; 
     char* line_no; 
     char* text; 
     if (fgets(t, KMAX, file_pipe) != NULL) { 
      file = strtok (t, delimiter); 
      line_no = strtok(NULL, delimiter); 
      int line = atoi(line_no); 
      text = strtok(NULL, delimiter); 
      add(&head, text, line, file); 
     } 

我知道變量正確傳遞給我的附加功能,因爲我打印出來每次我都可以驗證它。但是,當我嘗試打印列表時出現問題。它只是打印文本和文件名的最後一行,但整數值相應地改變。我的猜測是它與數組被刪除有關,並且每次都在同一塊內存中被重新創建,所以指針每次都會改變。

我不確定正確的方法是去解決這個問題。我是否以某種方式修改我的while循環並以不同的方式使用char指針,或者我應該改變結構以保存變量,而不是僅僅使用指針?我會很感激任何反饋!

編輯:添加更多的代碼

void add(struct info **x, char * text, int line_no, char * file) { 
struct info* current = *x; 
struct info* newInfo; 


newInfo = malloc(sizeof(struct info)); 
(*newInfo).next = NULL; 
(*newInfo).grepstring = text; 
(*newInfo).line_no = line_no; 
(*newInfo).file = file; 

if (current == NULL) { //indicates the head is null, special case 
     *x = newInfo; 
} else { 
     //get to the end of the list 
     while ((*current).next != NULL) { 
      current = (*current).next; 
     } 
     //apends node to the end of the list 
     (*current).next = newInfo; 
} 

}

+0

錯誤必須在添加或打印列表中的代碼。你可以請他們發表。 – 2012-02-03 02:36:21

+0

爲了能夠確定問題的原因,我們需要查看您提及的打印電話的確切位置。 也是迂腐,我會建議在每次調用後檢查strtok返回null,這將意味着字符串t null終止字符已被發現 – Lefteris 2012-02-03 02:40:14

+0

那麼,它是什麼? '結構信息'或'結構說'? – 2012-02-03 02:56:25

回答

2

當你說char* text,你在做什麼是在堆棧上分配char*strtok沒有將它指向一些新分配的內存,它將它指向t的堆棧分配空間。

該內存在超出範圍時丟失,該範圍發生在while循環的每次迭代的底部。任何對其地址的引用都可能指向正確的內容,或者沒有任何內容,或者在該點之後的某個其他隨機值 - 它們展示的行爲是未定義的。

您需要每個struct info的內容才能在循環中生存(並且可能在可預見的未來繼續存在)。要做到這一點,你必須做一個堆分配。在C中,這是通過malloc函數完成的。

在你add方法,說:

char* text_copy = malloc(strlen(text)+1); // +1 for trailing NUL character 
strcpy(text_copy, text); 

這將在堆上創建新的內存,具有相同內容的原文。

您應該對struct info的所有內容執行此操作,因爲此刻它們都是指向堆棧分配的緩衝區的指針。

當您完成該操作時,您必須再次使用free內存,但它會一直持續到此時。

+0

我認爲你是正確的...修改我的代碼,包括工作文本的內存分配。何時何地我應該釋放 - 最後當我銷燬列表? – thomascirca 2012-02-03 02:56:43

+0

@thomascirca每當你不再需要內容。每當你調用'malloc',某處必須有一個相應的'free',否則你有*內存泄漏*。就像你說的那樣,在這種特殊情況下,當你「摧毀列表」時,你可能想循環和「釋放」所有東西。 – Borealid 2012-02-03 02:59:39

+0

我只想補充一點,如果你的程序即將終止,你不需要擔心釋放,因爲所有的內存將在那個時候被操作系統釋放。 – 2012-02-03 03:10:56

1

你不告訴我們什麼呢add(),但顯然它只是分配直接調用strtok()到結構的成員的結果。您不能這樣做 - 在將它們分配給結構成員之前,使用strdup()(或malloc()strcpy())複製每個char *。指針strtok()返回指向該緩衝區的那個點,並且它們在每個新的循環迭代中變得無效。

1

你曾經舉行字符串創建的唯一緩衝是t,你在你的while循環的頂部做:

char t [KMAX]; 

char *指針那麼一切都將某處指向該緩衝區,但是這每當您撥打fgets時都會更改內容緩衝區,這是一個問題。讀完輸入後,實際存儲在RAM中的唯一文本將是上次調用fgets的數據。

您可以更改add函數,以便分配新緩衝區並將字符串複製到它們。已經有一個功能可以爲你做,它被稱爲strdup。像這樣的東西會工作(雖然我沒有測試過):

void add(struct info **x, char * text, int line_no, char * file) { 
... 
newInfo = malloc(sizeof(struct info)); 
newInfo->next = NULL; 
newInfo->grepstring = strdup(text); 
newInfo->line_no = line_no; 
newInfo->file = strdup(file); 
... 
}