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

Posted

技术标签:

【中文标题】为具有双指针的结构内的动态结构数组分配内存**【英文标题】:Allocate memory for dynamic array of structures inside a structure with double pointer** 【发布时间】:2019-10-20 08:38:23 【问题描述】:

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

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

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

【问题讨论】:

您是要创建一个动态的结构数组,这需要ArrayOfStructures *arrayarray[0].X,还是一个指向结构的指针的动态数组(它使用指向指针表示法的指针,但不是t 标题暗示你在追求什么)? 好问题。在我看来,如何转向结构数组[0]->X的元素并不重要;或数组[0].X;我想用最快的方式访问所有这些元素,因为高性能对我来说很重要。 双指针(即指向指针的指针)需要两次内存访问才能获取数据;单指针需要一个。那么,您可能应该使用更简单的版本。 另外,不要在一行中隐藏多个语句,如Points points; memset(&amp;points,0x0,sizeof(Points)); conf-&gt;points = &amp;points;。每个语句使用一行。 @JonathanLeffler 我想创建一个结构的动态数组,而不是结构指针的动态数组。 【参考方案1】:

根据你的comment,你已经非常接近你想要的了。

使用结构数组

这是对您的代码的改编。主要变化是使用ArrayOfStructs *array,而不是使用指向指针的指针。此外,由于您已决定使用 uint_fast64_t 作为数据类型,因此您必须使用来自 &lt;inttypes.h&gt;PRIuFAST64 来获取正确的格式字符串。最好改成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

令人欣慰的是,数据在返回函数链时并未损坏。

【讨论】:

非常感谢您的工作示例。你是对的,这个问题的真实代码已经被最小化了。我保留了整个函数调用树和结构嵌套的原始形式,简化了其他所有内容。 Valgrind 我的日常工具,我可以毫无问题地释放内存。但是指针和它的取消引用有时让我哭) 好吧,我理解我的错误。但是,我想知道这段代码应该如何使用指向结构的动态指针数组? 优秀。再一次非常感谢你。 ^_^【参考方案2】:

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

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

【讨论】:

未初始化的长度是我的错。不幸的是,我无法更改源代码的文本,因为这个网站有一个错误。但是如果你尝试添加 conf->points->length = 1;在 another_function() 调用开始时,什么都不会改变。分段错误保持不变。

以上是关于为具有双指针的结构内的动态结构数组分配内存**的主要内容,如果未能解决你的问题,请参考以下文章

在C中为结构指针数组成员分配地址

C 语言结构体 ( 结构体中嵌套一级指针 | 分配内存时先 为结构体分配内存 然后再为指针分配内存 | 释放内存时先释放 指针成员内存 然后再释放结构头内存 )

C++ 动态内存分配与结构中的数组

在 C 中声明指向结构的指针数组,但在需要之前不为结构分配内存

将二维数组分配为结构成员

双指针将 char 数组值分配给 char 数组,结构使用 char 指针