昨天有人问问了我这样一道题,如何不利用第三方变量,将字符串逆序输出。我给出了几种方案,有非递归的,也有递归的。
一:
首先来非递归的,这个就比较简单了,直接利用strlen函数求得字符串长度,然后逆序输出即可。
代码如下:
#include <iostream>
#include <string.h>
void reverse_str(const char *str)
{
auto len = strlen(str);
for(int i=len-1; i>=0; --i){
std::cout << str[i];
}
}
int main(int argc, char ** argv)
{
if(argc != 2){
fprintf(stdout, "Usage %s <string>\n", argv[0]);
exit(EXIT_FAILURE);
}
reverse_str(argv[1]);
return 0;
}
二:
其次为递归方法,递归的思路是函数压栈,当检测到\0,递归终止,然后函数出栈,逆序打印每个字符。
其中有两点值得注意:
1、字符串作为全局变量
<pre name="code" class="cpp">#include <iostream>
const char *str = "iloveyou";
void reverse_string(const char *)
{
if(*str != '\0')
reverse_string(++str);
if(*str != '\0')
std::cout << *str;
--str;
}
int main(int argc, char** argv)
{
reverse_string(str);
return 0;
}
这种递归方法显然可以成功,然后我又想用字符串定义在主函数,利用主函数调用的方式。
2.字符串作为主函数局部变量
(1)++str
我首先用了这样的写法:
//wrong
#include <iostream>
void reverse_string(const char *str) //error,因为++str如果在底层函数中改变,想要在上一层保留变动结果,需要传递引用。
{
if(*str != '\0')
reverse_string(++str); //
if(*str != '\0')
std::cout << *str;
--str;
}
int main(int argc, char** argv)
{
const char *str = "iloveyou";
reverse_string(str);
return 0;
}
这个写法困扰了我好长时间,它总是打印不到第一个字母,后来我突然意识到,如果需要在递归子程序里面改变参数的值,就需要传递引用给它,这样才能保留你要做的改动,并返回给上一层。下面这种写法才是正确的:
#include <iostream>
void reverse_string(const char *&str) //right,传递引用
{
if(*str != '\0')
reverse_string(++str);
if(*str != '\0')
std::cout << *str;
--str;
}
int main(int argc, char** argv)
{
const char *str = "iloveyou";
reverse_string(str);
return 0;
}
(2)str+1
另外一种写法就是直接用str+1,这样你的str指针始终指向不变,只是传递给下一层的参数,是你的str+偏移量的那个地址,相当于tmp = str +偏移量,tmp传给下一层子函数。而不是str++, str++其实是 str = str + 1,str自身指向也改变了。
由于每一层子函数都有自己的str+偏移量结果,自然不需要传递引用了,因为我们不需要也不会改变str的指向,也就不需要--str了。代码如下:
#include <iostream>
void reverse_string(const char *str) //由于不用改变str,所以不需要传递引用
{
if(*str != '\0')
reverse_string(str+1); //对应str+1
if(*str != '\0')
std::cout << *str;
//--str; //每一层都有自己的str+偏移量
}
int main(int argc, char** argv)
{
const char *str = "iloveyou";
reverse_string(str);
return 0;
}
三:
终极方法:main函数的递归调用实现字符串逆序输出。
1.首先我给出了这样的写法:
#include <iostream>
char* str = "iloveyou";
int main(char *, char **argv = NULL)
{
if(*str != '\0')
main(++str);
if(*str != '\0')
std::cout << *str;
--str;
return 0;
}
这种写法编译有警告,但可执行且输出结果正确。
不过本着好学的精神,我自己把它的几个警告一一解决掉了。
2.完美无敌版如下:
#include <iostream>
const char *str = "iloveyou";
int main(int argc , char** argv = NULL)
{
char ch = (char)argc;
if(ch != '\0')
main(*((int *)const_cast<char*>(++str))); //const_cast解除const限定
if(ch != '\0')
std::cout << *str;
--str;
return 0;
}
首先给字符串加上const解决第一个警告,但是由于加了const之后,再将str作为参数传递时,接受参数也必须为const,但是main函数参数如上图第二个警告所说,第一个必须为int型,所以先用const_cast去掉str的const限定,将str转为为Int类型,用argc参数接收,然后在函数内部进行强转赋给ch,通过char类型的ch作为判断条件,利用类似子函数递归逆序的方法,实现main函数的递归调用。
正确输出为: