老规矩先看代码
void reverse_string(char* string)
{
int sz = 0;
while (string[sz] != '\0') {
sz++;
}
if (sz<2) {
return;
}
char* left = string;
char* right = (string + sz - 1);
int ret = *left;
*left = *right;
*right = string[sz];
reverse_string(string+1);
*right = ret;
}
int main()
{
char arr[] = "abcdef";
reverse_string(arr);
printf("%s\n", arr);
return 0;
}
下面看一下运行结果
我们可以看到,字符串逆序了,说明代码没问题
接下来我来解释解释其中的难点
我们知道,字符串逆序就是将字符串首尾字符交换,直到最中间的元素交换完,这就满足了我们递归的三个条件:
问题规模要越递越小,直到拆解成基本问题
拆解成的基本问题要保持和原问题思路一样
存在递归中止条件
也就是下面这张图的内容:
上图中,我们将递归进行拆解,函数功能首先需要将两个字符交换,其次每次交换后,首尾各“去掉一位”,也就是说,我们把字符串逆序问题拆解成了c和e进行交换,终止条件是只剩下d元素,也就是当我们检索到字符串长度的一半时,有的同学可能会多想奇偶数的问题,但是这个条件与字符串长度是奇偶数无关。
非小白可能一看就懂了,但是小白还是云里雾里的,没关系,我逐句讲解一下大家就明白了
int sz = 0;
while (string[sz] != '\0') {
sz++;
}
由于不能使用库函数,这串代码代替库函数strlen的作用,计算字符串长度。
if (sz<2) {
return;
}
如果字符串长度小于2就不用交换了,这就是终止条件
char* left = string;//首指针,用来指向字符串首元素
char* right = (string + sz - 1);//尾指针,用来指向尾元素
这里我们通过指针将尾元素与首元素交换,交换完成后我们应该交换第二个元素和倒数第二个元素,也就是把第二个元素的地址传给reverse_string
函数,如果思路是这样的,逆序的结果就会变成fabcde
,我们会发现一个问题,首指针指向第二个元素了,尾指针怎么办?由于题目要求,只能有字符串这一个参数,并且left
和right
必须都要变化,所以我们发现right=string+sz-1
,可以用计算出来的sz
进行控制
int ret = *left;//用于保存第一个元素
*left = *right;
*right = string[sz];
reverse_string(string+1);//每次递归调用时,首指针后移
这段代码是核心,我们知道,计算sz
时,从第一个字符读到‘\0’
,就会停止,那么在将尾指针指向的元素地址赋值给首指针之前,我们先用临时变量保存第一个元素,然后再将‘\0’赋值给最后一个元素,这样每次递归,sz
就相当于执行sz--
操作,如下图所示
当sz < 1
时,函数return
,*right = ret;
这条代码就就会将每次递归保存下来的首元素放进'\0'
的位置