C++ 函数声明或原型。我如何定义它?

C++ 函数声明或原型。我如何定义它?,c++,c,function,linked-list,C++,C,Function,Linked List,我最近一直在研究链表和树。但我不确定何时将函数声明为: preorder(struct node* root); or preorder(struct node** root); 当两者的工作原理完全相同时。更准确地说,什么时候我必须将函数设计为双指针和单指针 谢谢 注意:在链表中插入节点需要有双指针,如: insert(struct node** root,int value); 除非根节点定义为全局值。而预排序可以很好地使用单个指针。如果有人能用这个例子来解释,那将非常有帮助。这取决于

我最近一直在研究链表和树。但我不确定何时将函数声明为:

preorder(struct node* root); 
or
preorder(struct node** root);
当两者的工作原理完全相同时。更准确地说,什么时候我必须将函数设计为双指针和单指针

谢谢

注意:在链表中插入节点需要有双指针,如:

insert(struct node** root,int value);

除非根节点定义为全局值。而预排序可以很好地使用单个指针。如果有人能用这个例子来解释,那将非常有帮助。

这取决于
preorder()
的功能。如果它在不修改列表/树的情况下打印一些内容,那么您只需要一个指针。如果有可能必须替换根目录,则需要一个双指针

这是因为参数是通过C中的值传递的。如果将原始变量的副本传递给函数,则无法修改原始变量:

int inc(int x)
{
    x = x + 1; // this will never work
}
为了避免这个问题,您可以传递参数的地址(指向它的指针),而不是传递参数。然后,该函数可以取消对指针的引用,并修改指针指向的值

// usage: inc(&x) where x is an int
int inc(int *ptr)
{
    *ptr = *ptr + 1; // this will work
}

对于列表/树,您已经在使用指针。这允许您访问和修改指向的对象(例如,获取/设置根的
下一个
成员),但不允许您修改指针本身(例如,用其他节点替换根)。为此,需要引入另一个级别,即指向节点的指针。

这取决于
preorder()的功能。如果它在不修改列表/树的情况下打印一些内容,那么您只需要一个指针。如果有可能必须替换根目录,则需要一个双指针

这是因为参数是通过C中的值传递的。如果将原始变量的副本传递给函数,则无法修改原始变量:

int inc(int x)
{
    x = x + 1; // this will never work
}
为了避免这个问题,您可以传递参数的地址(指向它的指针),而不是传递参数。然后,该函数可以取消对指针的引用,并修改指针指向的值

// usage: inc(&x) where x is an int
int inc(int *ptr)
{
    *ptr = *ptr + 1; // this will work
}
对于列表/树,您已经在使用指针。这允许您访问和修改指向的对象(例如,获取/设置根的
下一个
成员),但不允许您修改指针本身(例如,用其他节点替换根)。为此,需要引入另一个级别,即指向节点的指针。

preorder(struct node**root)

这里您传递的是
根目录的地址
,因为您可能希望使用该函数对其进行更新

preorder(结构节点*root)

在这里,您只需使用
root
横切数据结构,而无需修改
root

前序(结构节点**root)

这里您传递的是
根目录的地址
,因为您可能希望使用该函数对其进行更新

preorder(结构节点*root)


在这里,您只需使用
root
横切数据结构,而无需修改
root

,这有点让人困惑,但我会尝试一下,也许我的解释方式会对某人有意义:)

函数作用域中的每个变量都是以标准方式定义的,本质上是。。(变量类型)(变量名称)。是否:

int foo; // an int called foo

当您将它们作为参数传递给另一个函数时,处理
foo
bar
blah
的方式是相同的。如果希望被调用函数只查看或使用变量,可以按原样(按值)传递它们,从而创建值的副本(int、字符地址或结构xyz的地址)。因此,如果在调用的函数中更改int的值或
struct xyz
的地址,则只会更改原始变量的本地副本

如果您希望被调用函数实际更改原始变量的值(例如,increment foo、malloc memory for bar或更改blah指向列表中的哪个元素),则需要告诉被调用函数在何处进行更改(通过引用传递),这将导致被调用函数声明为
f(int*foo)
f(字符**条)
f(结构xyz**blah)


人们会陷入间接层次,但当你调用另一个函数时,真正重要的是你打算如何使用或改变局部范围内的变量,但我会试一试,也许我的解释方式会对某人有意义:)

函数作用域中的每个变量都是以标准方式定义的,本质上是。。(变量类型)(变量名称)。是否:

int foo; // an int called foo

当您将它们作为参数传递给另一个函数时,处理
foo
bar
blah
的方式是相同的。如果希望被调用函数只查看或使用变量,可以按原样(按值)传递它们,从而创建值的副本(int、字符地址或结构xyz的地址)。因此,如果在调用的函数中更改int的值或
struct xyz
的地址,则只会更改原始变量的本地副本

如果您希望被调用函数实际更改原始变量的值(例如,increment foo、malloc memory for bar或更改blah指向列表中的哪个元素),则需要告诉被调用函数在何处进行更改(通过引用传递),这将导致被调用函数声明为
f(int*foo)
f(字符**条)
f(结构xyz**blah)

人们会被间接层次所吸引,但这一切都很重要
void clearNode(struct node **n){
    (*n)->field = 0; // modify caller's struct
    *n = NULL; // set caller's pointer to NULL
}
...
struct node n; // value
struct node *np = &n; // pointer to node
clearNode(np); // will not compile, np is not right type
clearNode(&np); // OK, np becomes NULL, n.field becomes 0
clearNode(&n); // will not compile, &n is not of right type
void clearNode(struct node *n){
    n->field = 0; // modify caller's struct
    n = NULL; // change local parameter, which in this case has no effect anywhere
}
...
struct node n; // value
struct node *np = &n; // pointer to node
clearNode(np); // OK, except np is not modified, n.field becomes NULL
clearNode(&np); // will not compile, &np is not of right type
clearNode(&n); // OK, n.field becomes NULL
void clearNode(struct node &n){
    n.field = 0; // modify caller's struct
    // no pointer, nothing to set to NULL
}
...
struct node n; // value
struct node *np = &n; // pointer to node
clearNode(np); // will not compile, np is not of right type
clearNode(&np); // will not compile, &np is not of right type
clearNode(&n); // will not compile, &n is not of right type
// these work, n.field becomes 0:
clearnode(n);
clearnode(*np);