2015-02-07 54 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.