这段代码是如何工作的,很短的方法来反转一个字符串,它工作,但我不知道如何

Posted

技术标签:

【中文标题】这段代码是如何工作的,很短的方法来反转一个字符串,它工作,但我不知道如何【英文标题】:How this code work, really short way to reverse a string, It work, but I can't figure out how 【发布时间】:2017-08-04 00:59:34 【问题描述】:

请知道这个反向函数是如何工作的,不是很明白,我知道指针确实指向字符串[0],但是这个函数如何能够打印正确的字符来正确地反转字符串,这是怎么回事是存档吗?

#include <iostream>
using namespace std;

void reverse(char *s); //prototype
//-------------------------------------------------------------------       
int main ()

    char str[] = "begin_this is a test_last";    //cstring to be reverse

    reverse(str);    //recursive function

    cout << "\n";

    return 0;

//--------------------------------------------------------------------- 
void reverse(char *s)               
                                   
    if(*s)                         
        reverse(s + 1);
    else
        return;
    cout << *s;   //question how this print the string in reverse??????

【问题讨论】:

在递归的情况下,C 和 C++ 对于摇滚乐来说已经足够接近了,因此阅读很有帮助:How Recursion works in C 这对任何较长的字符串都不起作用。 是时候学习调试器了。 一个递归堆栈,当它全部展开时会从前打印。刚开始学习时有点难以概念化,但你会做到的。 感谢您抽出宝贵时间,但没有太多答案,有点假设,我明白了。 【参考方案1】:

您的reverse() 函数实际上并没有反转内存中的字符串,它只是以相反的顺序输出字符串的字符(要实际反转内存中的字符串,请使用 STL 的 std::reverse() 算法)。

现在,让我们看看逻辑。

main() 呼叫reverse()。堆栈帧被压入调用堆栈,其中s 指向第一个字符(str 衰减为指向第一个字符的指针)。

s 没有指向空终止符,所以reverse() 调用自己,在调用堆栈上压入一个新的堆栈帧,其中s 包含指向第二个字符的指针。

s 没有指向空终止符,因此reverse() 再次调用自身,将新的堆栈帧压入调用堆栈,其中s 包含指向第三个字符的指针。

以此类推,直到reverse() 使用堆栈帧运行,其中s 指向空终止符。此时,尚未向std::cout 输出任何内容,并且指向每个字符的指针(包括空终止符)已按从上到下的顺序被压入调用堆栈。

现在,reverse() 停止调用自身并退出,从调用堆栈中弹出当前堆栈帧(s 指向空终止符)。

执行返回到reverse()的前一个调用点,其堆栈帧有s指向最后一个字符。该字符输出到std::cout,然后reverse() 退出,从调用堆栈中弹出该堆栈帧。

执行返回到reverse() 的前一个调用点,其堆栈帧有s 指向倒数第二个字符。该字符输出到std::cout,然后reverse() 退出,从调用堆栈中弹出该堆栈帧。

执行返回到reverse() 的前一个调用点,其堆栈帧有s 指向倒数第三个字符。该字符输出到std::cout,然后reverse() 退出,从调用堆栈中弹出该堆栈帧。

以此类推,直到执行返回main(),整个字符串已经逆序输出到std::cout

【讨论】:

谢谢你的时间,我猜这个递归do循环调用了自己,但是main只调用了一次,而cout语句只被一个else执行,我只看到它,执行时NULL被命中,此时s指针位于字符串的'l'位置,此时,我放弃了对cout的调用,因为满足NULL条件,但是指针如何从NULL跳转,我的循环在我的脑海中, 是使用字符串 [0] 的原始调用,递归调用字符串 [0+n],但一直到最后一个字符串 [last],原始,. 将生成对内部递归函数的调用,该函数将指向 string[NULL],现在将触发 else 和 cout,我知道我的方法在某些方面是错误的,但是在哪里.. @ForceBeWhithYou:我向你解释的内容到底有什么不清楚的地方?我确切地解释了代码如何从头到尾在字符串中移动,然后从尾到头打印字符。您了解什么是调用堆栈,以及堆栈帧是如何工作的吗? __cdecl 调用约定如何与调用堆栈交互?如果没有,在处理递归之前,你需要学习更多(以及为什么长时间迭代会很危险) 我确实对堆栈功能有所了解,现在,您的解释以一个绝妙的概念得到了很好的理解,对我来说,很难将这个功能与其他功能结合起来,谁来做 cout。我在理解递归、数字和算术方面从来没有问题,但是这个从 else 语句中消失的概念让我很受打击,感谢您抽出时间,我会参考您推荐的例程 _cdecl @ForceBeWhithYou:重写reverse() 以删除else,也许它对你更有意义:void reverse(char *s) if (*s == 0) return; reverse(s + 1); cout &lt;&lt; *s; 你了解return 的实际作用吗?以及调用函数如何阻塞调用者直到函数退出,然后调用者从中断处继续?【参考方案2】:

