这有点是一个主观问题,但似乎应该有一个标准。我正在制作树状数据结构,我想知道从函数传递新节点的最佳方法。我有几个想法,但我不知道哪个是最安全/最有效的。
这是我的代码的简化:
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 ++编写的,并且处理引用和指针,我担心我不能真正理解它们之间的区别。
执行此操作的标准方法是什么?
(对不起,如果这太长了)
答案 0 :(得分:5)
您已涵盖所有四种可用方法,包括一种无法使用的方法。在它们之间挑选取决于您的设计偏好:
答案 1 :(得分:3)
因为您问过Do I cast the result of malloc?否。
至于你关心的所有方法都有它们的优点和缺点,所以选择一个用于你的项目并继续致力于该决定(不要对一个函数使用一种方法,然后对树的另一个函数使用另一种方法)。
所有权可以是任何一种功能' (但调用者必须调用将取消分配树的那个)或调用者自己。
例如,在库中,我希望它们能够处理数据结构的内存分配,然后我只需调用库本身提供的函数来解除空间分配。这样我就不会进入他们的内部细节,这很好。
通常我给予这些功能所有权,但这是主观的。