C 关于递归函数的问题?

C 关于递归函数的问题?,c,recursion,C,Recursion,我有一个C语言书中的递归函数,如下所示: void print(int a[], int n) { if (n<=0) return ; printf("%d\n", a[0]); print(&a[1], n-1); } void打印(int a[],int n) {如果(n&a[1]是数组第二个元素的地址,它实际上是第一个元素之后的数组部分的地址。因此,在打印参数数组的第一个元素之后 print(&a[1], n-1); 将自身传递给数组的

我有一个C语言书中的递归函数,如下所示:

void print(int a[], int n)
{   if (n<=0)  return ;
     printf("%d\n", a[0]);
     print(&a[1], n-1);
}
void打印(int a[],int n)

{如果(n
&a[1]
是数组第二个元素的地址,它实际上是第一个元素之后的数组部分的地址。因此,在打印参数数组的第一个元素之后

print(&a[1], n-1);
将自身传递给数组的其余部分,同时将长度减少1

例如,如果使用数组
{1,2,3,4,5}
n==5
调用
print
,则事件和调用链如下所示:

  • 打印第一个元素(1)
  • 用数组的剩余部分调用自己,即
    {2,3,4,5}
    n==4
  • 打印第一个元素(2)
  • 用数组的剩余部分调用自身,即
    {3,4,5}
    n==3
  • 打印第一个元素(3)
  • 用数组的剩余部分调用自身,即
    {4,5}
    n==2
  • 打印第一个元素(4)
  • 使用数组的剩余部分调用自身,即
    {5}
    n==1
  • 打印第一个元素(5)
  • 用数组的剩余部分调用自身,即
    {}
    n==0
  • n返回
  • 返回
  • 返回
  • 返回
  • 返回
  • 返回
  • 如果
    n
    为零(或更小),它什么也不做,因此递归停止。如果
    n
    >0,则它打印
    a[0]
    ,并递归调用
    n
    n-1
    (因此随着递归的进行,它会变为0)和
    &a[1]
    用于
    a
    ,即在每次递归调用中递增指针
    a
    。请记住,C中的数组参数是指针参数的语法糖

    因此,您发布的代码相当于:

    void print(int *a, int n)
    {
        if (n > 0) {
            printf("%d\n", *a);
            print(a+1, n-1);
        }
    }
    

    如果您可以验证以下算法是否可以打印数组,那么您应该能够理解为什么C代码可以工作,因为它是直接翻译的

    要打印数组的n个元素,请执行以下操作:

    • 如果要求您不打印任何元素,请停止打印
    • 否则:
      • 打印第一个元素,然后
      • 打印数组其余部分的n-1个元素(使用相同的配方)

    数组基本上是指向第一个元素开头的指针,因此您的代码基本上是这样的:

    void print(int *a, int n)
    {   if (n<=0)  return ;
         printf("%d\n", *a);
         print(a+1, n-1);
    }
    
    void打印(int*a,int-n)
    
    {如果(n如此,它会执行以下操作:

  • 检查数组中是否有元素,如果没有,请返回
  • 打印数组中的第一个元素,因为我们知道至少有一个元素
  • 再次调用自身,指向数组中的第二个元素,并从大小中减去1,从而再次从#1开始

  • 此函数将数组的剩余部分及其包含的元素数作为参数。每次打印第一个元素,然后递归调用剩余部分时,都会使用该参数。以下是一个示例:

    array: 1, 2, 3, 4, 5, 6; N = 6
    array: 2, 3, 4, 5, 6; N = 5
    array: 3, 4, 5, 6; N = 4
    array: 4, 5, 6; N = 3
    array: 5, 6; N = 2
    array: 6; N = 1
    array: ; N = 0 return;
    

    每次打印调用都要执行以下操作:

  • 打印数组a的第n个元素,并减少要打印的剩余元素(n)计数。(看着n,就像它意味着:还有多少元素要打印一样)
  • 将指针传递给数组的第二个元素(&a[1])称为自递减(n-1:要打印的元素少了一个),因为第一个元素(a[0])已经打印

  • 您到底不明白什么?

    理解递归IMHO的一个好方法是在调试器中运行代码,并观察调用堆栈和变量。

    它相当于一个循环:

    int i ;
    for (i = 0 ; i< n ; i++) { 
    printf("%d\n",a[i]);
    }
    
    inti;
    对于(i=0;i
    为什么?递归总是查看第一个元素并打印它,然后通过查看第二个元素的数组(在下一次迭代中,它现在将是“第一个”)将它们前进到下一个元素。

    停止条件是不再剩下任何元素,即长度为0的数组。

    函数接受数组和数组长度

    if(n<=0) return;
    
    将打印数组的第一个元素,即元素0

    print(&a[1], n-1);
    
    &[1]获取指向数组第一个元素的指针。数组和指针可以互换使用,因此当将其传递给函数时,函数可以将其视为一个新数组,从上一个数组的第二个元素开始,长度减少一个。

    • 如何打印零大小的数组?简单:您不需要打印
      这就是你的
      if(nIt)如果你用+1替换&a[1],可能更容易理解——它们的意思是一样的。
      
      print(&a[1], n-1);