【问题标题】:Recursive function, command after recall递归函数,召回后的命令
【发布时间】:2019-06-07 01:53:57
【问题描述】:

我正在关注 pdf 来研究递归和字符串操作,但我偶然发现了这一点。我通常了解递归函数的行为方式(仍然不是那么好),但无法弄清楚这一点。这反转了字符串。好吧,把它倒过来打印出来。

void reverse(const char *const sptr);

int main()
{

char sentence[80];
printf("Enter a line of text:\n");
gets(sentence);

printf("\nThe reversed version:\n");
reverse(sentence);
puts("");


return 0;
}

void reverse(const char *const sptr)
{
    if(sptr[0] == '\0')
    {
        return;
    }
    else{
        reverse(&sptr[1]);
        putchar(sptr[0]);
    }
}

我真的不明白 putchar 在这种情况下是如何工作的。谁能给我解释一下?我想这不仅适用于 putchar,在调用函数“之后”编写另一个命令行时,该函数的行为如何?

【问题讨论】:

  • imho,这更容易理解没有数组语法,而不是只使用指针算术和解引用运算符。在reverse 内,将所有sptr[0] 更改为*sptr,并将递归调用参数更改为sptr+1,可能(不是说会;可能)有帮助

标签: c string recursion


【解决方案1】:

它与putchar无关,它与递归有关。

假设你给它字符串"1234" - 或者我们称之为['1','2','3','4','\0'] 第一次调用reverse,调用时参数sptr指向['1','2','3','4','\0']

执行到递归调用reverse,这次使用偏移量1,因此参数变为['2','3','4','\0']

重复该过程直到找到'\0',现在该函数返回到打印最后一个字符的前一个调用者,返回到打印第二个最后一个字符的前一个调用者,依此类推,直到顶部反向调用是到达哪个打印第一个字符,然后存在。

也许打印一些额外的调试信息会更容易理解。

#include <stdio.h>

void reverse(const char *const sptr);

int recursion_level;

int main()
{
recursion_level=0;
    char sentence[80]="1234";
    // printf("Enter a line of text:\n");
    // gets(sentence);

    printf("\nThe reversed version:\n");
    reverse(sentence);
    puts("");
    return 0;
}

void reverse(const char *const sptr)
{
        recursion_level++;
        printf("reverse entered, recursion level:%d , sptr:%s \n",recursion_level, sptr);
        if(sptr[0] == '\0')
        {   recursion_level--;
            return;
        }
        else{
            reverse(&sptr[1]);
            putchar(sptr[0]);
        }
        printf("\n  reverse exits, recursion level:%d , \n",recursion_level);
        recursion_level--;
}

生成以下输出

The reversed version:                                                                                                                          
reverse entered, recursion level:1 , sptr:1234                                                                                                 
reverse entered, recursion level:2 , sptr:234                                                                                                  
reverse entered, recursion level:3 , sptr:34                                                                                                   
reverse entered, recursion level:4 , sptr:4                                                                                                    
reverse entered, recursion level:5 , sptr:                                                                                                     
4                                                                                                                                              
  reverse exits, recursion level:4 ,                                                                                                           
3                                                                                                                                              
  reverse exits, recursion level:3 ,                                                                                                           
2                                                                                                                                              
  reverse exits, recursion level:2 ,                                                                                                           
1                                                                                                                                              
  reverse exits, recursion level:1 ,  

