为具有双指针的结构内的结构的动态数组分配内存**

时间:2019-06-04 19:36:25

标签: c arrays pointers memory-management struct

当我使用此代码时,我想转向如下结构数组的每个元素:

array[0]->X;
array[1]->X;

我尽力了,但是在所有情况下,我都遇到了细分错误。我在做什么错了?

请查看#if 0 #endif

之间的块
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <inttypes.h>

typedef struct
{
    double X;
    double Y;

} ArrayOfStructures;

typedef struct
{
    uint_fast64_t length;

    ArrayOfStructures **array;

} Points;

typedef struct
{
    Points *points;

} Config;

void add_new_array(Config *conf)
{
    printf("conf=%p\n",conf);
    printf("conf->points=%p\n",conf->points);
    printf("conf->points->length=%zu\n",conf->points->length);
    printf("conf->points->array=%p\n",conf->points->array);
    #if 0
    ArrayOfStructures *temp = (ArrayOfStructures*)calloc(conf->points->length,sizeof(ArrayOfStructures));
    printf("temp=%p\n",temp);
    // Segmentation fault
    *conf->points->array = temp;
    #else
    conf->points->array  = (ArrayOfStructures **)calloc(conf->points->length,sizeof(ArrayOfStructures *));
    #endif
    printf("conf->points->array=%p\n",conf->points->array);
}

void another_function(Config *conf)
{
    conf->points->length = 1;

    add_new_array(conf);

    conf->points->array[0]->X = 0.1;
    conf->points->array[0]->Y = 0.2;

    printf("The result: X=%.12f, Y=%.12f, length=%zu\n",conf->points->array[0]->X,conf->points->array[0]->Y,conf->points->length);
}

void some_function(Config * conf)
{
    // To pass the structure to another function
    another_function(conf);
}

int main(void)
{
    // Stack's allocated memory
    Config conf_;
    Config *conf = &conf_;
    memset(conf,0x0,sizeof(Config));

    // Stack's allocated memory
    Points points;
    memset(&points,0x0,sizeof(Points));
    conf->points = &points;

    some_function(conf);

    return(EXIT_SUCCESS);
}

编译使用:

gcc -D_SVID_SOURCE -g -ggdb -ggdb1 -ggdb2 -ggdb3 -O0 -DDEBUG -std=c11 -Wall --pedantic arryay.c -o array

我试图找到处理双指针的答案,但是一切都很混乱。

2 个答案:

答案 0 :(得分:1)

您似乎没有将length初始化为有意义的值。因此,您实际上并没有分配内存,因为您在第一个参数为零的情况下调用了calloc()

(免责声明:我尚未测试代码,但这似乎是错误的。)

答案 1 :(得分:1)

根据comment,您已经非常接近想要的东西。

使用结构数组

这是您的代码的改编版。主要更改是使用ArrayOfStructs *array而不是使用指针到指针。另外,由于您决定对数据类型使用uint_fast64_t,因此必须使用PRIuFAST64中的<inttypes.h>来获取正确的格式字符串。最好将其更改为size_t;您不会在任何合理的系统上发现性能差异(但是代码使用格式PRIuFAST64)。

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <inttypes.h>

typedef struct
{
    double X;
    double Y;
} ArrayOfStructures;

typedef struct
{
    uint_fast64_t length;
    ArrayOfStructures *array;
} Points;

typedef struct
{
    Points *points;
} Config;

static
void add_new_array(Config *conf)
{
    printf("conf=%p\n", conf);
    printf("conf->points=%p\n", conf->points);
    printf("conf->points->length=%" PRIuFAST64 "\n", conf->points->length);
    printf("conf->points->array=%p\n", conf->points->array);

    ArrayOfStructures *temp = calloc(conf->points->length, sizeof(ArrayOfStructures));
    printf("temp=%p\n", temp);
    conf->points->array = temp;
    printf("conf->points->array=%p\n", conf->points->array);
}

static
void another_function(Config *conf)
{
    conf->points->length = 1;

    add_new_array(conf);

    conf->points->array[0].X = 0.1;
    conf->points->array[0].Y = 0.2;

    printf("The result: X=%.12f, Y=%.12f, length=%" PRIuFAST64 "\n",
           conf->points->array[0].X, conf->points->array[0].Y, conf->points->length);
}

static
void some_function(Config *conf)
{
    // To pass the structure to another function
    another_function(conf);
}

int main(void)
{
    // Stack's allocated memory
    Config conf_;
    Config *conf = &conf_;
    memset(conf, 0x0, sizeof(Config));

    // Stack's allocated memory
    Points points;
    memset(&points, 0x0, sizeof(Points));
    conf->points = &points;

    some_function(conf);

    return(EXIT_SUCCESS);
}

运行时会产生:

conf=0x7ffeed6883f8
conf->points=0x7ffeed688400
conf->points->length=1
conf->points->array=0x0
temp=0x7fef13c02a80
conf->points->array=0x7fef13c02a80
The result: X=0.100000000000, Y=0.200000000000, length=1

