我试图创建动态分配的集群数组,其中每个集群都有自己动态分配的点数组。
typedef struct Point
{
int ID; //each point has some ID and XY coordinates
int X;
int Y;
}Point;
typedef struct Cluster
{
int size; //how many points can cluster hold
int count; //how many points cluster actually holds
Point *points; //dynamically allocated array of points
}Cluster;
我能够初始化簇数组并使用此函数填充它:
void fill_array(Cluster **arr, int how_many_clusters)
{
*arr = (Cluster *)malloc(sizeof(Cluster) * how_many_clusters);
for(int i = 0; i < how_many_clusters; i++)
{
Point point;
point.ID = i;
point.X = i * 2;
point.Y = i * 3;
(*arr)[i].size = 1;
(*arr)[i].count = 1;
(*arr)[i].points = (Point *)malloc(sizeof(Point));
(*arr)[i].points[i] = point;
}
}
在main中我想创建数组,用前面提到的函数填充它然后释放它。
int main ()
{
Cluster *clusters;
int clusters_count = 20;
fill_array(&cluters, clusters_count);
for(int i = clusters_count - 1; i >= 0; i--)
{
free(clusters[i].points); //crash point
clusters[i].points = NULL;
}
free(clusters);
return 0;
}
当我编译并运行该程序时,它会在free
的第二次迭代中崩溃并出现分段错误。我花了两天时间在互联网上挖掘,但没有找到任何关于我做错的事情。
任何人都可以指出我无法看到的错误在哪里?
答案 0 :(得分:1)
(*arr)[i].points[i] = point;
这看起来并不正确。它应该是
(*arr)[i].points[0] = point;
答案 1 :(得分:1)
没有必要强制转换malloc
,这是不必要的。见:Do I cast the result of malloc?。 malloc
返回与任何指针兼容的void *
。演员阵容只能使水变得泥泞。只需分配指针points
,然后在解除引用的指针上调用sizeof
,例如:
(*arr)[i].points = malloc (sizeof *(*arr)[i].points);
虽然正确的分配声明,但它完全无法验证分配成功,而是检查malloc
的回报不是NULL
,例如
if (!((*arr)[i].points = malloc (sizeof *(*arr)[i].points))) {
perror ("malloc failed - points");
exit (EXIT_FAILURE);
}
*arr
的分配相同,例如
if (!(*arr = malloc (sizeof **arr * nclusters))) {
perror ("malloc failed - nclusters");
exit (EXIT_FAILURE);
}
(注意:how_many_clusters
缩写为nclusters
,我们不是在写小说)
您的主要问题是:
(*arr)[i].points[i] = point;
您只为一个Point
结构分配内存,因此points[i]
毫无意义。你分配了sizeof(Point)
- 你认为有多少人?{/ p>
由于您的目标是将point
复制到指针(*arr)[i].points
所持地址的新分配内存块,“如何访问(或设置)引用的值(例如指针指针?“( 答案: ,你取消引用指针获取值)。
这就是你需要做的一切。在解除引用[..]
时,最后没有额外的(*arr)[i].points
,只需将其与一元'*'
取消引用,例如
*(*arr)[i].points = point; /* copy struct to allocated memory */
完全放置部分,您可以执行以下操作:
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int ID; //each point has some ID and XY coordinates
int X;
int Y;
} Point;
typedef struct {
int size; //how many points can cluster hold
int count; //how many points cluster actually holds
Point *points; //dynamically allocated array of points
} Cluster;
void fill_array (Cluster **arr, int nclusters)
{
if (!(*arr = malloc (sizeof **arr * nclusters))) {
perror ("malloc failed - nclusters");
exit (EXIT_FAILURE);
}
for (int i = 0; i < nclusters; i++)
{
Point point;
point.ID = i;
point.X = i * 2;
point.Y = i * 3;
(*arr)[i].size = 1;
(*arr)[i].count = 1;
if (!((*arr)[i].points = malloc (sizeof *(*arr)[i].points))) {
perror ("malloc failed - points");
exit (EXIT_FAILURE);
}
*(*arr)[i].points = point; /* copy struct to allocated memory */
}
}
int main (void) {
Cluster *clusters;
int clusters_count = 20;
fill_array (&clusters, clusters_count);
for(int i = 0; i < clusters_count; i++)
{
free(clusters[i].points); //crash point
clusters[i].points = NULL;
}
free (clusters);
return 0;
}
(注意:,不必须free
每个clusters[i].points
按相反顺序。(不是错了,没有必要按照自己的方式去做。)只需在你循环的过程中释放它们。)
示例使用/验证
在你编写的动态分配内存的任何代码中,你有2个职责关于任何分配的内存块:(1)总是保留一个指向起始地址的指针内存块,(2)当不再需要时,它可以释放。
必须使用内存错误检查程序,以确保您不会尝试访问内存或写入超出/超出已分配块的范围,尝试读取或基于未初始化值的条件跳转,最后,确认您释放了所有已分配的内存。
对于Linux valgrind
是正常的选择。每个平台都有类似的记忆检查器。它们都很简单易用,只需通过它运行程序即可。
$ valgrind ./bin/fillclusters_alloc
==26217== Memcheck, a memory error detector
==26217== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==26217== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==26217== Command: ./bin/fillclusters_alloc
==26217==
==26217==
==26217== HEAP SUMMARY:
==26217== in use at exit: 0 bytes in 0 blocks
==26217== total heap usage: 21 allocs, 21 frees, 560 bytes allocated
==26217==
==26217== All heap blocks were freed -- no leaks are possible
==26217==
==26217== For counts of detected and suppressed errors, rerun with: -v
==26217== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
始终确认已释放已分配的所有内存并且没有内存错误。
仔细看看,如果您有其他问题,请告诉我。
答案 2 :(得分:0)
以下一点:
(*arr)[i].points = (Point *)malloc(sizeof(Point));
(*arr)[i].points[i] = point;
没有分配正确的内存量。 i
将是大于零的某个数字,但您只为一个 Point
分配了空间。你正在粉碎你的堆,然后会发生崩溃。