free():释放二维指针时指针无效

时间:2021-08-01 16:01:31

标签: c pointers free

我有一个二维指针数组:

char **fields = calloc(1, sizeof(char *));

我向它添加了不同的字符串,如下所示:

if(i > 0) fields = realloc(fields, (i+1) * sizeof(char *));
fields[i] = calloc(size, sizeof(char));

然后我将 memcpy 用于 fields[i] 所需的字符串。

在程序结束时,当我尝试释放字段时,我会这样做:

int j=0
while(fields != NULL && fields[j]){
    free(fields[j]);
    j++;
}
free(fields);

程序在字段中插入 4 个字符串。 第一个字符串按预期释放,但是在循环的第二次迭代 (j=1) 时,程序停止并输出错误:free(): invalid pointer

编辑:我做了一个有同样问题的小程序:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char *argv[]){
    char **fields = calloc(1, sizeof(char *));
    int fieldsIndex = 0,i=0;
    while (i<4) {
        if(fieldsIndex > 0){
            fields = realloc(fields, (fieldsIndex + 1) * sizeof(char *));
            fields[fieldsIndex] =NULL;
            printf("amount of field places: %d\n", (fieldsIndex + 1));
        }

        fields[fieldsIndex] = calloc(8, sizeof(char));
        fields[fieldsIndex] = "88888888";
        fieldsIndex++;
        i++;
    }
    int j=0;
    for(j=0; j<i; j++){
        printf("field: %s\n", fields[j]);
        free(fields[j]);
    }
    free(fields);
    return 0;
}

有人可以帮忙吗?

1 个答案:

答案 0 :(得分:4)

主要针对 MRE。

  • 主要问题围绕这一行:

    fields[fieldsIndex] = "88888888";
    

    不正确的原因有两个:

    • 首先,您需要在数组中多一个元素作为空字节。

    • 其次,您使 fields[fieldsIndex] 指针指向字符串文字,这不仅会导致内存泄漏,而且这些字符串文字通常存储在内存的只读部分,无论哪种方式都会释放行为指向字符串文字的指针未定义。

      您需要将字符串复制到您刚刚分配的内存中。只要您像前一点提到的那样保留足够的内存,使用 memcpy 就应该可以工作,更简洁的方法是使用 strdup

  • 另一个问题是 if(fieldsIndex > 0),因为这样 fields[0] 将不会分配内存。

其他一些注意事项,如果您知道字符串的数量(i < 4),则不需要realloc,只需为第一个calloc中的所有指针分配空间*(假设不是由 MRE 的构建带来的),还有 ifieldsIndex 似乎是多余的。

Here is a demo 保持 realloc(因为它与 OP 相切):

int main()
{
    char **fields = NULL;
    char **tempfields; // I advise the use of an auxiliary pointer for reallocation
    int fieldsIndex = 0;

    while (fieldsIndex < 4)
    {
        tempfields = realloc(fields, (fieldsIndex + 1) * sizeof *fields); //*
        if (!tempfields)
        {         
            // handle the allocation error appropriately
        }
        fields = tempfields;
        printf("amount of field places: %d\n", (fieldsIndex + 1));
        fields[fieldsIndex] = strdup("88888888");
        // Or 
        // fields[fieldsIndex] = calloc(9, sizeof **fields); // check return
        // strcpy(fields[fieldsIndex], "88888888");

        fieldsIndex++;
    }

    // With int iterator
    int j = 0;
    for (j = 0; j < fieldsIndex; j++)
    {
        printf("field: %s\n", fields[j]);
        free(fields[j]);
    }
    free(fields);
}

或者在 fields 中使用哨兵元素:

Live demo

// With sentinel
tempfields = realloc(fields, (fieldsIndex + 1) * sizeof *fields);
if (!tempfields)
{
     // handle the allocation error appropriately
}
fields = tempfields;
fields[fieldsIndex] = NULL;

while (*fields)
{
    printf("field: %s\n", *fields);
    free(*fields);
    fields++;
}
free(tempfields);