在c中的2d数组中释放2d数组时遇到的问题

在c中的2d数组中释放2d数组时遇到的问题,c,multidimensional-array,memory-management,heap-memory,free,C,Multidimensional Array,Memory Management,Heap Memory,Free,我的程序的简要概述:它包含大约500组初始参数。然后,它将这500个数据分成50个“块”,这样它就可以计算出50个数据并将结果写入文件,然后继续下一个50个“块”,等等。这是一个检查点系统。无论如何,对于每个“块”,都会创建一个名为calc\u result的结构数组来保存50个结果。每个calc_结果都包含一个名称、一个索引和一个用于实际结果的2d字符数组。然后工作完成并写入文件,当前的calc\u结果数组被释放。以下是基本程序: typedef struct { char* name

我的程序的简要概述:它包含大约500组初始参数。然后,它将这500个数据分成50个“块”,这样它就可以计算出50个数据并将结果写入文件,然后继续下一个50个“块”,等等。这是一个检查点系统。无论如何,对于每个“块”,都会创建一个名为
calc\u result
的结构数组来保存50个结果。每个
calc_结果都包含一个名称、一个索引和一个用于实际结果的2d字符数组。然后工作完成并写入文件,当前的
calc\u结果
数组被释放。以下是基本程序:

typedef struct
{
    char* name;
    int index;
    char** finals;
} calc_results;

int main(int argc, char** argv)
{
    //read in sets of initial parameters
    int numChunks = 10;
    int calcsPerChunk = 50;

    for(int i = 0; i < numChunks; i++)
    {
        calc_result** results = malloc(sizeof(calc_result*)*calcsPerChunk);
        for(int j = 0; j < calcsPerChunk; j++)
        {
             results[j] = malloc(sizeof(calc_result));
             results[j]->name = "blah";
             results[j]->index = j;
             results[j]->finals = malloc(sizeof(char*) * 12); //12 final results
             for(int k = 0; k < 12; k++)
             {
                 results[j]->finals[k] = malloc(70); //max string size is 70
             }
         }

         //DO ACTUAL WORK

         //WRITE RESULTS TO FILE

         //FREE STUFF:
         for(int a = 0; a < calcsPerChunk; a++)
         {
             for(int b = 0; b < 12; b++)
             {
                 free(results[a]->finals[b]);
             }
             free(results[a]->name);
             free(results[a]->finals);
             free(results[a]);
         }

      free(results);
     }
}
typedef结构
{
字符*名称;
整数指数;
半决赛;
}计算结果;
int main(int argc,字符**argv)
{
//读入初始参数集
int numChunks=10;
int calcsPerChunk=50;
for(int i=0;iname=“blah”;
结果[j]->指数=j;
结果[j]->finals=malloc(sizeof(char*)*12);//12最终结果
对于(int k=0;k<12;k++)
{
结果[j]->final[k]=malloc(70);//最大字符串大小为70
}
}
//实际工作
//将结果写入文件
//免费物品:
对于(int a=0;a决赛[b]);
}
免费(结果[a]->名称);
免费(结果[a]->决赛);
免费(结果[a]);
}
免费(结果);
}
}

我在释放结果方面遇到了麻烦。该程序运行10个“块”中的7个,并释放1个
calcsPerChunk
(即
i=8
a=1
b=0
),然后抛出一个指向
free(results[a]->final[b])
行的错误。该错误无效:“Program.exe”已触发断点。“我不确定我做错了什么,有人能帮忙吗?

注意:您的代码中没有数组,因此您的问题标题用词不当。您正在为指针类型分配指针,首先为每个对象分配指针,然后为每个对象分配一个存储块,然后为指针分配每个存储块的起始地址。(规则:指针不是数组,数组也不是指针——尽管在访问时,数组会根据规则转换为指向第一个元素的指针)


您唯一的问题是试图
释放(results[a]->name)未分配,然后您无法验证每个分配的返回值。除此之外,你们非常亲密。你知道你需要什么来
释放
以及在
中释放的顺序(results[a]->name)看起来更像是一个
“…duh…”
错误,而不是理解上的任何错误

您还可以通过使用取消引用的指针来调整每个分配的类型大小,而不是尝试调用
X-type
for
sizeof(X-type)
,这在某些情况下很容易出错。例如,而不是:

    calc_result** results = malloc(sizeof(calc_result*)*calcsPerChunk);
