C - 释放动态分配的数组后的分段错误

时间:2017-12-06 23:14:11

标签: c arrays struct segmentation-fault

我试图创建动态分配的集群数组,其中每个集群都有自己动态分配的点数组。

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的第二次迭代中崩溃并出现分段错误。我花了两天时间在互联网上挖掘,但没有找到任何关于我做错的事情。 任何人都可以指出我无法看到的错误在哪里?

3 个答案:

答案 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分配了空间。你正在粉碎你的堆,然后会发生崩溃。