【问题标题】:free(): invalid pointer when freeing a 2d pointerfree():释放二维指针时指针无效
【发布时间】:2021-10-07 05:55:38
【问题描述】:

我有一个二维指针数组:

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

谁能帮忙?

【问题讨论】:

  • 额外的哨兵指针是什么意思?你能给我一个代码中的例子吗?谢谢
  • 我们一个minimal reproducible example怎么样?呈现的代码片段本质上不是错误的,但它们可能依赖于不安全的假设。或者我有一个完全独立的问题。
  • 当你释放它的时候,在这之前显然是错误的,但是你已经 nit 显示了该代码。您已经展示了calloc() 调用,但包含确定i 值的代码,也没有其他可能破坏fields[1] 的代码。本质上,您发布的任何代码都不包含导致问题的代码。
  • @ItaiElidan:让我数一数!不过我不打算猜测,您需要展示整个代码 - 堆损坏可能发生在任何地方。如果代码很大,您将不得不在一些较小的可重现示例中重现错误。如果你不能这样做,那么很明显你正在减少它的代码不是错误所在。
  • “哨兵指针”是数组结束处的额外空指针。您可以使用它来知道何时到达数组的末尾,就像“字符串”末尾的 nul 字符一样。

标签: c pointers free


【解决方案1】:

主要针对 MRE。

  • 主要问题围绕这一行:

    fields[fieldsIndex] = "88888888";
    

    不正确有两个原因:

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

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

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

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

其他一些注意事项,如果您知道字符串的数量(i &lt; 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);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-02-21
    • 1970-01-01
    • 1970-01-01
    • 2011-10-28
    • 2013-06-27
    • 1970-01-01
    • 2015-03-31
    • 2017-04-02
    相关资源
    最近更新 更多