简体   繁体   English

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

[英]How this code work, really short way to reverse a string, It work, but I can't figure out how

Please need to know how this reverse function work, don't really get it, I know pointer do point to string[0], but how this function is able to print the right character to reverse the string correctly, How this is archive? 请需要知道这个反向函数是如何工作的,并没有真正得到它,我知道指针确实指向string [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??????
}

Your reverse() function is not actually reversing the string in memory, it is just outputting the string's characters in reverse order (to actually reverse the string in memory, use the STL's std::reverse() algorithm). 您的reverse()函数实际上并没有反转内存中的字符串,它只是以相反的顺序输出字符串的字符(要实际反转内存中的字符串,请使用STL的std::reverse()算法)。

Now, lets look at the logic. 现在,让我们看一下逻辑。

main() calls reverse() . main()调用reverse() A stack frame is pushed on the call stack, where s is pointing at the 1st character ( str decays into a pointer to the first character). 将堆栈帧压入调用堆栈,其中s指向第一个字符( str衰减为指向第一个字符的指针)。

s is not pointing at the null terminator, so reverse() calls itself, pushing a new stack frame on the call stack, where s contains a pointer to the 2nd character. s没有指向空终止符,因此reverse()自行调用,将新的堆栈帧推入调用堆栈,其中s包含一个指向第二个字符的指针。

s is not pointing at the null terminator, so reverse() calls itself again, pushing a new stack frame on the call stack, where s contains a pointer to the 3rd character. s没有指向空终止符,因此reverse()再次调用自身,将新的堆栈帧压入调用堆栈,其中s包含指向第三个字符的指针。

And so on, until reverse() is running with a stack frame where s is pointing at the null terminator. 依此类推,直到reverse()运行带有s指向空终止符的堆栈帧为止。 At this point, nothing has been output to std::cout yet, and a pointer to every character, including the null terminator, has been pushed onto the call stack in first-to-last order. 此时, std::cout尚未输出任何内容,指向每个字符(包括空终止符)的指针已按倒数第一的顺序推入调用堆栈。

调用堆栈

Now, reverse() stops calling itself and just exits, popping the current stack frame from the call stack (where s points at the null terminator). 现在, reverse()停止调用自身而只是退出,从调用堆栈中弹出当前堆栈帧(其中s指向空终止符)。

Execution returns to the previous call site of reverse() , whose stack frame has s pointing at the last character. 执行返回到reverse()的上一个调用位置,该堆栈的堆栈框架的s指向最后一个字符。 That character is output to std::cout and then reverse() exits, popping that stack frame from the call stack. 该字符将输出到std::cout ,然后退出reverse() ,从调用堆栈中弹出该堆栈帧。

Execution returns to the previous call site of reverse() , whose stack frame has s pointing at the 2nd-to-last character. 执行返回到reverse()的前一个调用位置,该堆栈的堆栈帧的s指向倒数第二个字符。 That character is output to std::cout and then reverse() exits, popping that stack frame from the call stack. 该字符将输出到std::cout ,然后退出reverse() ,从调用堆栈中弹出该堆栈帧。

Execution returns to the previous call site of reverse() , whose stack frame has s pointing at the 3rd-to-last character. 执行将返回到reverse()的前一个调用位置,该堆栈的堆栈帧的s指向倒数第二个字符。 That character is output to std::cout and then reverse() exits, popping that stack frame from the call stack. 该字符将输出到std::cout ,然后退出reverse() ,从调用堆栈中弹出该堆栈帧。

And so on, until execution returns to main() , and the entire string has been output to std::cout in reverse order. 依此类推,直到执行返回到main()为止,并且整个字符串已按相反的顺序输出到std::cout

reverse(char *s) is a recursive function. reverse(char *s)是一个递归函数。 Recursive function would terminate only if certain conditions are met. 仅当满足某些条件时,递归函数才会终止。 In your example, the condition is *s == NULL 在您的示例中,条件是*s == NULL

If the condition does not met, it would uses a stack to save the content of current function and execute the remaining code until its next generation complete all the tasks . 如果不满足条件,它将使用堆栈来保存当前函数的内容并执行剩余的代码, 直到其下一代完成所有任务为止

In your example, all cout << *s would be push into the stack until the last generation. 在您的示例中,所有cout << *s都将被压入堆栈,直到最后一代为止。 Therefore, the first time you execute cout << *s is actually printing the last character of your string. 因此,第一次执行cout << *s实际上是打印字符串的最后一个字符。

For example, let char arr[] = "READ" be the array. 例如,让char arr[] = "READ"为数组。

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

After the last generation is complete: 上一代完成后:

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

And then the next generation 然后是下一代

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

And then the final generation 然后是最后一代

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

This is exactly how to print a string backwards recursively. 这正是递归地向后打印字符串的方法。

Translated into English: in order to print a string in reverse, you first reverse-print everything except its first character, then you print its first character. 翻译成英文:为了反向打印字符串,首先要反向打印除第一个字符以外的所有内容,然后再打印其第一个字符。 If the string is empty, you do nothing. 如果字符串为空,则不执行任何操作。

Recursion, like the idea of functions in general, is older than computers. 像一般的功能概念一样,递归比计算机早。 You can understand it without knowing a single thing about how a programming language might be implemented. 您无需了解如何实现编程语言就可以了解它。
(It helps if you're familiar with mathematical induction, but it's definitely not a requirement.) (它帮助 ,如果你熟悉数学归纳法,但它绝对不是一个要求。)

In fact, if you understand that in order to "first do this , then do that ", that has to wait until this is done, you've pretty much understood everything. 事实上,如果你明白,以“先这样做,那么 ”, 要等到做到一点,你已经非常明白了一切。

The only thing missing, and what makes it recursive, is that in order to accomplish this , you may possibly need to do a smaller bit of " this , then that " first. 唯一缺少的是递归,为了做到这一点 ,您可能需要先做一小部分“ this ,then that ”。

More concretely, suppose we want to print "abc" in reverse. 更具体地说,假设我们要反向打印“ abc”。

One way to look at it as that we need to first print 'c', then 'b', then 'a'. 一种看待它的方式是,我们需要先打印'c',然后打印'b',然后打印'a'。

Another way is to say that we can first print "cb", then 'a'. 换句话说,我们可以先打印“ cb”,然后打印“ a”。
But "cb" is also the reverse of the "tail" of "abc", so we should be able to use the same procedure for reversing both "abc" and "bc" - as long as we know how to reverse a shorter string, we can do that and then tack the string's first character on afterwards. 但是“ cb”也是“ abc”的“ tail”的反转,因此我们应该能够使用相同的过程来反转“ abc”和“ bc”-只要我们知道如何反转较短的字符串,我们可以执行此操作,然后在字符串上附加第一个字符。
When does it end? 什么时候结束?
When we reach the shortest possible string, the empty string, we don't need to do anything, so that's where it ends. 当我们到达最短的字符串(空字符串)时,我们无需执行任何操作,因此它就此结束。

Slightly more formally, we can use this procedure: 稍微正式一点,我们可以使用以下过程:

  • If the string is empty, do nothing. 如果字符串为空,则不执行任何操作。
  • If the string is not empty: 如果字符串不为空:
    • First print, using this procedure, all the characters except the first one, 使用此过程进行第一次打印,除第一个字符外的所有字符,
    • Then print the first character. 然后打印第一个字符。

and reversing "abc" will go like this: 并反转“ 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]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM