【问题标题】:How to return a pointer struct array from a function in C如何从C中的函数返回指针结构数组
【发布时间】:2018-03-28 04:52:48
【问题描述】:

假设您有一个函数,函数输出将是链表的头尾地址(用于将链表复制到另一个地址的函数):

struct path *copyPath(struct path *head) {

  struct path *temp = malloc(sizeof (struct path));  

  // array of newHead and newTail
  struct path *resultPath[2];

  struct path *newHead = NULL;
  struct path *newTail = NULL;    

  while (head != NULL) {
      temp = malloc(sizeof (struct path));
      if (newHead == NULL) {
          // Add a new node to the first of list and save newHead as the beginning of the list
      } else {            
          // Add the other nodes and save the last node address as newTail
      }
      head = head -> next;
  }      

  resultPath[0] = newHead;
  resultPath[1] = newTail;        

  return resultPath;
}

我定义了一个struct path 的数组并将其返回。在主函数中定义了一个数组:

struct path *newPath;
newPath = copyPath(path_head, nextNode);

当我运行它时,我在 newPath 中没有任何东西,它是空的。

那么,返回这些地址的最佳方式是什么?为什么我在 newPath 中没有它?

另外,当我使用时:

struct path *newPath[2];
newPath = copyPath(path_head, nextNode);

我有一个错误:error: assignment to expression with array type

如何将这两个值传递给主函数?

【问题讨论】:

  • 1path*[] 转换为path* 是危险的。 2 打开你的编译器警告将帮助你调试你的程序。 3 minimal reproducible example 请。
  • 没有调用上下文...我们怎么能说一些有趣的事情呢?另外,resultPath 是一个指向路径的指针数组,您返回指向路径的指针。请使用好的编译器并仔细阅读警告信息。当有人说过马路很危险时,你至少需要四处看看。
  • @user202729 不,这不是我的答案。我在 Google、SO 等上搜索过。
  • struct path *resultPath[2]; 被声明为 copyPath 的本地。当copyPath 返回时,所有局部变量都被销毁(函数栈帧内存被释放以供重用)。为了返回resultPath,您需要为其动态分配存储空间并返回一个指针来执行此操作——正如上面已经提供的所有链接中所解释的那样。

标签: c arrays function linked-list


【解决方案1】:

除了 cmets,您的功能还有两个主要问题,1)您通过覆盖第一个分配的内存块的地址来泄漏内存;和 2) 您尝试返回 returnPath,它的自动存储持续时间声明为本地 copyPath

内存泄漏

在分配指针temp 之前,您会在函数中泄漏内存,例如

struct path *temp = malloc(sizeof (struct path));  
...
while (head != NULL) {
    temp = malloc(sizeof (struct path));

通过在将原始指针分配给另一个变量之前为temp 分配第二次,您将丢失temp 中指向分配的第一个内存块的原始指针。从那时起,您的程序将永远无法释放该内存。

返回声明为函数本地自动存储的数组

当我运行它时,我在 newPath 中没有任何东西,它是空的。

struct path *resultPath[2]; 声明了一个 指向struct path 的指针数组(其中两个)。 resultPath 的自动存储在其函数堆栈框架内声明为 copyPath 本地。当copyPath返回时,所有具有自动存储时长的局部变量都被销毁(函数栈帧内存被释放以供重用)。这是C11 Standard - §6.2.4 Storage durations of objects明确解释的

1) 对象具有决定其生命周期的存储持续时间。有四种存储持续时间:静态、线程、自动和分配。 7.22.3 中描述了分配的存储空间。

2) 对象的生命周期是程序执行过程中保证为其保留存储空间的部分。一个对象存在,具有一个常量地址,33) 并在其生命周期内保留其最后存储的值。34) 如果一个对象在其生命周期之外被引用,则行为是未定义的。当指针指向(或刚刚过去)的对象到达其生命周期的末尾时,指针变得不确定。

6) 对于这样一个没有可变长度数组类型的对象,它的生命周期从进入到与之关联的块中延长直到该块的执行结束于任何方式

强调我们的

那么,返回这些地址的最佳方式是什么?为什么我在 newPath 中没有它?

为了返回resultPath,你需要为它动态分配存储空间并返回一个指向它的指针。具有已分配存储持续时间的对象会在程序的生命周期内延长或直到它们被释放。

为能够存储两个指向struct path 的指针的对象声明和分配的最简单方法是声明一个指向结构路径的指针,(实际上是一个动态指针数组) , 并为两个指针分配存储空间,例如

/* allocate & validate 2 pointers to struct path */
struct path **resultPath = malloc (sizeof *resultPath * 2);
if (!resultPath) {        /* always validate all memory allocations */
    perror ("malloc resultPath failed.");
    return NULL;
}
...
resultPath[0] = newHead;  /* newHead & newTail must point to allocated memory */
resultPath[1] = newTail;        

return resultPath;

您现在可以安全地 return resultPathresultPath 的存储空间将在返回后继续存在,从而消除您对不再可用的内存的访问。然后,您可以在调用程序中分别通过newPath[0]newPath[1] 访问newHeadnewTail

您还需要将copyPath 的返回类型更改为stuct path **,例如

struct path **copyPath(struct path *head)

并更新调用者中的类型。

【讨论】:

    【解决方案2】:

    每当您分配动态内存(使用 malloc、calloc、realloc)时,将返回地址适当地转换为正确的数据类型。因为这些函数返回 void 指针。在下面的行中,您将 void 指针类型地址分配给 struct path 类型指针。

    temp = malloc(sizeof (struct path));

    可以写成:

    temp = (struct path *)malloc(sizeof (struct path));

    第二件事,您正在返回一个类型为“struct path”的指针数组,但是您正在将这个返回的指针值数组收集在 main 中的一个“struct path”类型的常规指针中,这违反了 C 标准。更正此错误并尝试运行代码。

    在Main中使用指针数组来收集返回值:

    结构路径 *newPath[2];

    newPath = copyPath(path_head, nextNode)

    【讨论】:

    • 报错:error: assignment to expression with array type
    • malloc的返回不用强制转换,没必要。见:Do I cast the result of malloc?
    • @DavidC.Rankin 没有问题,我的问题是如何将这两个值返回给主函数?
    猜你喜欢
    • 2015-08-25
    • 1970-01-01
    • 2016-04-21
    • 1970-01-01
    • 1970-01-01
    • 2017-06-13
    • 2017-03-22
    相关资源
    最近更新 更多