我有一个递归函数,我将数组作为局部变量传递。 (我知道如果你在一个函数中传递一个数组作为参数,只有指针,即数组的起始地址被传递。但我的目标是找到一种方法来克服所有这些限制,以便在一个纯粹的应用程序点工作视图。)
在每个递归级别,我正在改变数组的内容并使用此数组调用递归函数。我想要的是,当递归结束时,我希望每个级别的数组都像在递归中前进一样。目前我观察到的是,在返回递归时,所有调用中的数组内容保持不变。
这是我的代码
#include <stdio.h>
int len = 0;
int main(void)
{
int a[5] = {0};
len = sizeof(a)/sizeof(*a);
fun(a,0);
return 0;
}
int fun(int a[], int j)
{
if(j==5)
return;
a[j] = j;
fun(a,j+1);
}
这是我的gdb跟踪的输出。正如您所看到的,在前进过程中,数组内容看起来像
level 0 -{0}
level 1 -{0,1}
level 2 -{0,1,2}
level 3 -{0,1,2,3}
level 4 -{0,1,2,3,4}
但回来后,它总是
level 4 -{0,1,2,3,4}
level 3 -{0,1,2,3,4}
level 2 -{0,1,2,3,4}
level 1 -{0,1,2,3,4}
我希望我的数组在返回递归时看起来像这样
level 4 -{0,1,2,3,4}
level 3 -{0,1,2,3}
level 2 -{0,1,2}
level 1 -{0,1}
level 0 -{0}
gdb trace
(gdb) disp *a@5
1: *a@5 = {0, 0, 0, 0, 0}
(gdb) disp j
2: j = 0
(gdb) s
2: j = 0
1: *a@5 = {0, 0, 0, 0, 0}
2: j = 0
1: *a@5 = {0, 0, 0, 0, 0}
fun (a=0x7fffffffdf90, j=1) at main.c:18
2: j = 1
1: *a@5 = {0, 0, 0, 0, 0}
2: j = 1
1: *a@5 = {0, 0, 0, 0, 0}
(gdb) s
2: j = 1
1: *a@5 = {0, 0, 0, 0, 0}
2: j = 1
1: *a@5 = {0, 1, 0, 0, 0}
fun (a=0x7fffffffdf90, j=2) at main.c:18
2: j = 2
1: *a@5 = {0, 1, 0, 0, 0}
2: j = 2
1: *a@5 = {0, 1, 0, 0, 0}
2: j = 2
1: *a@5 = {0, 1, 0, 0, 0}
(gdb) s
2: j = 2
1: *a@5 = {0, 1, 2, 0, 0}
fun (a=0x7fffffffdf90, j=3) at main.c:18
2: j = 3
1: *a@5 = {0, 1, 2, 0, 0}
2: j = 3
1: *a@5 = {0, 1, 2, 0, 0}
2: j = 3
1: *a@5 = {0, 1, 2, 3, 0}
1: *a@5 = {0, 1, 2, 3, 0}
(gdb) s
fun (a=0x7fffffffdf90, j=4) at main.c:18
2: j = 4
1: *a@5 = {0, 1, 2, 3, 0}
2: j = 4
1: *a@5 = {0, 1, 2, 3, 0}
2: j = 4
1: *a@5 = {0, 1, 2, 3, 4}
fun (a=0x7fffffffdf90, j=5) at main.c:18
2: j = 5
1: *a@5 = {0, 1, 2, 3, 4}
1: *a@5 = {0, 1, 2, 3, 4}
(gdb) s
2: j = 5
1: *a@5 = {0, 1, 2, 3, 4}
2: j = 5
1: *a@5 = {0, 1, 2, 3, 4}
2: j = 4
1: *a@5 = {0, 1, 2, 3, 4}
2: j = 3
1: *a@5 = {0, 1, 2, 3, 4}
2: j = 2
1: *a@5 = {0, 1, 2, 3, 4}
(gdb) s
2: j = 1
1: *a@5 = {0, 1, 2, 3, 4}
2: j = 0
1: *a@5 = {0, 1, 2, 3, 4}
main () at main.c:13
编辑: 此外,这是其他语言的情况,例如java。我认为在java中指针的概念不存在,它将每个数组保存为单独的递归调用的局部变量。但我得到的输出与C相同。
代码
class Hello
{
public static void main(String[] args)
{
int[] a = {0,0,0,0,0};
fun(a,0);
System.out.println("");
}
static void fun(int[] a, int j)
{
int i = 0;
if(j==5)
{
for(i=0;i<5;i++)
System.out.print(a[i]);
System.out.println("");
return;
}
a[j] = j;
fun(a,j+1);
System.out.print("at j=="+j+" : ");
for(i=0;i<5;i++)
System.out.print(a[i]);
System.out.println("");
}
}
输出
01234
at j==4 : 01234
at j==3 : 01234
at j==2 : 01234
at j==1 : 01234
at j==0 : 01234
答案 0 :(得分:1)
在返回之前,只需恢复每次通话的内容:
void fun(int a[], int j) {
if (j == 5) {
return;
}
int tmp = a[j];
a[j] = j;
fun(a, j+1);
a[j] = tmp;
}
同样如评论中所述,您不应在未事先声明或定义的情况下使用函数。您可以在main()
之前使用原型声明它:
void fun(int a[], int j);
或者只是在main()
之前完全定义它并且您不会需要原型。
注意:该函数不会返回任何内容,因此正确的返回类型为void
,而不是int
。
答案 1 :(得分:0)
我想要的是,当递归结束时,我希望数组在 每个级别都像在递归中前进一样。
可以通过struct包装数组来将其视为值类型。
E.g
#include <stdio.h>
int len = 0;
typedef struct {
int a[5];
} varType;
void fun(varType v, int i);
int main(void){
varType v = {0};
len = sizeof(v.a)/sizeof(*v.a);
fun(v,0);
return 0;
}
void fun(varType x, int j){
#if DEBUG
for(int i=0; i < len; ++i)
printf("%d ", x.a[i]);
printf("\n");
#endif
if(j==5)
return;
x.a[j] = j;
fun(x, j+1);
#if DEBUG
for(int i=0; i < len; ++i)
printf("%d ", x.a[i]);
printf("\n");
#endif
}
答案 2 :(得分:0)
//something of the form to null out the last element prior to falling out of each recursion
int fun(int a[], int j)
{
static int i = 0;
if(j<5){
a[j] = j;
i++;//inc on each recursion
fun(a,j+1);
}
i--;//decrement on falling out of each recursion
a[i] = 0;//null out the last index
return 0;
}
答案 3 :(得分:0)
正如其他人所暗示的那样,在大多数情况下,重用相同的数组更为方便和有效(就像你在传递引用时已经做的那样),而是让堆栈的每个级别“撤消”无论它在返回之前对数组做了什么。这将导致您需要的输出(当每个级别的递归调用完成时,每个级别都将数组视为未更改。)
但是,由于您明确询问如何在每个级别创建一个新数组,以下是您在Java中如何做到这一点:
只需将递归调用更改为fun(a, j + 1);
至fun(Arrays.copyOf(a, a.length), j + 1);
。
如果您的问题只是如何复制数组(或任何对象),那么此处的递归实际上并不相关。我在我的C库上生锈了,但是必须有一种简单的方法来复制数组,或者你可以在几行中编写自己的复制方法,只需分配一个与源副本大小相同的新数组,然后逐个复制元素。