递归函数和通过引用C / C ++调用函数之间有什么区别?


回答 1:

这两个函数都是递归的。主要区别在于第二个函数的参数是对值的引用,而不是直接传递的值,这意味着每次调用该函数时都不会复制直接值。 (这种属性对于int值不太有用,而对结构或类则更有用,以避免每次函数重复时都必须复制整个数据块。)

唯一的不同是第二个函数不返回任何值,而第一个函数则返回任何值。


回答 2:

这些都是递归函数调用。一个返回递归调用的结果,一个不返回。使用递归时,两者均有效(且有用)。

显然,这两个示例都包含一个错误,因为您永远不会终止递归(最终将导致堆栈溢出),但是我认为您只是在用虚构的代码来构想问题。


回答 3:

我通过告诉您与其他答案相同的事情来击败一匹死马,但是void方法将在反复执行相同任务的过程中,就像将返回方法用于累积每个递归调用的结果一样。

现在,如果您不知道这些不是好的递归函数,因为没有基本情况,您将遇到堆栈溢出(或缓冲区溢出,具体取决于您与谁谈话),这在使用C时会存在很多内存问题,因此你要小心点您需要在递归函数中有一个基本案例来指示底部。


回答 4:

除了具有返回值的值以外,大多数情况下都是偏好/易读性。

尽管我认为这在命令式编程中主要是一种不良做法。对于递归至关重要的事情,您最有可能与更复杂的数学算法的实现有关,因此函数式编程更适用于分析属性和运行时。当转向实际使用时,命令式编程语言中有比递归更好的概念。


回答 5:

就像所有其他人所说的那样,您的两个函数都是递归的。

而且您没有通过引用调用任何东西,但是您拥有一个变量,在第一种情况下仅给出了该变量(未使用),而在第二种情况下给出了对该变量的引用(指针)。

顺便说一句,您的(int&x)在C语言中不起作用。那是只有C ++才能做到的事情,这也意味着您无法从调用者那里看到被调用者可以更改此变量。

int x = 42;
func(x);
funcref(&x);

int func(int i){
i = 1;
返回i + 2; //将返回3,x保持不变(我只是本地的)
}
int funcref(int * i){
* i = 1;
返回* i + 2; //将返回3,x设置为1
}

这是按值调用和按引用调用的示例。第一次通话无法直接更改X。 funcref正在更改调用者的X值,因为它不仅获取该变量的值,而且获取该变量本身的地址。

现在通过引用来调用函数:

#include 
int func1(int x){
返回x + 1;
}
int func2(int x){
返回x + 2;
}

int main(){
int(* call)(int x);

call =&func1;
printf(“%d \ n”,call(41));

call =&func2;
printf(“%d \ n”,call(41));
}

编译输出:

> cc -O3 -o fcall fcall.c
> ./fcall
42
43

通过引用调用函数具有强大的功能。在汇编级,这样的调用只是一个操作码的调用,因此,通常不需要更多的时间来跳过寄存器中的地址,而不必直接跳转到必须从内存中获取的地址。它甚至可以比这更快,因为这种跳转不需要任何内存访问。

实际上,我们通常跳过跳转表。就像这里的例子一样:

#include 
int fadd(int a,int b){返回a + b; }
int fsub(int a,int b){返回a-b; }
int fmul(int a,int b){返回a * b; }
int fdiv(int a,int b){返回a / b; }

