从C中的函数返回具有多个可变长度数组的结构
Posted
技术标签:
【中文标题】从C中的函数返回具有多个可变长度数组的结构【英文标题】:returning struct with multiple variable length arrays from function in C 【发布时间】:2021-08-01 21:49:45 【问题描述】:一段时间以来,我一直在寻找解决方案。我想我知道发生了什么以及解决方案应该是什么,但是我不太确定如何实施。
我有一个包含两个可变长度数组的结构。这些将在函数中填充并返回给调用函数以进行处理。 问题似乎是当被调用函数超出范围时,可变长度数组的任何分配都变得无效。我猜想一个解决方案可能是在堆上分配内存,然后在我完成调用函数中的结构后释放内存。下面给出一个代码示例
struct fields
int n;
double * A;
double * B;
;
struct fields field()
int n = 4;
double A[n] = 1, 2, 3, 4 ;
double B[n] = 1, 2, 3, 4 ;
struct fields field;
field.n = n;
field.A = A;
field.B = B;
/* field can be accessed with n, A, B set properly */
return field;
double calling_function()
struct fields field1 = field();
/* field1 contains n but A and B have not returned */
.
.
.
【问题讨论】:
I would guess that a solution may be to allocate the memory on the heap and then free the memory once I am done with the struct in the calling function.
-- 这可能是个不错的猜测。
吹毛求疵,但你没有可变长度数组的结构(这实际上是不可能的),但是你有一个带有 pointers 的结构并且这些指针必须指向生命周期将比结构本身(或结构的任何副本)更长的东西。
您所做的基本上是返回指向局部变量的指针,这是从未被允许的。局部(非静态)变量在其作用域结束之前都有一个生命周期。对于数组A
和B
,这是函数返回的时间。参见例如How to access a local variable from a different function using pointers? 关于这个主题的一个较早的问题。
【参考方案1】:
首先,您的结构中实际上没有两个可变长度数组。如果你这样做了,那将是一个错误。你实际拥有的是两个指针,每个指针都可以指向任意大小数组的第一个元素。
您遇到的问题是,您将在 field
函数中创建为局部变量的数组并将它们(或更准确地说是指向它们的第一个元素的指针)分配给正在返回的结构。这意味着您要从函数返回局部变量的地址。这些局部变量的生命周期在函数退出时结束,因此这些指针指向的内存无效(实际上指针值本身是 indeterminate)并尝试取消引用这些指针会触发 undefined behavior。
还要注意不能初始化变长数组。
您需要为A
和B
字段动态分配空间并写入这些数组。但是,如果您不想复制单个成员,则可以使用现有的本地数组来执行 memcpy
。
struct fields field()
double A[4] = 1, 2, 3, 4 ;
double B[4] = 1, 2, 3, 4 ;
struct fields field;
field.n = 4;
field.A = malloc(sizeof A);
field.B = malloc(sizeof B);
memcpy(field.A, A, sizeof A);
memcpy(field.B, B, sizeof B);
return field;
【讨论】:
感谢所有 cmets 和两个解决方案,dbush 的版本成功了!无需重新编写其余代码来处理字段的指针实例。非常感谢,这为我节省了很多时间。【参考方案2】:局部变量有其生命周期 - 仅在其函数的堆栈框架内。
如果你想创建一个变量然后在函数之外使用它,你需要声明一个具有“更大”范围的变量,比如在堆上动态分配它。
堆变量的生命周期是从内存请求(malloc)到“空闲”或程序结束。
所以,如果你想返回这个结构,它应该是这样的:
struct fields *field()
struct fields *field = (struct fields *)malloc(sizeof(struct fields));
if (NUUL == filed)
return (NULL);
field->n = 4;
field->A = (double *)malloc(sizeof(double) * n);
//check if malloc fail
field->B = (double *)malloc(sizeof(double) * n);
//check if malloc fail
//assign A and B their values
return (field);
**别忘了释放这个分配
free(field->A);
free(field->B);
free(field);
【讨论】:
Scope 是标识符在源代码中可见的位置。对象存在时(为其保留内存)是 lifetime 或 storage duration。 @Eric Postpischil 正确,我改了,谢谢!以上是关于从C中的函数返回具有多个可变长度数组的结构的主要内容,如果未能解决你的问题,请参考以下文章
创建一个具有可变长度数组的接口,其中包含 TypeScript/Angular4 中的对象