何时将指针作为参数传递给结构,何时将指针传递给指向结构的指针?

我的问题是关于以下代码。

#include  #include  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 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); } } 

因此,代码完美无缺。 它会正确地将每个值插入到BST中,并且遍历函数将正确地遍历树。 但是,当我最初声明t为BST(例如第27行)时,如果我还将t指定为NULL(例如BST * t = NULL),则插入不再起作用。 但是,如果我然后为第一次插入重新分配t(例如t = bst_insert(t,5)),那么一切都会再次起作用。 这有什么特别的原因吗?

其次,我怎么知道何时需要将指针传递给指向结构的指针? 如果我想更改int i指向的值,那么我需要将&i传递给函数,对吗? 但是如果我想更改struct node n的值,那么为什么我需要将**node传递给一个函数,而不仅仅是一个*node

非常感谢你看一看。

在C中, 一切都是按值传递的,对此没有例外。

您可以通过传递指针并在函数中取消引用它来模拟传递引用,但这对于真正的传递引用来说是一个糟糕的表亲。

底线是,如果你想改变传递给函数的任何东西 ,你必须提供它的指针用于解除引用,并且,为了更改指针本身,这意味着传递指针的指针。 注意:

 t = modifyAndReturn (t); 

实际上并不是同一个东西 – 函数本身不会修改t ,它只返回调用者然后分配给t

所以,你已经用后一种方式完成了,你可以做到这样的事情:

 int add42 (int n) { return n + 42; } : x = add42 (x); 

使用模拟的pass-by-reference,即(使用指针和解除引用):

 void add42 (int *n) { *n += 42; } : add42 (&x); 

对于更改指针,如前所述,您需要将指针传递给指针。 假设您想要更改一个字符指针,使其指向下一个字符。 你会做的事情如下:

 #include  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 ++实际上使用& “修饰符”提供了正确的 pass-by-reference,例如:

 void add42 (int &n) { n += 42; } 

并且您不必担心函数内的derefencing,任何更改都会立即回显到原始传递的参数。 我更希望C21能有这个function,对于不熟悉我们必须忍受的指针体操的人来说,它会省去很多麻烦:-)


顺便说一句,你有一个相当严重的代码问题。 在main内部,该行:

 BST * t; 

t设置为一个不太可能是你想要的任意值。 您应该将它最初设置为NULL,以便bst_insert正确初始化它。

实际上你的代码是不正确的,因为你没有为你的主要内容分配内存。 当您尝试访问bst_insert_node指向的值时,将获得未定义的行为。 正确的方法是将其设置为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"

现在,

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(); // Allocates some memory and stores its base address inside "tree"

现在看,上面的语句更改了bst_insert() tree指向的位置,而不是main() t

因此,当您编写t = bst_insert(t, 5)您将显式返回树指向的值以存储在树中,因此代码工作正常。

如果不使用返回值,则t仍为NULL

要么这样使用,要么就是这样:

bst_insert(BST **tree, int new_val);

并在main()

bst_insert(&t, 5);

现在发生了什么!!

现在你将使用*tree = malloc();

所以你直接将分配的内存的基地址分配给: *tree ,它实际上是t本身。 现在您无需返回mem地址。

这与下面的代码相同,写在一个函数中:

 BST **tree; BST *t; tree = &t; *tree = malloc(); // You are allocating memory and storing address // actually at "t" 

希望你明白我想要解释的内容。