您可以使用
sizeof*results
(取消引用的指针)设置每个对象的大小,例如:

    calc_results **results = malloc (sizeof *results * calcsPerChunk);
注意:
'*'
'**'
通常与指针一起使用,而不是与类型一起使用。为什么?,语义和使指针显式。例如:

    calc_results* a, b, c;
当然不会声明指向
计算结果的三指针。相反,它声明指向
计算结果a
和两个
结构计算结果b,c
的指针。确保
“*”
位于指针上可以清楚地表明这一点,例如

    calc_results *a, b, c;
(就法律语法而言,这没有什么区别,编译器可以毫无问题地解析它——问题往往发生在人的方面)

确认您方法的快速示例

对于测试,您不需要:

int numChunks = 10;
int calcsPerChunk = 50;
3
5
(或比
1
更多的内容)就可以了)

结合一个简短的示例,通过使用取消引用的指针验证每个分配并调整每个分配的大小(并为每个级别吐出输出,只是为了好玩),您可以执行以下操作:

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

typedef struct {
    char *name;
    int index;
    char **finals;
} calc_results;

int main(void)
{
    int numChunks = 3;
    int calcsPerChunk = 5;

    for(int i = 0; i < numChunks; i++) {
        calc_results **results = malloc (sizeof *results * calcsPerChunk);
        if (!results) {
            perror ("malloc-results");
            return 1;
        }
        for(int j = 0; j < calcsPerChunk; j++)
        {
            if (!(results[j] = malloc (sizeof *results[j]))) {
                perror ("malloc-results[j]");
                return 1;
            }
            results[j]->name = "blah";
            results[j]->index = j;
            if (!(results[j]->finals=malloc(sizeof *results[j]->finals*12))) {
                perror ("malloc-results[j]->finals");
                return 1;
            }
            for(int k = 0; k < 12; k++) {
                if (!(results[j]->finals[k] = malloc(70))) {
                    perror ("malloc-results[j]->finals[k]");
                    return 1;
                }
                sprintf (results[j]->finals[k], "grade %d", k+1);
            }
        }

        /* DO ACTUAL WORK */

        /* output & free stuff */
        printf ("results[%2d]\n", i);
        for (int a = 0; a < calcsPerChunk; a++) {
            printf ("  %s %2d\n", results[a]->name, results[a]->index);
            for (int b = 0; b < 12; b++) {
                printf ("    %s\n", results[a]->finals[b]);
                free (results[a]->finals[b]);
            }
            // free(results[a]->name);
            free(results[a]->finals);
            free(results[a]);
        }

        free(results);
    }
}
始终确认已释放所有已分配的内存,并且没有内存错误


仔细检查一下,如果你还有其他问题,请告诉我。你真的非常接近,我怀疑你实际上是在实际代码中分配
name
,所以你的代码很可能已经工作了。

你没有检查内存分配
malloc()
是否成功。
免费(结果[a]->期末[b])原因错误。代码越来越长,所以我去掉了检查和内存集。分配内存时没有报告错误。其中
空闲(results[a]->name)已分配?(这是一个大问题)@esmaele-
results[j]>final[k]=malloc(70)
很好
sizeof(char)
始终是
1
。谢谢您的帮助。你说得对-我在代码中对名称进行了malloc'ed,但忘记将其放在代码示例中。你关于内存错误测试的评论让我思考,我确实在这个
calc_results
allocation code之前使用的单独函数中发现了内存泄漏。它是固定的,现在
calc\u结果
stuff工作了!不客气。很明显你明白你在做什么。深度嵌套分配中唯一的挑战是戴上“会计帽”,点上所有
“I”
并交叉所有
“T”
,以确保每个分配都以正确的顺序与
free()
配对。不,我的
$ valgrind ./bin/free_nested_struct
==13663== Memcheck, a memory error detector
==13663== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==13663== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==13663== Command: ./bin/free_nested_struct
==13663==
results[ 0]
  blah  0
    grade 1
    grade 2
    grade 3
    grade 4
    grade 5
    grade 6
    ...
    <snip>
==13663==
==13663== HEAP SUMMARY:
==13663==     in use at exit: 0 bytes in 0 blocks
==13663==   total heap usage: 213 allocs, 213 frees, 14,520 bytes allocated
==13663==
==13663== All heap blocks were freed -- no leaks are possible
==13663==
==13663== For counts of detected and suppressed errors, rerun with: -v
==13663== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)