int main(){
//初始化跳转表“ call”
int(* call [])(int x,int y)= {&fadd,&fsub,&fmul,&fdiv};

for(int i = 0; i 

编译输出:

> cc -O3 -o fcall fcall.c
> ./fcall
15
9
36
4

如您所见,数组中的这类函数作为工具非常强大。这样您就可以解决很多问题。实际上,这可以像开关/外壳结构那样使用,只是比它更复杂并且更紧凑。紧凑是很好的,它将代码保存在缓存中。因此,例如,如果您有任何类型的问题解决问题,这可能是解决问题的最有效方法之一。

在我的示例中,现在只需要很少的钱就可以对此做一个小的计算器了。您可以使用类似的东西进行仿真,甚至用于状态机,而本机状态机使用某种跳转机制,是的,我在这里谈论的是GOTO。但这是另一个问题。

但是,如果您具有带有递归回调结构的状态机(可能在许多AI问题中都存在这种状态机),则可以使用工具来解决此问题。

另外,如果您要在C语言中进行纯函数编程,这也是解决方案:您确实要使用函数表。

函数式编程不是单一语言的领域。诸如Scheme或Lisp之类的东西可能会大大支持它,但是函数调用一个变量(一个未命名的变量)时,就是那些人们喜欢谈论的Lambda。只需将Lisp的效率与此进行比较即可。

用非常HLL编写这样的东西可能会更方便,但是这样做的代价太高了,以至于在原型制作之外通常都没有必要避免这种麻烦。我已经向您展示了解决方法的麻烦。


回答 6:

就像所有其他人所说的那样,您的两个函数都是递归的。

而且您没有通过引用调用任何东西,但是您拥有一个变量,在第一种情况下仅给出了该变量(未使用),而在第二种情况下给出了对该变量的引用(指针)。

顺便说一句,您的(int&x)在C语言中不起作用。那是只有C ++才能做到的事情,这也意味着您无法从调用者那里看到被调用者可以更改此变量。

int x = 42;
func(x);
funcref(&x);

int func(int i){
i = 1;
返回i + 2; //将返回3,x保持不变(我只是本地的)
}
int funcref(int * i){
* i = 1;
返回* i + 2; //将返回3,x设置为1
}

这是按值调用和按引用调用的示例。第一次通话无法直接更改X。 funcref正在更改调用者的X值,因为它不仅获取该变量的值,而且获取该变量本身的地址。

现在通过引用来调用函数:

#include 
int func1(int x){
返回x + 1;
}
int func2(int x){
返回x + 2;
}

int main(){
int(* call)(int x);

call =&func1;
printf(“%d \ n”,call(41));

call =&func2;
printf(“%d \ n”,call(41));
}

编译输出:

> cc -O3 -o fcall fcall.c
> ./fcall
42
43

通过引用调用函数具有强大的功能。在汇编级,这样的调用只是一个操作码的调用,因此,通常不需要更多的时间来跳过寄存器中的地址,而不必直接跳转到必须从内存中获取的地址。它甚至可以比这更快,因为这种跳转不需要任何内存访问。

实际上,我们通常跳过跳转表。就像这里的例子一样:

#include 
int fadd(int a,int b){返回a + b; }
int fsub(int a,int b){返回a-b; }
int fmul(int a,int b){返回a * b; }
int fdiv(int a,int b){返回a / b; }

int main(){
//初始化跳转表“ call”
int(* call [])(int x,int y)= {&fadd,&fsub,&fmul,&fdiv};

for(int i = 0; i 

编译输出:

> cc -O3 -o fcall fcall.c
> ./fcall
15
9
36
4

如您所见,数组中的这类函数作为工具非常强大。这样您就可以解决很多问题。实际上,这可以像开关/外壳结构那样使用,只是比它更复杂并且更紧凑。紧凑是很好的,它将代码保存在缓存中。因此,例如,如果您有任何类型的问题解决问题,这可能是解决问题的最有效方法之一。

在我的示例中,现在只需要很少的钱就可以对此做一个小的计算器了。您可以使用类似的东西进行仿真,甚至用于状态机,而本机状态机使用某种跳转机制,是的,我在这里谈论的是GOTO。但这是另一个问题。

但是,如果您具有带有递归回调结构的状态机(可能在许多AI问题中都存在这种状态机),则可以使用工具来解决此问题。

另外,如果您要在C语言中进行纯函数编程,这也是解决方案:您确实要使用函数表。

函数式编程不是单一语言的领域。诸如Scheme或Lisp之类的东西可能会大大支持它,但是函数调用一个变量(一个未命名的变量)时,就是那些人们喜欢谈论的Lambda。只需将Lisp的效率与此进行比较即可。

用非常HLL编写这样的东西可能会更方便,但是这样做的代价太高了,以至于在原型制作之外通常都没有必要避免这种麻烦。我已经向您展示了解决方法的麻烦。


回答 7:

就像所有其他人所说的那样,您的两个函数都是递归的。

而且您没有通过引用调用任何东西,但是您拥有一个变量,在第一种情况下仅给出了该变量(未使用),而在第二种情况下给出了对该变量的引用(指针)。

顺便说一句,您的(int&x)在C语言中不起作用。那是只有C ++才能做到的事情,这也意味着您无法从调用者那里看到被调用者可以更改此变量。

int x = 42;
func(x);
funcref(&x);

int func(int i){
i = 1;
返回i + 2; //将返回3,x保持不变(我只是本地的)
}
int funcref(int * i){
* i = 1;
返回* i + 2; //将返回3,x设置为1
}

这是按值调用和按引用调用的示例。第一次通话无法直接更改X。 funcref正在更改调用者的X值,因为它不仅获取该变量的值,而且获取该变量本身的地址。

现在通过引用来调用函数:

#include 
int func1(int x){
返回x + 1;
}
int func2(int x){
返回x + 2;
}

int main(){
int(* call)(int x);

call =&func1;
printf(“%d \ n”,call(41));

call =&func2;
printf(“%d \ n”,call(41));
}

编译输出:

> cc -O3 -o fcall fcall.c
> ./fcall
42
43

通过引用调用函数具有强大的功能。在汇编级,这样的调用只是一个操作码的调用,因此,通常不需要更多的时间来跳过寄存器中的地址,而不必直接跳转到必须从内存中获取的地址。它甚至可以比这更快,因为这种跳转不需要任何内存访问。

实际上,我们通常跳过跳转表。就像这里的例子一样:

#include 
int fadd(int a,int b){返回a + b; }
int fsub(int a,int b){返回a-b; }
int fmul(int a,int b){返回a * b; }
int fdiv(int a,int b){返回a / b; }

int main(){
//初始化跳转表“ call”
int(* call [])(int x,int y)= {&fadd,&fsub,&fmul,&fdiv};

for(int i = 0; i 

编译输出:

> cc -O3 -o fcall fcall.c
> ./fcall
15
9
36
4

如您所见,数组中的这类函数作为工具非常强大。这样您就可以解决很多问题。实际上,这可以像开关/外壳结构那样使用,只是比它更复杂并且更紧凑。紧凑是很好的,它将代码保存在缓存中。因此,例如,如果您有任何类型的问题解决问题,这可能是解决问题的最有效方法之一。

在我的示例中,现在只需要很少的钱就可以对此做一个小的计算器了。您可以使用类似的东西进行仿真,甚至用于状态机,而本机状态机使用某种跳转机制,是的,我在这里谈论的是GOTO。但这是另一个问题。

但是,如果您具有带有递归回调结构的状态机(可能在许多AI问题中都存在这种状态机),则可以使用工具来解决此问题。

另外,如果您要在C语言中进行纯函数编程,这也是解决方案:您确实要使用函数表。

函数式编程不是单一语言的领域。诸如Scheme或Lisp之类的东西可能会大大支持它,但是函数调用一个变量(一个未命名的变量)时,就是那些人们喜欢谈论的Lambda。只需将Lisp的效率与此进行比较即可。

用非常HLL编写这样的东西可能会更方便,但是这样做的代价太高了,以至于在原型制作之外通常都没有必要避免这种麻烦。我已经向您展示了解决方法的麻烦。