从 C 中的函数返回具有多个可变长度数组的结构
returning struct with multiple variable length arrays from function in C
我一直在寻找解决方案。我想我知道发生了什么以及解决方案应该是什么,但是我不太确定如何实施它。
我有一个包含两个可变长度数组的结构。这些将在函数中填充并返回给调用函数进行处理。
问题似乎是当被调用函数超出范围时,可变长度数组的任何分配都变得无效。我猜想一个解决方案可能是在堆上分配内存,然后在完成调用函数中的结构后释放内存。下面给出代码示例
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 */
.
.
.
}
局部变量有其生命周期 - 仅在其函数的堆栈帧内。
如果你想创建一个变量,然后在函数之外使用它,你需要声明一个具有“更大”范围的变量,比如在堆上动态分配它。
堆变量的生命周期是从内存请求(malloc)到'free'或程序结束。
所以,如果你想 return 这个结构应该是这样的:
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);
首先,您的结构中实际上没有两个可变长度数组。如果你这样做了,那将是一个错误。你实际上拥有的是两个指针,每个指针都可能指向任意大小数组的第一个元素。
您遇到的问题是,您将在 field
函数中创建为局部变量的数组分配给返回的结构(或更准确地说是指向其第一个元素的指针) .这意味着您要从函数返回局部变量的地址。这些局部变量的生命周期在函数退出时结束,因此这些指针指向的内存是无效的(实际上指针值本身是 不确定)并且尝试取消引用这些指针会触发 undefined behavior.
另请注意,可变长度数组无法初始化。
您需要为 A
和 B
字段动态分配 space 并写入这些数组。但是,如果您不想复制单个成员,则可以使用现有的本地数组来执行 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;
}
我一直在寻找解决方案。我想我知道发生了什么以及解决方案应该是什么,但是我不太确定如何实施它。
我有一个包含两个可变长度数组的结构。这些将在函数中填充并返回给调用函数进行处理。 问题似乎是当被调用函数超出范围时,可变长度数组的任何分配都变得无效。我猜想一个解决方案可能是在堆上分配内存,然后在完成调用函数中的结构后释放内存。下面给出代码示例
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 */
.
.
.
}
局部变量有其生命周期 - 仅在其函数的堆栈帧内。
如果你想创建一个变量,然后在函数之外使用它,你需要声明一个具有“更大”范围的变量,比如在堆上动态分配它。
堆变量的生命周期是从内存请求(malloc)到'free'或程序结束。
所以,如果你想 return 这个结构应该是这样的:
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);
首先,您的结构中实际上没有两个可变长度数组。如果你这样做了,那将是一个错误。你实际上拥有的是两个指针,每个指针都可能指向任意大小数组的第一个元素。
您遇到的问题是,您将在 field
函数中创建为局部变量的数组分配给返回的结构(或更准确地说是指向其第一个元素的指针) .这意味着您要从函数返回局部变量的地址。这些局部变量的生命周期在函数退出时结束,因此这些指针指向的内存是无效的(实际上指针值本身是 不确定)并且尝试取消引用这些指针会触发 undefined behavior.
另请注意,可变长度数组无法初始化。
您需要为 A
和 B
字段动态分配 space 并写入这些数组。但是,如果您不想复制单个成员,则可以使用现有的本地数组来执行 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;
}