【问题标题】:How can I debug my recursive function that's causing stack overflow error?如何调试导致堆栈溢出错误的递归函数?
【发布时间】:2020-08-03 01:51:36
【问题描述】:

我要解决的问题是 KR2 练习 1-22; '编写一个程序,在第 n 列输入之前出现的最后一个非空白字符之后将长输入行“折叠”成两行或多行较短的行。确保你的程序用很长的行做一些智能的事情,如果在指定的列之前没有空格或制表符。

我试图处理一个递归函数,但它只是卡住了。

错误行为示例:
你好世界 输出 >>
地狱
喔喔
喔喔
喔喔
喔喔
....
...
预期行为:
你好世界 输出 >>
地狱
喔喔
rld

错误行为的第二个例子:
你好世界 输出 >>

呵呵
洛 呵呵
洛 呵呵
呵呵
....
...
次要预期行为:
你好世界 输出 >>

呵呵
工作

见下面的代码:

#include <stdio.h>
#define PAGEWIDTH 5
#define MAXLINE 1000

int getline(char line[], int maxline);
void fold(char line[], int start);

/* "fold" long input lines into two or more shorter lines after
  the last non-blnk character that occurs before the n-th
  column of input */
int main()
{
    int len;                /* current line length*/
    char line[MAXLINE];     /* current input lne*/

    while ((len = getline(line, MAXLINE)) > 0)
        if (len > PAGEWIDTH)
            fold(line, 0);
    return 0;
}

/* getline : read a line into s, return length */
int getline(char s[], int lim)
{
    int c, i;

    c = 0;
    for (i = 0; i < lim - 1 && (c = getchar()) != EOF && c != '\n'; ++i)
        s[i] = c;
    if (c == '\n') {
        s[i] = c;
        ++i;
    }
    s[i] = '\0';

    return i;
}

void fold(char line[], int start)
{
    int i, lstnb;
    i = lstnb = 0;

    for (i = 0; i < PAGEWIDTH-1 && line[start + i] != '\0'; ++i) {
        if (line[start + i] != ' ')
            lstnb = i;
    }
    for (i = 0; i <= lstnb; ++i)
        putchar(line[start + i]);

    putchar('\n');
    if(line[lstnb + 1] != '\0')
        fold(line, lstnb + 1);
}

【问题讨论】:

  • 我会开始使用调试器。但是为什么要递归而不是循环呢?
  • 以这种方式接近它感觉更直观。如果我无法弄清楚当前的问题,我计划重写它以迭代地工作。尽管我仍然感到困惑,但我已经使用了打印语句和调试器。在函数 fold 的初始调用中使用调试器并检查变量“start”,值为 0。随后,它是 -129496704,而不是给定的第一个示例“hello world”输入所期望的 4。打印提供给 fold 的参数(开始)确实显示 4。我认为编译器优化可能是差异的原因,因为事情仍然在一定程度上起作用。
  • 以下 for 循环中出现问题:for (i = 0; i &lt; PAGEWIDTH-1 &amp;&amp; line[start + i] != '\0'; ++i) { if (line[start + i] != ' ') lstnb = i;
  • 提示:问题出在fold 函数的最后两行。提示 2:考虑 lstnb 实际代表什么。
  • 递归是解决问题的好方法;但是当您发现自己在递归函数定义中编写循环,或者在返回 void 的递归函数定义中编写循环时,您应该怀疑自己是否走在正确的轨道上。顺便说一句,您的函数定义是尾递归的; C 不保证尾调用消除,但 GCC 确实 支持它。不过,我不知道任何其他 C 编译器会进行这种优化,而且我严重怀疑 MSVC 会这样做。

标签: c visual-studio visual-c++


【解决方案1】:

好问题。首先,我认为递归解决方案在这里并不理想。我让它适用于您提供的输入,但考虑到 PAGEWIDTH 有多小,您可能会遇到较大输入的问题。使用循环将使您的生活更轻松,并产生更可靠的功能。

也就是说,您的问题在于您在 fold() 函数中进行的递归调用,您提供了错误的起始索引。这意味着您不会在每次通话时都继续前进。此外,您没有明确定义基本情况(即何时结束递归)。您可以通过修改 for 循环条件或将字符串长度 (n) 传递给函数并检查 start > n 来做到这一点。

在调试递归函数时,检查基本情况和递归调用始终是一个很好的起点。这通常是我的问题的来源,很容易假设您正确地完成了这些问题并在调试时忽略了它们。

我不确定您在寻找什么答案,但如果这些建议没有让您更接近,我将修复粘贴到 pastebin here。我没有在这里发布,以防您想自己解决。

希望有效,如果有什么我错过的,请告诉我。

【讨论】:

    猜你喜欢
    • 2011-02-26
    • 2013-04-05
    • 2020-09-11
    • 2018-06-19
    • 2020-03-06
    • 1970-01-01
    相关资源
    最近更新 更多