C语言《C Primer Plus 》 演示递归,递归就像洋葱,假设一个洋葱横切,从外面一层一层打开,每一层都调用一次函数

《C Primer Plus 》例题解析 程序清单 9.6 recur.c 程序


#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
void up_and_down(int);
int main(void)
{
	up_and_down(1);
	return 0;
}
void up_and_down(int n)
{
	printf("Level %d: location %p\n", n, &n); // #1
	if (n < 4)
		up_and_down(n + 1);
	printf("LEVEL %d: location %p\n", n, &n); // #2
}

运行结果:

Level 1: location 004FFE18
Level 2: location 004FFD40
Level 3: location 004FFC68
Level 4: location 004FFB90
LEVEL 4: location 004FFB90
LEVEL 3: location 004FFC68
LEVEL 2: location 004FFD40
LEVEL 1: location 004FFE18

解析

&n是指n的地址

printf1 打印出来的顺序是1234,是因为它在 if 语句之前,每一级函数开始的时候,还没遇到递归判断条件就先打印了它。

printf2 打印出来的顺序是4321,是因为它在 if 语句之前,当函数开始的时候,碰到 if 语句,进入递归,if 语句里面进行一次又一次地函数调用,只有达到了递归的限制条件(n=4)才算调用完了,这时候才会打印 if 语句后面 printf2,而且printf2 是从里层函数往外打印的,所以是4321。

递归就像洋葱,假设一个洋葱横切,从外面一层一层打开,每一层都调用一次函数,而每一层函数up_and_down()都有一个printf1 和一个printf2。

每剥开一片洋葱,if 语句之前的 printf1 先打印一次,等剥到洋葱最里面,不能继续往里剥的时候,也就是不再执行 if 语句的时候,那 if 语句后面的 printf2 就开始打印了。

打印完最里面的printf2,再打上一层函数带的 printf2,然后再打上上一层函数带的 printf2,也就是printf2 是从最里面往外面一层一层打印的。

每一层函数他们的 n 的值是不一样的,但是同一级函数里面,printf1 和printf2 里面 n 的值是一样的,虽然打印的时间有先后,导致printf1 打印的是1234,printf2 打印的是4321,但是,printf1 里面的1和printf2 里面的1 地址是一样,2和2地址是一样的,3和3地址是一样的,4和4地址也是一样的。

千言万语都在下面图表中了:

 注意,这样分解仅仅是便于理解递归的调用过程,递归的基本原理有6个:

  1. 每级函数调用都有自己的变量;
  2. 每级函数调用都会返回一次,当函数执行完毕后,控制权将被传回上一级递归;
  3. 递归函数中位于递归调用之前的语句,均按被调函数的顺序执行;
  4. 递归函数中位于递归调用之后的语句,均按被调函数相反的顺序执行;
  5. 虽然每级递归都有自己的变量,但是并没有拷贝函数的代码。(下面的分解程序是博主自己写出来便于理解的。)程序按顺序执行函数中的代码,而递归调用就相当于又从头开始执行函数的代码。只是每次为递归创建一个变量,递归调用非常类似于一个循环语句。
  6. 递归函数必须包含能让递归调用停止的语句。通常,递归函数都使用 if 或其他等价的测试条件再函数形参等于某特定值时终止递归。

将下面程序于递归的基本原理对应起来如下:

/*5.虽然每级递归都有自己的变量,但是并没有拷贝函数的代码。下面的分解程序是博主自己写出来
便于理解的。程序按顺序执行函数中的代码,而递归调用就相当于又从头开始执行函数的代码。只是
每次为递归创建一个变量,递归调用非常类似于一个循环语句。*/
void up_and_down(int n)  //n=1  
//1.每级函数调用都有自己的变量
//2.每级函数调用都会返回一次,当函数执行完毕后,控制权将被传回上一级递归
{
	printf("Level %d: location %p\n", n, &n); // #1
	//3.递归函数中位于递归调用之前的语句,均按被调函数的顺序执行。
	if (n < 4)
	{
		up_and_down(1 + 1);   //n=2
//1.每级函数调用都有自己的变量
//2.每级函数调用都会返回一次,当函数执行完毕后,控制权将被传回上一级递归
		{
			printf("Level %d: location %p\n", n, &n); // #2
	        //3.递归函数中位于递归调用之前的语句,均按被调函数的顺序执行。

			if (n < 4)
			{
				up_and_down(2 + 1);   //n=3
//1.每级函数调用都有自己的变量
//2.每级函数调用都会返回一次,当函数执行完毕后,控制权将被传回上一级递归
				{
					printf("Level %d: location %p\n", n, &n); // #3
	                //3.递归函数中位于递归调用之前的语句,均按被调函数的顺序执行。

					if (n < 4)
					{
						up_and_down(3+ 1);   //n=4
//1.每级函数调用都有自己的变量
//2.每级函数调用都会返回一次,当函数执行完毕后,控制权将被传回上一级递归
						{
							printf("Level %d: location %p\n", n, &n); // #4
	                        //3.递归函数中位于递归调用之前的语句,均按被调函数的顺序执行。

							if (n < 4)  //条件不符合
					        /*6.递归函数必须包含能让递归调用停止的语句。通常,递归函数都
                           使用if或其他等价的测试条件再函数形参等于某特定值时终止递归。*/
							{
								up_and_down(4 + 1);
							}
							printf("LEVEL %d: location %p\n", n, &n); // #4
						//4.递归函数中位于递归调用之后的语句,均按被调函数相反的顺序执行。
						}
					}
					printf("LEVEL %d: location %p\n", n, &n); // #3
					//4.递归函数中位于递归调用之后的语句,均按被调函数相反的顺序执行。
				}
			}
			printf("LEVEL %d: location %p\n", n, &n); // #2
			//4.递归函数中位于递归调用之后的语句,均按被调函数相反的顺序执行。
		}
	}
	printf("LEVEL %d: location %p\n", n, &n); // #1
	//4.递归函数中位于递归调用之后的语句,均按被调函数相反的顺序执行。
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值