为具有双指针的结构内的动态结构数组分配内存**
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 *array
和array[0].X
,还是一个指向结构的指针的动态数组(它使用指向指针表示法的指针,但不是t 标题暗示你在追求什么)?
好问题。在我看来,如何转向结构数组[0]->X的元素并不重要;或数组[0].X;我想用最快的方式访问所有这些元素,因为高性能对我来说很重要。
双指针(即指向指针的指针)需要两次内存访问才能获取数据;单指针需要一个。那么,您可能应该使用更简单的版本。
另外,不要在一行中隐藏多个语句,如Points points; memset(&points,0x0,sizeof(Points)); conf->points = &points;
。每个语句使用一行。
@JonathanLeffler 我想创建一个结构的动态数组,而不是结构指针的动态数组。
【参考方案1】:
根据你的comment,你已经非常接近你想要的了。
使用结构数组
这是对您的代码的改编。主要变化是使用ArrayOfStructs *array
,而不是使用指向指针的指针。此外,由于您已决定使用 uint_fast64_t
作为数据类型,因此您必须使用来自 <inttypes.h>
的 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 语言结构体 ( 结构体中嵌套一级指针 | 分配内存时先 为结构体分配内存 然后再为指针分配内存 | 释放内存时先释放 指针成员内存 然后再释放结构头内存 )