2015-02-07 52 views
0

我現在正在處理的是來自流的任何輸入的基於狀態的解析器。我的教授告訴我這是避免特殊情況的最好方法。我設置的方式是使用函數,並且在嘗試重用分配的內存時遇到了一些麻煩,所以我不會造成任何泄漏。我解析的是多個參數。每個參數都有一個名稱和一個值。一個示例的輸入將是:如何回收和重新使用分配的內存?

parameterName = 500; 

名爲參數名稱和它的類型是整數的與的值。

我成功地能夠解析其中的一個沒有內存泄漏。但是,做第二個參數會導致泄漏,我知道爲什麼:這是我的參數名稱上多次使用malloc

看看解析代碼:

int main() 
{ 
    int x; 
    char c; 
    char *nameTemp; 
    int hasName = 0; 
    int hasEqual = 0; 

    /* ParameterManager values */ 
    ParameterManager *pm; 
    pm = PM_create(500); 
    if((PM_manage(pm, "name", INT_TYPE, 1))); 

    while((x = getchar()) != EOF) 
    { 
     /* Cast int to char */ 
     c = (char)x; 

     /* Whitespace state */ 
     if((isspace(c))) 
     { 
      c = whitespace(); 
     } 

     /* Comment state */ 
     if(c == '#') 
     { 
      c = comment();   
     } 

     /* Name state */  
     if(((isalnum(c)) && hasEqual == 0 && hasName == 0)) 
     { 
      nameTemp = name(c); 
      printf("Name: %s\n", nameTemp); 
      hasName = 1; 
     } 

     /* Equal state */ 
     if(c == '=' && hasName == 1 && hasEqual == 0) 
     { 
      hasEqual = 1; 
     } 

     /* Value state */ 
     if((isalnum(c)) && hasName == 1 && hasEqual == 1) 
     { 
      getValues(c, nameTemp, pm->t_List, pm->m_List); 
      hasName = 0; 
      hasEqual = 0; 
     } 
    } 

    free(nameTemp); 
    if((PM_destroy(pm)) && DEBUG) printf("Success destroying PM.\n"); 
    return 0; 
} 

nameTemp = name(c)/* Name state */下,返回一個分配的字符串。這個字符串稍後傳遞給其他工作。但是,由於這個整個解析思路處於循環中,因此將會創建多個mallocs。我只能免費nameTemp一次,但有多個mallocs這個名字。我如何重複使用nameTemp而不會導致泄漏?

下面是一段代碼(在功能name()),其中nameTemp分配:

/* Make sure temp is not NULL before mallocing */ 
    if(temp[0] != '\0') 
    { 
     returnName = malloc(sizeof(char)*strlen(temp)+1); 
     strncpy(returnName, temp, strlen(temp)+1); 
     temp[0] = '\0'; 
     return returnName; 
    } 

我道歉,如果一些事情都不清楚。我想盡可能地做到一般,所以如果你需要更多的澄清,請讓我知道。

回答

2

malloc()沒有跟蹤分配的塊。你需要找到你完成處理你請求的內存的所有地方,然後在那裏找到它。

如果我正確讀取了您的代碼,那將會在您的while循環的正文末尾。

編輯:拉上評論。

這是未定義的行爲,嘗試使用已經存在的內存塊free()'d。

但是,用於保留塊上的句柄的指針只是一個常規指針,並且在將它傳遞給free()後不會失效。事實上,它根本不會讓步,因爲free()將其複製。

因此,在將指針傳遞到free()之後,將所述指針設置爲NULL以確保不會意外地重新使用現在不可用的塊是很常見的。

然後,您可以很好地重複使用它來處理由malloc()返回的全新塊,如往常一樣。

+0

如果我再次使用指針,釋放指針不是非法的嗎?如果我將** free(tempName)**放在身體末端,下次收集參數名稱時,它會給我一個錯誤。還是我不在同一頁上? – Plaidypus 2015-02-07 23:57:55

+1

@Plaidypus:你將實際的分配內存塊混淆了「指針」(這是一個指向某個內存的變量)。同一塊內存*兩次釋放是非法的。但是,您可以將變量用於不同的事情,並且在這樣的循環中,它是非常有意義的。 – 2015-02-08 00:05:38

+1

@Plaidypus不,這很好。在你釋放它之後使用相同的指針**地址**是未定義的行爲(除非它再次被'malloc'返回,這是完全可能的),但包含指針地址的變量具有自動存儲持續時間並且可用該函數退出。 – IllusiveBrian 2015-02-08 00:05:51

2

nameTemp = name(c);會導致一個不可避免的泄漏,當nameTemp存儲一個指針時,該指針不會保存在別處,也不會在此時釋放。

有很多方法可以避免這種情況(取決於您想要實現的目標以及您願意更改代碼結構的程度)。

三種可能性(勒令代碼變化最少的大部分):再次分配給它(和自由再次在節目的結尾)

free(nameTemp); 
nameTemp = name(c); 

  1. 釋放內存
  2. 免存儲器時,它變得過時
/* Value state */ 
if((isalnum(c)) && hasName == 1 && hasEqual == 1) 
{ 
    getValues(c, nameTemp, pm->t_List, pm->m_List); 
    hasName = 0; 
    hasEqual = 0; 
    free(nameTemp); 
    nameTemp=NULL; 
} 
  1. 使用通用緩衝區,在開始時分配足夠大的內存垃圾並再次釋放它。
char* nameTemp; 
nameTemp = (char*)malloc(512); //Or any other size, just check that its actually big enough before writing to it, otherwise buffer overflow errors will occur. 

// Somwhere in your program 
write_name(nameTemp, 512 , c); // Pass the buffer to be filled by the function, instead of returning a new pointer. 

// At the end of your program 
free(nameTemp); 
nameTemp = NULL; //Prevent access of freed memory.