[英]When to pass a pointer to a structure as an argument, and when to pass a pointer to a pointer to a structure?
My question is in regards to the following code. 我的问题是关于以下代码。
#include <stdio.h>
#include <stdlib.h>
struct node
{
int v;
struct node * left;
struct node * right;
};
typedef struct node Node;
struct bst
{
Node * root;
};
typedef struct bst BST;
BST * bst_insert(BST * tree, int newValue);
Node * bst_insert_node(Node * node, int newValue);
void bst_traverseInOrder(BST * tree);
void bst_traverseInOrderNode(Node * node);
int main(void)
{
BST * t;
bst_insert(t, 5);
bst_insert(t, 8);
bst_insert(t, 6);
bst_insert(t, 3);
bst_insert(t, 12);
bst_traverseInOrder(t);
return 0;
}
BST * bst_insert(BST * tree, int newValue)
{
if (tree == NULL)
{
tree = (BST *) malloc(sizeof(BST));
tree->root = (Node *) malloc(sizeof(Node));
tree->root->v = newValue;
tree->root->left = NULL;
tree->root->right = NULL;
return tree;
}
tree->root = bst_insert_node(tree->root, newValue);
return tree;
}
Node * bst_insert_node(Node * node, int newValue)
{
if (node == NULL)
{
Node * new = (Node *) malloc(sizeof(Node));
new->v = newValue;
new->left = NULL;
new->right = NULL;
return new;
}
else if (newValue < node->v)
node->left = bst_insert_node(node->left, newValue);
else
node->right = bst_insert_node(node->right, newValue);
return node;
}
void bst_traverseInOrder(BST * tree)
{
if (tree == NULL)
return;
else
{
bst_traverseInOrderNode(tree->root);
printf("\n");
}
}
void bst_traverseInOrderNode(Node * node)
{
if (node == NULL)
return;
else
{
bst_traverseInOrderNode(node->left);
printf("%d ", node->v);
bst_traverseInOrderNode(node->right);
}
}
So, the code works perfectly as is. 因此,代码按原样完美运行。 It will insert each value into BST correctly, and the traversal function will traverse the tree inorder correctly.
它将正确地将每个值插入BST,并且遍历函数将正确地遍历树。 However, when I am initially declaring t to be a BST (eg line 27), if I also assign t to be NULL (eg BST * t = NULL), then the insertion does not work anymore.
但是,当我最初声明t为BST时(例如,第27行),如果我也将t分配为NULL(例如BST * t = NULL),则插入不再起作用。 But, if I then reassign t for the first insertion (eg t = bst_insert(t, 5)), then everything works again.
但是,如果我随后为第一次插入重新分配了t(例如t = bst_insert(t,5)),那么一切都会再次起作用。 Is there a particular reason for this?
是否有特定原因?
Secondly, how do I know when I need to pass a pointer to a pointer to a structure? 其次,如何知道何时需要将指针传递给结构的指针? If I want to change the value that
int i
points to, then I need to pass &i
to a function, correct? 如果我想更改
int i
指向的值,那么我需要将&i
传递给函数,对吗? But if I want to change the values within struct node n
, then why do I need to pass a **node
to a function, and not just a *node
? 但是,如果要更改
struct node n
的值,那么为什么需要将**node
传递给函数,而不仅是*node
?
Thank you so much for taking a look. 非常感谢您的关注。
In C, everything is passed by value, there is no exception to this. 在C语言中, 一切都是通过值传递的,对此也不例外。
You can emulate pass-by-reference by passing the pointer and dereferencing it in the function but this is a poor cousin to real pass-by-reference. 您可以通过传递指针并在函数中取消对指针的引用来模拟传递引用,但这与真实的传递引用不太理想。
The bottom line is, if you want to change anything passed to a function, you have to provide its pointer for dereferencing and, for changing pointers themselves, that means passing the pointer of the pointer. 最重要的是,如果您想更改传递给函数的任何内容 ,则必须提供其指针以供取消引用,而要更改指针本身,则意味着要传递指针的指针。 Note that:
注意:
t = modifyAndReturn (t);
is not really the same thing - the function itself does not modify t
, it simply returns something which the caller then assigns to t
. 并不是完全一样-函数本身不会修改
t
,它只返回调用者然后分配给t
。
So, you've done it the latter way, where you can do something like this: 因此,您采用了后一种方法,可以执行以下操作:
int add42 (int n) { return n + 42; }
:
x = add42 (x);
Using the emulated pass-by-reference, that would be (with pointers and dereferencing): 使用模拟的传递引用,将是(带有指针和取消引用):
void add42 (int *n) { *n += 42; }
:
add42 (&x);
For changing pointers, as mentioned earlier, you need to pass the pointer to the pointer. 如前所述,要更改指针,您需要将指针传递给指针。 Let's say you want to change a char pointer so that it points to the next character.
假设您要更改一个char指针,使其指向下一个字符。 You would do something like:
您将执行以下操作:
#include <stdio.h>
void pointToNextChar (char **pChPtr) {
*pChPtr += 1; // advance the pointer being pointed to.
}
int main (void) {
char plugh[] = "hello";
char *xyzzy = plugh;
pointToNextChar (&xyzzy);
puts (xyzzy); // outputs "ello".
}
C++ actually provides proper pass-by-reference with the &
"modifier" such as: C ++实际上使用
&
“修饰符”提供正确的按引用传递,例如:
void add42 (int &n) { n += 42; }
and you don't have to then worry about derefencing within the function, any changes are immediately echoed back to the original passed parameter. 而且您不必担心在函数中进行反引用,任何更改都会立即回显到原始传递的参数中。 I rather hope that C21 will have this feature, it will save a lot of trouble for people unfamiliar with the pointer gymnastics we have to endure in C :-)
我希望C21具有此功能,它将为不熟悉我们必须在C中忍受的指针体操的人们节省很多麻烦:-)
By the way, you have a rather serious problem with that code. 顺便说一句,您对该代码有一个相当严重的问题。 Within
main
, the line: 在
main
,该行:
BST * t;
will set t
to an arbitrary value which is unlikely to be what you want. 将
t
设置为不太可能是您想要的任意值。 You should set it initially to NULL so that bst_insert
correctly initialises it. 您应该首先将其设置为NULL,以便
bst_insert
正确初始化它。
Actually your code is incorrect as it is, because you are not allocating memory for t
in your main. 实际上,您的代码实际上是不正确的,因为您没有在main中为
t
分配内存。 You will get undefined behavior when you try to access the value pointed in bst_insert_node
. 当您尝试访问
bst_insert_node
指向的值时,您将获得未定义的行为。 The correct way to do it would be to set it to NULL
and then 正确的方法是将其设置为
NULL
,然后
t = bst_insert(t, 5);
BST *t; // It declares a pointer of type BST
BST *t = NULL; // Declares pointer same way and pointer points to mem location "0"
Now, 现在,
bst_insert(t, 5); // Now "tree" pointer inside "bst_insert" definition points to location pointed by "t" ie NULL (in 2nd case above)
tree = malloc(<some memory>); // Allocates some memory and stores its base address inside "tree"
Now see, above statement changes the location pointed by tree
in bst_insert()
, but not by t
in main()
. 现在来看,上面的语句更改了
bst_insert()
tree
指向的位置,而main()
t
指向的位置未更改。
So when you write t = bst_insert(t, 5)
you return the value pointed by tree explicitly to store in tree, So code works fine. 因此,当您编写
t = bst_insert(t, 5)
,将显式地返回树所指向的值以存储在树中,因此代码可以正常工作。
If you do not use the return value, t
is still NULL
. 如果不使用返回值,则
t
仍为NULL
。
Either use this way, or you can do like this: 可以使用这种方式,也可以这样:
bst_insert(BST **tree, int new_val);
And in main()
在
main()
bst_insert(&t, 5);
What happens now!! 现在会发生什么!
Now you will use *tree = malloc(<some mem>);
现在,您将使用
*tree = malloc(<some mem>);
So you directly assign base address of memory allocated to: *tree
which is actually t
itself. 因此,您可以直接分配分配给以下对象的内存的基地址:
*tree
,它实际上是t
本身。 Now you need not return the mem address. 现在,您无需返回内存地址。
This is same as code below, written inside one function: 这与下面的代码相同,写在一个函数中:
BST **tree;
BST *t;
tree = &t;
*tree = malloc(<some mem>); // You are allocating memory and storing address
// actually at "t"
Hope you understand what I want to explain. 希望您理解我要解释的内容。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.