0

私の質問は次のコードに関するものです (ここでコードの別の領域について関連する質問をしたことに注意してください):

#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 = NULL;

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

特に、bst_insert は参照ではなく値だけを取るため (たとえば、実際に自分自身を変更することはできません)、自分自身を実際に変更するには、に再割り当てtする必要があるようです。ただし、後で BST が作成されたときに、参照によって引数として受け取っていなくても、宣言するだけで、これ自体が変更されます (例: change )。誰かがここでの違いを説明してもらえますか? 本当にありがとう!bst-insert(t, 5)maintBST *BST *bst_insert(t, 8)tt->root->leftt

4

2 に答える 2

3

「... bst_insert は BST * を参照ではなく、値のみで取得するため..」間違った用語を使用しています。これは、下にある概念の不明確な理解が原因である可能性があります。

C には参照渡しがありません。関数のすべての引数は渡しです。値渡しとは、関数呼び出しが行われたときに引数がコピーされ、関数の対応するパラメーターがそのコピーを取得することを意味します。したがって、関数内では、引数のコピーを操作します。

対照的に、一部の言語 (特に C++ であり、C ではない) は、参照によって引数を渡す場合があります。これは、関数内の対応するパラメータが引数のエイリアスになることを意味します。つまり、同じオブジェクトの代替名として使用できます。この場合、関数内でエイリアスを使用してオブジェクトに加えた変更は、関数の「外部」の引数に影響します。

C では、ポインターを関数パラメーターとして使用することで、参照渡しの動作にいくらか近づけることができます。ポインター値(つまり、オブジェクト アドレス)を渡す場合、関数内でそれを使用して、ポインターが指しているオブジェクトを間接的に変更できます。

誰かがこの「トリック」をポインタ渡し(またはポインタ渡し)と呼んでいますが、IMO この用語は、実際の基礎となるメカニズムを知らない初心者にとって誤解を招く可能性があります。実際、これはまったく新しいメカニズムではなく、ポインタ値に適用される値渡しにすぎません! 実際、 (指しているオブジェクトではなく)ポインター自体に加えた変更はローカルになります。つまり、呼び出しで渡す実際のポインターには影響しません。

于 2013-08-30T06:38:18.427 に答える
2

違いは、最初の呼び出し ( tisの場合NULL) で、関数bst_insertがポインター自体を変更していることです ( withtに新しい値を割り当てています)。次の呼び出しでは、それ自体は変更されず、それが指すコンテンツのみが変更されます。たとえば、変更とは、 が指すコンテンツを変更することを意味しますが、それ自体 (それが指すアドレス)は変更しません。tmalloctt->roottt

于 2013-08-30T05:10:50.627 に答える