如何回收和重用已分配的内存?

时间:2015-02-07 23:46:46

标签: c malloc realloc

我现在正在做的是基于状态的解析器,用于来自流的任何输入。我的教授告诉我这是避免特殊情况的最佳方法。我设置它的方式是使用函数,我在尝试重用已分配的内存时遇到一些麻烦,所以我不会造成任何泄漏。我正在解析的是多个参数。每个参数都有一个名称和一个值。输入的示例如下:

parameterName = 500;

名称为 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 个答案:

答案 0 :(得分:2)

malloc()不跟踪已分配的块。您需要找到您处理所请求内存的所有地方,并在那里free()

如果我正确阅读了您的代码,那么就会在while循环体的末尾。

编辑:提取评论。

尝试使用已经free()' d

的内存块,这是未定义的行为。

但是,用于保持块上句柄的指针只是一个常规指针,在将其传递给free()后不会过时。事实上,它根本不会让步,因为free()通过副本获取它。

因此,通常会在将NULL传递给free()之后将其设置为malloc(),以确保不会意外地重复使用现在不可用的块。

然后,您可以像往常一样将其重新用作{{1}}返回的全新块的句柄。

答案 1 :(得分:2)

nameTemp = name(c);会导致不可避免的泄漏,当nameTemp存储一个未在其他地方保存的指针时,此时也不会释放。

有很多选择可以避免这种情况(取决于您要实现的目标以及您愿意更改代码结构的程度)。

三种可能性(从最少量的代码更改到最多):

  1. 在重新分配之前释放内存(并在程序结束时再次释放)
  2. 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. 使用通用缓冲区,在开头分配足够大的内存,最后再将其释放。
      2. 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.