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

dyx*_*yxh 1 c tree pointers arguments

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

#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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

非常感谢你看一看.

pax*_*blo 5

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

您可以通过传递指针并在函数中取消引用它来模拟传递引用,但这是一个真正的传递引用的表兄弟.

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

t = modifyAndReturn (t);
Run Code Online (Sandbox Code Playgroud)

实际上并不是同一个东西 - 函数本身不会修改t,它只返回调用者随后分配的内容t.

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

int add42 (int n) { return n + 42; }
:
x = add42 (x);
Run Code Online (Sandbox Code Playgroud)

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

void add42 (int *n) { *n += 42; }
:
add42 (&x);
Run Code Online (Sandbox Code Playgroud)

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

#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".
}
Run Code Online (Sandbox Code Playgroud)

C++实际上使用"修饰符" 提供了正确的 pass-by-reference,&例如:

void add42 (int &n) { n += 42; }
Run Code Online (Sandbox Code Playgroud)

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


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

BST * t;
Run Code Online (Sandbox Code Playgroud)

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