【问题标题】:Seg fault on strcatstrcat 上的段错误
【发布时间】:2012-12-09 08:53:29
【问题描述】:

所以我的代码中出现了段错误,我似乎无法弄清楚是什么原因造成的。有人能捕捉到我没有捕捉到的东西吗?

从逻辑上讲,我试图通过将事物连接到末尾来创建一个 char 数组(一个字符串),然后将其添加到一个字符串数组中。

它最终应该是这个'word1、word2、word3、word4、word5...等'

段错误发生在strcat(str, ", ");

void save_ladder(graphNode *curNode) {

    char *str = malloc(1000 * sizeof(char));

    strcpy(str, "");
    strcat(str, curNode->word);
    strcat(str, ", ");

    graphNode *prev = curNode->prevWord;
    while (prev != NULL) {
            if (prev->prevWord != NULL) {
                strcat(str, prev->word);
                strcat(str, ", "); // SEG FAULT HAPPENS HERE
            }
            else 
                strcat(str, prev->word);

            prev = prev->prevWord;
    }

    ladders[numLadders++] = str;
}

gdb 堆栈跟踪:

Program received signal SIGSEGV, Segmentation fault.
0x00000000004013d1 in save_ladder (curNode=0x6420f0) at wordladder.c:150
150             strcat(str, ", ");

有人知道为什么会这样吗?

【问题讨论】:

  • sizeof(char) 始终为 1。并显示更多关于结构和为其内容分配内存的代码 - 问题可能在于这些。
  • 您确定您使用的字符数不超过分配的 1000 个字符吗?在崩溃之前打印字符串的样子可能很有用。
  • 这很可能是缓冲区溢出。您希望最终的字符串可以容纳 999 个字符吗?如果是这样,错误一定是您添加了更多的字符,这由您的链表决定。因此,结构。
  • 使用调试器。看看你的变量。我们不能。
  • 我将通过在 malloc 行上放置一个断点来开始调试此问题,并记下该值。然后检查,发生错误时str的值是否仍然相同。还要检查结果字符串是否小于 1000 个字符。

标签: c strcat


【解决方案1】:

可能是缓冲区溢出。将以下代码放在您的 while 循环中并检查是否是这种情况:

printf ("%d %d\n", strlen (str), strlen (prev->word));

如果这两个数字的总和接近 1000,则您的缓冲区可能需要更大。

或者,如果第二个似乎有点大或似乎有太多单词,那么您列表中的数据或列表结构本身都是可疑的。

此外,还有两点。第一个是你永远不需要乘以sizeof(char),因为它总是1(你还应该检查malloc的返回值,以防它失败)。

第二个是您可以因此简化字符串构造,而无需 while 中的 if 语句:

strcpy(str, curNode->word);
graphNode *prev = curNode->prevWord;
while (prev != NULL) {
    strcat (str, ", ");
    strcat(str, prev->word);
    prev = prev->prevWord;
}

【讨论】:

  • 是的,看起来是缓冲区溢出。字符串实际上不应该那么长,但不知何故,我在代码中的其他地方删除了一个“- 1”,这导致了这种情况的发生。我花了一段时间才找到丢失的 - 1,但是当我这样做时,问题就解决了!并感谢您的字符串构造。我一直在这个项目上工作了 12 个小时,所以我处于自动驾驶模式,没有费心优化任何东西......
【解决方案2】:

我有两件事要注意/评论/回复:

  1. 您正在使用Schlemiel the Painter 的算法:在每个strcat() 上,再次遍历收集到的字符串。您应该考虑使用指向您当前所在位置的“光标指针”:将每个strcat(str, ...) 替换为strcpy(crsr, ...),后跟crsr += strlen(crsr),以便将其设置为到目前为止的字符串末尾。 crsr 应在开始时设置为 str

  2. 正如其他人所写,您的代码最多只能使用 1000 个字符。要么你的 structor 坏了,要么其中一个字符串太长。无论如何,您的算法太不灵活了。您应该考虑在附加之前检查每个字符串长度,如果不合适,realloc() 您的str 适当。 (不要忘记更新您的crsr。)在这种情况下,您不再有任何限制。

    将您的 str 最后调整为 strlen(str) + 1,以免浪费内存。

【讨论】:

  • 我确实明白每次我想附加一些东西时我都在遍历 char 数组,但由于我对 C 还比较陌生,所以我不知道如何绕过它。谢谢!跨度>
【解决方案3】:

我同意缓冲区溢出的答案。我也同意代码清理。但是,我认为也许您应该研究 asprintf 或 snprintf。使用 asprintf,您提供一个 char ** 并返回新字符串的位置。如果您不需要自己仔细管理内存,这将非常有用。这个例程也是一个 GNU 扩展,所以请注意。 Snprintf 让我们传递一个 char * 和剩余缓冲区的长度,以确定其余的格式是否适合。这将捕获溢出。

这里是一个使用 asprintf 的例子:

char *output = NULL;
char *last = NULL;

prev = curNode;
while (prev != NULL) {
    last = output;
    if (asprintf(&output, "%s,", prev->word) < 0) {
        break;  // error
    }
    if (last != NULL)
        free(last);
    }
    prev = prev->prevWord;
}

// remove trailing ',' here

注意:上面的代码没有经过测试(我是在平板电脑上写的。)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-03-16
    • 1970-01-01
    • 1970-01-01
    • 2020-10-05
    • 2012-01-06
    • 1970-01-01
    • 2013-02-04
    • 1970-01-01
    相关资源
    最近更新 更多