为包含指针引用的已分配内存的结构释放内存的正确方法

时间:2016-08-11 19:43:26

标签: c free

我有以下功能:

/* undef: from s from hashtab */
void undef(char *s) {
    struct nlist *currentPtr, *previousPtr;

    for (previousPtr = NULL, currentPtr = hashtab[hash(s)];
            currentPtr != NULL;
            previousPtr = currentPtr, currentPtr = currentPtr->next) {

        if (strcmp(currentPtr->name, s) == 0) {
            if (previousPtr == NULL) /* first element */
                hashtab[hash(s)] = currentPtr->next;
            else /* element in the middle or at the end */
                previousPtr->next = currentPtr->next;
            /* free memory */
            free(currentPtr->name);
            free(currentPtr->defn);
            //free(currentPtr);
        }
    }
}

currentPtr指向由malloc分配的内存。

currentPtr->namecurrentPtr->defn指向通过strdup复制的字符数组。

我不确定释放列表项的内存的正确方法是什么。

如果我使用

free(currentPtr->name);
free(currentPtr->defn);

然后我没有分段错误,但我相信字符数组内存被释放,但列表结构元素本身不是。

如果我使用

free(currentPtr);

然后我也没有分段错误,但我相信我释放了列表结构元素本身,而不是字符数组内存。

使用

free(currentPtr->name);
free(currentPtr->defn);
free(currentPtr);

给我分段错误。但我认为这是正确的做法。

哪个是正确的?为什么会失败?

1 个答案:

答案 0 :(得分:4)

您需要稍微改变一下策略,因为currentPtr是调用

后的悬空指针
free(currentPtr);

这是我的建议:

for (previousPtr = NULL, currentPtr = hashtab[hash(s)];
        currentPtr != NULL;
        previousPtr = currentPtr) {

    if (strcmp(currentPtr->name, s) == 0)
    {
        if (previousPtr == NULL) /* first element */
            hashtab[hash(s)] = currentPtr->next;
        else /* element in the middle or at the end */
            previousPtr->next = currentPtr->next;

        /* free memory */
        free(currentPtr->name);
        free(currentPtr->defn);

        // Get hold of the next pointer before free'ing currentPtr
        struct nlist *tempPtr = currentPtr->next;
        free(currentPtr);
        currentPtr = tempPtr;
    }
    else
    {
        currentPtr = currentPtr->next;
    }
}

更新,更精简的版本

由于您在四个地方使用currentPtr->next,因此可以使用以下方法简化循环:

struct nlist *nextPtr = NULL;
for (previousPtr = NULL, currentPtr = hashtab[hash(s)];
        currentPtr != NULL;
        previousPtr = currentPtr, currentPtr = nextPtr) {

    nextPtr = currentPtr->next;
    if (strcmp(currentPtr->name, s) == 0)
    {
        if (previousPtr == NULL) /* first element */
            hashtab[hash(s)] = nextPtr;
        else /* element in the middle or at the end */
            previousPtr->next = nextPtr;

        /* free memory */
        free(currentPtr->name);
        free(currentPtr->defn);
        free(currentPtr);
    }
}