reverse(char *s) 是一个递归函数。只有满足某些条件,递归函数才会终止。在您的示例中,条件为*s == NULL

如果条件不满足,它将使用堆栈来保存当前函数的内容并执行剩余的代码直到它的下一代完成所有任务

在您的示例中,所有cout &lt;&lt; *s 都将被推入堆栈,直到最后一代。因此,第一次执行cout &lt;&lt; *s 实际上是打印字符串的最后一个字符。

例如,设char arr[] = "READ" 为数组。

1st   R  // waiting
2nd   E  // waiting
3rd   A  // waiting
4nd   D  // printing!!

上一代完成后:

1st   R  // waiting
2nd   E  // waiting
3rd   A  // printing!!
4nd   D  // finish!!

然后是下一代

1st   R  // waiting
2nd   E  // printing!!
3rd   A  // finish!!
4nd   D  // finish!!

然后是最后一代

1st   R  // printing!!
2nd   E  // finish!!
3rd   A  // finish!!
4nd   D  // finish!!

这正是递归打印字符串的方法。

【讨论】:

这正是我所看到的,没有其他循环命中 NULL,直到调用字符串的最后一个字符,并且因为该函数使用 s + 1,所以从那里满足 NULL 标准,另一个角色是如何被 cout 击中的,你向我解释,他们已经在堆栈中,并且打印递归,但我看不到,当满足条件时,在你的 READ 示例中打印 A 我得到了堆栈的东西,但是,当它需要用于存储 A 时,我看不到它,只有 D。并且函数在我的周期中结束。 男人们,我什么时候去调试器看看,那些调用,到堆栈,重复,cout 语句邪恶谢谢大家。【参考方案3】:

翻译成英文:为了反向打印一个字符串,你首先反向打印除第一个字符之外的所有内容,然后打印它的第一个字符。如果字符串为空,则什么也不做。

递归,就像一般的函数概念一样,比计算机更古老。您无需了解编程语言的实现方式就可以理解它。 (如果您熟悉数学归纳法,它会有所帮助,但绝对不是必需的。)

其实,如果你理解为了“先做this,再做that”,that必须等到到此 完成了,你就差不多明白了。

唯一缺少的,也是递归的,是为了完成this,你可能需要做一小部分“this,然后那个”首先。

更具体地说,假设我们要反向打印“abc”。

一种看待它的方式是,我们需要先打印'c',然后是'b',然后是'a'。

另一种说法是,我们可以先打印“cb”,然后打印“a”。 但是“cb”也是“abc”的“tail”的反转,所以我们应该能够使用相同的过程来反转“abc”和“bc”——只要我们知道如何反转a 较短的字符串,我们可以这样做,然后将字符串的第一个字符添加到后面。 什么时候结束? 当我们到达最短的字符串时,空字符串,我们不需要做任何事情,所以它就结束了。

稍微正式一点,我们可以使用这个过程:

如果字符串为空,则什么也不做。 如果字符串不为空: 第一次打印,使用此程序,除第一个字符外的所有字符, 然后打印第一个字符。

并且反转“abc”将如下所示:

   Reverse "abc"
-> Reverse "bc", then print 'a'
-> Reverse "c", then print 'b', then print 'a'
-> Reverse "", then print 'c', then print 'b', then print 'a'

Reversing "" is to not do anything. 
After we've done nothing, we can continue executing the rest of the sentence.

-> print 'c', then print 'b', then print 'a'
   [Output: c]
-> print 'b', then print 'a'
   [Output: cb]
-> print 'a'
   [Output: cba]

【讨论】:

以上是关于这段代码是如何工作的,很短的方法来反转一个字符串,它工作,但我不知道如何的主要内容,如果未能解决你的问题,请参考以下文章

在很短的时间后多次播放音频文件?

编写汇编语言代码来反转字符串

使用splice()方法反转数组

sizeToFit 在非常短的字符串周围放置填充

这段代码如何反转? (递归)

在Python中反转一个字符串