它不会崩溃。我尚未在Valgrind下运行它。它将报告分配的内存泄漏。

对于没有数组的类型,您的类型名称ArrayOfStructures似乎非常不合适。我曾希望给它起一个Point之类的名字。我认为您的Config结构已被最小化(如果是,谢谢)。如果不是,那么持有指向另一个结构的单个指针的结构不会给您带来任何好处。这只会减慢您对数据的访问速度-大大超过了使用uint_fast64_t而不是size_t带来的好处。您需要注意Config结构的内存分配;您目前无法简单地释放Config及其子结构中的所有内容。

使用指向结构的指针数组

这与上一代码非常相似,但是您需要额外的一组内存分配。我将其圈成一个循环,因为使用此设计的唯一原因是允许您分别分配指向的结构。否则,它就是不必要的复杂。我做了一些小小的清理;还有更多可能的改进。我添加了一个结构转储函数dump_points(),我可以并且确实使用它来打印不同点的值。

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <inttypes.h>

typedef struct
{
    double X;
    double Y;
} ArrayOfStructures;

typedef struct
{
    size_t length;
    ArrayOfStructures **array;
} Points;

typedef struct
{
    Points *points;
} Config;

static void dump_points(const char *tag, const Points *points)
{
    printf("%s (%zu, %p)\n", tag, points->length, (void *)points);
    for (size_t i = 0; i < points->length; i++)
        printf("%zu: (%.12f, %.12f) %p\n", i, points->array[i]->X, points->array[i]->Y,
               (void *)points->array[i]);
}

static
void add_new_array(Config *conf)
{
    printf("conf=%p\n", (void *)conf);
    printf("conf->points=%p\n", (void *)conf->points);
    printf("conf->points->length=%zu\n", conf->points->length);
    printf("conf->points->array=%p\n", (void *)conf->points->array);

    conf->points->array = calloc(conf->points->length, sizeof(conf->points->array[0]));
    for (size_t i = 0; i < conf->points->length; i++)
        conf->points->array[i] = calloc(1, sizeof(conf->points->array[i][0]));
    printf("conf->points->array=%p\n", (void *)conf->points->array);
    printf("conf->points->array[0]=%p\n", (void *)conf->points->array[0]);
    dump_points("Inside add new array", conf->points);
}

static
void another_function(Config *conf)
{
    conf->points->length = 3;

    add_new_array(conf);

    conf->points->array[0]->X = 0.1;
    conf->points->array[0]->Y = 0.2;
    conf->points->array[1]->X = 1.1;
    conf->points->array[1]->Y = 1.2;
    conf->points->array[2]->X = 2.1;
    conf->points->array[2]->Y = 2.2;

    dump_points("Inside another function", conf->points);
}

static
void some_function(Config *conf)
{
    // To pass the structure to another function
    another_function(conf);
    dump_points("Inside some function", conf->points);
}

int main(void)
{
    // Stack's allocated memory
    Config conf_;
    Config *conf = &conf_;
    memset(conf, 0x0, sizeof(Config));

    // Stack's allocated memory
    Points points;
    memset(&points, 0x0, sizeof(Points));
    conf->points = &points;

    some_function(conf);
    dump_points("Inside main", conf->points);

    return(EXIT_SUCCESS);
}

示例输出(macOS 10.14.5 Mojave; GCC 9.1.0):

conf=0x7ffee6f6b408
conf->points=0x7ffee6f6b410
conf->points->length=3
conf->points->array=0x0
conf->points->array=0x7f9c0a402a70
conf->points->array[0]=0x7f9c0a402a90
Inside add new array (3, 0x7ffee6f6b410)
0: (0.000000000000, 0.000000000000) 0x7f9c0a402a90
1: (0.000000000000, 0.000000000000) 0x7f9c0a402aa0
2: (0.000000000000, 0.000000000000) 0x7f9c0a402ab0
Inside another function (3, 0x7ffee6f6b410)
0: (0.100000000000, 0.200000000000) 0x7f9c0a402a90
1: (1.100000000000, 1.200000000000) 0x7f9c0a402aa0
2: (2.100000000000, 2.200000000000) 0x7f9c0a402ab0
Inside some function (3, 0x7ffee6f6b410)
0: (0.100000000000, 0.200000000000) 0x7f9c0a402a90
1: (1.100000000000, 1.200000000000) 0x7f9c0a402aa0
2: (2.100000000000, 2.200000000000) 0x7f9c0a402ab0
Inside main (3, 0x7ffee6f6b410)
0: (0.100000000000, 0.200000000000) 0x7f9c0a402a90
1: (1.100000000000, 1.200000000000) 0x7f9c0a402aa0
2: (2.100000000000, 2.200000000000) 0x7f9c0a402ab0

令人欣慰的是,在将数据传递回功能链时,数据没有损坏。