从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 的结构并且这些指针必须指向生命周期将比结构本身(或结构的任何副本)更长的东西。 您所做的基本上是返回指向局部变量的指针,这是从未被允许的。局部(非静态)变量在其作用域结束之前都有一个生命周期。对于数组AB,这是函数返回的时间。参见例如How to access a local variable from a different function using pointers? 关于这个主题的一个较早的问题。 【参考方案1】:

首先,您的结构中实际上没有两个可变长度数组。如果你这样做了,那将是一个错误。你实际拥有的是两个指针,每个指针都可以指向任意大小数组的第一个元素。

您遇到的问题是,您将在 field 函数中创建为局部变量的数组并将它们(或更准确地说是指向它们的第一个元素的指针)分配给正在返回的结构。这意味着您要从函数返回局部变量的地址。这些局部变量的生命周期在函数退出时结束,因此这些指针指向的内存无效(实际上指针值本身是 indeterminate)并尝试取消引用这些指针会触发 undefined behavior。

还要注意不能初始化变长数组。

您需要为AB 字段动态分配空间并写入这些数组。但是,如果您不想复制单个成员,则可以使用现有的本地数组来执行 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 是标识符在源代码中可见的位置。对象存在时(为其保留内存)是 lifetimestorage duration @Eric Postpischil 正确,我改了,谢谢!

以上是关于从C中的函数返回具有多个可变长度数组的结构的主要内容,如果未能解决你的问题,请参考以下文章

创建一个具有可变长度数组的接口,其中包含 TypeScript/Angular4 中的对象

如何在从 C 到 C# 的结构中获取非托管可变长度 C 数组?

是否需要从堆栈中分配 C 可变长度数组?

具有标量值函数的可变长度 NVARCHAR

C ++中的可变长度数组开销?

在其内存应该已被释放后访问可变长度数组