本文共 1900 字,大约阅读时间需要 6 分钟。
01递归方式逆序打印
02递归和全局变量(把逆序的结果存入全局变量)
03递归和非全局变量(递归指针做函数参数)
#define _CRT_SECURE_NO_WARNINGS#include"stdio.h"#include"stdlib.h"#include"string.h"//01递归方式逆序打印int reverse01(char *p){ if (p == NULL) //递归结束的异常条件 { return -1; } if (*p == '\0') //递归结束的条件 { return 0; } reverse01(p+1); //此时并不会接着执行打印,而是p的地址+1,不断入栈 //开始递归调用,保护程序执行现场,以便程序返回 //补充一个额外的知识点:p++相当于p=p+1,给p做了重新赋值。而p+1并不给p重新赋值 printf("%c\n",*p);}//02递归和全局变量(把逆序的结果存入全局变量)char g_buf[1000];//用全局变量把逆序的结果保存下来int reverse02(char *p){ if (p == NULL) //递归结束的异常条件 { return -1; } if (*p == '\0') //递归结束的条件 { return 0; } reverse02(p + 1); //printf("%c\n", *p); //strncpy(g_buf, p, 1); //每次拷的都是同一个位置,覆盖了 strncat(g_buf, p, 1); //不断向后连接,不会覆盖}//03递归和非全局变量(递归指针做函数参数)int reverse03(char *p, char *bufResult){ if (p == NULL) //递归结束的异常条件 { return -1; } if (*p == '\0') //递归结束的条件 { return 0; } reverse03(p + 1,bufResult); //printf("%c\n", *p); strncat(bufResult, p, 1);}void main(){ int ret = 0; char *p = "123456789"; //ret = reverse01(p); /*memset(g_buf, 0, sizeof(g_buf)); reverse02(p); printf("全局变量g_buf:%s\n", g_buf);*/ char mybuf[1024] = { 0 }; reverse03(p, mybuf); printf("局部变量mybuf:%s\n", mybuf);}
关于reverse(p++)和reverse(p+1):
在递归函数中递归时,若使用reverse(p++),跟踪调试,发现每次递归传进去的p都是完整的“123456789”,并没有实现地址+1的操作。 下面是reverse(p++)调试截图:reverse(p++)时反汇编:
下面是reverse(p+1)的调试截图:
reverse(p+1)时反汇编:
分析:
从上面的调试可以看出:p++时执行死循环,没有ECX寄存器控制(ECX 是计数器(counter), 是重复(REP)前缀指令和LOOP指令的内定计数器)。而p+1时,则lea ecx,[esi+1],最后对esi进行逐个pop。
突然觉得这个话题好低能,看上面的递归,这里用p++和p+1时,对于传入的参数值不同,前者就是p,而后者是p+1。虽然p++会对后续使用p带来影响,但此处的递归函数reverse01需要的是p所指向的下一个地址,可写成p+1或者++p。但是++p改变了p值,反而后续输出则变得不正常。
通过反汇编,也可以看到reverse(p++)成了一个死循环,因为每次reverse(p++)传入的参数都是p,虽然p发生了变化,但是用不上!p++相当于p=p+1,给p做了重新赋值,p发生了更新。而p+1并不给p重新赋值,p不会发生更新。
void main(){ char *p = "123456"; for (; *p != '\0' ; p+1) //死循环不断输出"1" { printf("%c", *p); }}所以什么时候用p++什么时候用p+1,一定要明白这两个的不同之处。