从函数返回对象的最佳方法是什么(C)

时间:2017-05-11 18:23:22

标签: c pointers struct

这有点是一个主观问题,但似乎应该有一个标准。我正在制作树状数据结构,我想知道从函数传递新节点的最佳方法。我有几个想法,但我不知道哪个是最安全/最有效的。

这是我的代码的简化:

typedef struct Node {
    struct Node *left;
    struct Node *right;
    int value;
} Node;

int f() {
    //do stuff
}

Node *new_node() {
    Node n = {NULL, NULL, f()};
    return &n;
}

int main() {
    Node a = {new_node(), new_node(), 0};
}

显然,这不起作用,因为new_node()函数返回的指针指向堆栈分配的数据,这些数据将在new_node()结束后立即释放。但是解决这个问题的最佳方法是什么?

一种可能性是在堆上分配n,如下所示:

Node *new_node() {
    Node *n = (Node *) malloc(sizeof(Node)); //unsure if the cast is necessary here, but that's not relevant
    n->left = NULL;
    n->right = NULL;
    n->value = f();
    return n;
}

虽然这感觉不对,因为它要求调用者函数直接处理内存清除,这可能会很快变得混乱。

我见过的另一个选项(特别是当对象是数组或缓冲区而不是对象时)是传递指向函数的指针,只是修改指针的内容。

void new_node(Node *n) {
    n->left = NULL;
    n->right = NULL;
    n->value = f();
}

int main() {
    Node n = {NULL, NULL, 0};
    Node n1 = n;
    new_node(&n);
    new_node(&n1);
    Node a = {&n, &n1, 0};
}

或者你可以直接传递数据,特别是因为在这种情况下Node是如此之小:

 Node new_node() {
     Node n = {NULL, NULL, f()}
     return n;
 }
虽然我不确定,但这似乎会慢一些。

关于这个主题已经有一些答案,但是它们都是用C ++编写的,并且处理引用和指针,我担心我不能真正理解它们之间的区别。

执行此操作的标准方法是什么?

(对不起,如果这太长了)

2 个答案:

答案 0 :(得分:5)

您已涵盖所有四种可用方法,包括一种无法使用的方法。在它们之间挑选取决于您的设计偏好:

  • 您正确地注意到第一种方法已被破坏
  • 第二种方法适用于您创建的对象无法静态分配的情况,例如,因为您在运行时之前不知道您将需要多少对象
  • 第三种方法适用于初始化静态分配的对象,因为它不需要复制,并且可以避免手动资源管理。
  • 由于希望避免复制,最后一种方法不太常见。这几乎普遍等于过早优化,因此这种方法也非常有效。

答案 1 :(得分:3)

因为您问过Do I cast the result of malloc?否。

至于你关心的所有方法都有它们的优点和缺点,所以选择一个用于你的项目并继续致力于该决定(不要对一个函数使用一种方法,然后对树的另一个函数使用另一种方法)。

所有权可以是任何一种功能' (但调用者必须调用将取消分配树的那个)或调用者自己。

例如,在库中,我希望它们能够处理数据结构的内存分配,然后我只需调用库本身提供的函数来解除空间分配。这样我就不会进入他们的内部细节,这很好。

通常给予这些功能所有权,但这是主观的。