【讨论】:

    【解决方案2】:

    这是因为:

       reverse(&sptr[1]);
       putchar(sptr[0]);
    

    你首先调用下一个字符然后你打印第一个字符,所以

    • 第一个打印的字符将是最后一个
    • 然后你回来写前一个就在最后一个之前
    • ...
    • 然后你回来打印第一个字符

    &amp;sptr[1] 等价于sptr + 1,因此指向下一个字符的地址


    如果你颠倒这些线并这样做:

       putchar(sptr[0]);
       reverse(&sptr[1]);
    

    您按初始顺序打印字符


    当你不明白时,只需一步一步将程序执行到调试器中

    【讨论】:

      【解决方案3】:

      很简单。

      您以字符串作为参数递归调用函数。每次调用字符串都短一个字符(当您将指针传递给字符串中的第二个 char 时。当它的长度为零时,第一个返回发生。字符串的长度为 1,它只是字符串的最后一个字符字符串。你打印它(当你打印第一个字符时),然后你返回到字符串长度为 2 个字符的实例 - 你打印它的第一个字符是从末尾算起的第二个字符。然后你返回,字符串是 3 chars long 您再次打印第一个字符,并重复此操作,直到您以相反的顺序打印字符串中的所有字符。

      您根本不需要 else 语句,因为如果满足条件,控件将永远不会到达该语句

      void reverse(const char *const sptr)
      {
          if(!sptr[0]) return;
          reverse(&sptr[1]);
          putchar(sptr[0]);
      }
      
      int main()
      {
          reverse("Hello World");
      
          return 0;
      }
      

      你也可以添加检查参数是否为NULL

      void reverse(const char *const sptr)
      {
          if(!sptr && sptr[0] == '\0') return;
          reverse(&sptr[1]);
          putchar(sptr[0]);
      }
      

      【讨论】:

        【解决方案4】:

        正如所有其他人所说,这很简单。

        但最好的解释是看看你如何在你的 C 代码中添加一些日志。

        #include "pch.h"
        #include <stdio.h>
        #include <stdlib.h>
        
        void reverse(const char *const sptr);
        void openTraceFile();
        void closeTraceFile();
        void enterFunction();
        void exitFunction();
        void writeMessage(const char* s);
        
        int main()
            {
            char sentence[80];
            printf("Enter a line of text:\n");
            //gets(sentence);
            fgets(sentence, 80, stdin);
        
            openTraceFile();
        
            printf("\nThe reversed version:\n");
            reverse(sentence);
            puts("");
        
            closeTraceFile();
        
            return 0;
            }
        
        static FILE* logfile;
        static int iNrSpaces = 0;
        
        void reverse(const char *const sptr)
            {
            enterFunction();
        
            if (sptr[0] == '\0')
                {
                writeMessage("end of string");
                exitFunction();
                return;
                }
        
            reverse(&sptr[1]);
        
            putchar(sptr[0]);
        
            char s[80];
            sprintf(s,"putchar( %c )", sptr[0]);
            writeMessage(s);
        
            exitFunction();
            }
        
        void openTraceFile()
            {
            logfile = fopen("reverse.log", "w");
        
            if (logfile == NULL)
                {
                printf("Error! Could not open file\n");
                exit(-1);
                }
        
        
        void closeTraceFile()
            {
            fclose(logfile);
            }
        
        void enterFunction()
            {
            writeMessage(">> reverse()");
            iNrSpaces += 4;
            writeMessage("{");
            }
        
        void exitFunction()
            {
            writeMessage("}");
            iNrSpaces -= 4;
            }
        
        void writeMessage(const char* s)
            {
            for (int i = 0; i < iNrSpaces; i++)
                {
                fputc(' ',logfile);
                }
            fprintf(logfile, s);
            fputc('\n', logfile);
            }
        

        当你在输入“帮助”中执行这个程序时,你会在reverse.log文件中得到以下几行。

        >> reverse()
            {
            >> reverse()
                {
                >> reverse()
                    {
                    >> reverse()
                        {
                        >> reverse()
                            {
                            >> reverse()
                                {
                                end of string
                                }
                            putchar( \0 )
                            }
                        putchar( p )
                        }
                    putchar( l )
                    }
                putchar( e )
                }
            putchar( h )
            }
        

        如果现在,你在不改变执行顺序的情况下提取 putchar() 调用,你将获得

        putchar( p ); 
        putchar( l ); 
        putchar( e ); 
        putchar( h ); 
        

        那是反转的字符串!

        我希望这个使用LOG的解释可以帮助你理解这个问题。

        小备注:\0 字符在您的示例中首先是返回者!

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2014-12-06
          • 1970-01-01
          • 2017-12-11
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2022-01-16
          相关资源
          最近更新 更多