free():释放 2d 指针时指针无效

free(): invalid pointer when freeing a 2d pointer

我有一个二维指针数组:

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;
}

有人能帮忙吗?

主要解决 MRE。

  • 主要问题出在这一行:

    fields[fieldsIndex] = "88888888";
    

    不正确的原因有两个:

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

    • 其次,你让fields[fieldsIndex]指针指向字符串文字,这不仅会导致内存泄漏,而且这些字符串文字通常存储在内存的只读部分,要么释放指向字符串文字的指针的行为未定义。

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

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

一些其他注意事项,如果您知道字符串的数量 (i < 4),则不需要 realloc,只需为第一个 [中的所有指针分配 space =20=]*(假设不是构建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);