【问题标题】:function returning an instance of struct返回结构实例的函数
【发布时间】:2018-07-10 05:08:39
【问题描述】:
struct Temp {};

struct Temp *newTemp() {
    struct Temp *temp = malloc(sizeof(struct Temp));
    return temp;
}


int main() {
    struct Temp *temp = newTemp(); // any problem?
    return 0;
}

从函数内部(工厂方法)返回结构的实例有什么问题吗?

请问指针会无效。有人建议,如果你返回一个指针,它应该指向调用者堆栈上的某个东西、一个全局的或堆上的某个东西

【问题讨论】:

  • 唯一的问题是内存泄漏。由于您即将退出,因此在这种情况下这不是主要问题,但总的来说,内存泄漏是一个问题,尤其是在长时间运行的程序中。
  • 一切都很好,只是不要忘记free在适当位置的指针,例如在退出主函数之前。

标签: c pointers memory-management struct


【解决方案1】:

根据标准,C 结构必须包含至少一个成员,但 gcc 允许将其作为扩展。

而且你所做的是合法的——你可以返回指向动态分配内存的指针并在其他函数中使用它。

malloc 分配的内存具有超出其声明范围的存储期限(分配的存储期限)。您可以毫无问题地使用它。

预计您将释放分配的内存并检查 malloc 的返回值(避免您在失败时取消引用 null)。

Standard N1570 C11 标准在§7.22.3内存管理函数下也有提及:

....已分配对象的生命周期从分配一直延续到解除分配

【讨论】:

    【解决方案2】:

    你有两种方法可以从函数中返回一个结构体:

    1. 返回指向动态分配结构的指针(您的示例代码)

      动态分配的对象的生命周期会一直延长,直到它被解除分配,因此调用者将能够使用它。简单地说,当您不再需要它时,您一定不要忘记释放它。不这样做称为内存泄漏。所以一个固定的版本应该是:

      struct Temp {
          int i;          // a struct should not be empty...
      };
      
      struct Temp *newTemp() {
          struct Temp *temp = malloc(sizeof(struct Temp));
          return temp;
      }
      
      int main() {
          struct Temp *temp = newTemp(); // any problem?
          // use temp...
          free(temp);
          return 0;
      }
      
    2. 返回一个临时对象

      结构是 C 中的第一类对象,因此您可以直接分配给它。然后,您可以在函数中构建一个结构并返回它(注意:返回指向它的指针实际上会返回一个悬空指针,因为生命周期将在函数返回时结束)。所以另一种方法是:

      struct Temp {
          int i;          // a struct should not be empty...
      };
      
      struct Temp newTemp() {
          struct Temp temp;
          // set values of temp members...
          return temp;
      }
      
      int main() {
          struct Temp temp = newTemp(); // no problem?
          // use temp...
          return 0;
      }
      

      这里的好消息是结构是调用者中的自动对象,因此它不必(也不应该)是 free-d。 decent 编译器甚至可以通过让被调用者直接使用调用者自动存储来删除副本。

    【讨论】:

      【解决方案3】:

      malloc 在堆上分配内存。在堆上分配的对象具有静态存储持续时间。从函数返回指向malloc 分配的对象的指针是有效的。

      请注意,您使用的空结构不是标准 C。GCC 提供此功能作为扩展。

      【讨论】:

      • 留下评论指出我做错了什么会很棒?
      • 我没有投反对票,但 “堆上的内存,它具有静态存储持续时间” 似乎是对正式术语的滥用。
      • @StoryTeller;我没明白。能详细点吗?
      • 我说的是在n1570 中搞砸这一点。我认为您说错了可能是分配的存储持续时间?
      • 我现在明白你的意思了。尽管坦率地说,我认为最好用一两句话来解释它,而不是过多地使用正式术语。只是我的两分钱。无论如何都要 +1
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-09-16
      • 1970-01-01
      • 2013-07-20
      • 1970-01-01
      • 2021-12-24
      • 1970-01-01
      相关资源
      最近更新 更多