2

诚然,我是一个纯 C 的新手,但这让我很难过。我正在研究一个链表实现以供练习,我通过简单地向 split_node 函数添加一个变量来得到一个段错误:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

struct Node {
    struct Node *child;
    char *content;
};

void print_list(struct Node node);
void split_node(struct Node *node, int position);

int main() {

    struct Node head, second, third;

    head.content = "first";
    second.content = "second";
    third.content = "i'm third";

    head.child = &second;
    second.child = &third;

    print_list(head);
    split_node(&head, 3);
    print_list(head);

    return 0;
}

void print_list(struct Node node) {
    printf("%s\n", node.content);
    if(node.child) print_list(*node.child);
}

    /*
    Split node into two nodes, with the first position characters of the node's content remaining with node, and the remainder being copied to the new node. (It doesn't yet truncate the first node's string, but does do the copy.)
    */
void split_node(struct Node *node, int position) {
    if(position >= strlen((*node).content)) return;
    struct Node newNode;
    newNode.child = (*node).child;
    (*node).child = &newNode;

    int length = (strlen((*node).content) - position);
    newNode.content = malloc(sizeof(char) * (length + 1));
    strncpy(newNode.content, (*node).content + sizeof(char) * position, length);
    newNode.content[length] = '\0';

    //int foo;
}

此代码编译(gcc -Wall -o list list.c)并运行良好:

$ ./list
first
second
i'm third
first
st
second
i'm third

但是如果我int foo在结尾取消注释split_node,编译并运行,我会得到:

$ ./list
first
second
i'm third
first
st
Segmentation fault

gdb 给了我这个回溯:

#0  0x91d6ae70 in strlen ()
#1  0x91dd3126 in puts ()
#2  0x00001f21 in print_list (node={child = 0xbcec815b, content = 0x8b000000 <Address 0x8b000000 out of bounds>}) at list.c:41
#3  0x00001f3c in print_list (node={child = 0x8fe0154b, content = 0x1ff6 "i'm third"}) at list.c:42
#4  0x00001f3c in print_list (node={child = 0xbffff568, content = 0x1fef "second"}) at list.c:42
#5  0x00001f3c in print_list (node={child = 0xbffff570, content = 0x1fe9 "first"}) at list.c:42
#6  0x00001ee0 in main () at list.c:33

为什么添加变量定义会导致段错误?它似乎正在破坏新创建节点的内容指针。我很困惑; 有什么帮助吗?

4

3 回答 3

15

您需要动态分配节点(使用 malloc)。

正如你所拥有的,你的新节点被声明在堆栈上。当 split 函数返回时,该新节点不再是有效内存。

添加变量会导致段错误,因为该变量会更改堆栈的布局,从而导致函数返回时的行为略有不同。

于 2009-01-11T21:08:07.280 回答
0

尝试将 Nodes 子属性设置为 NULL,C 不会自动将内存归零,因此看起来您的子项中可能有垃圾(或者您可以使用 calloc 而不是 malloc)。SoapBox 的回答也是正确的。

于 2009-01-11T21:11:38.210 回答
0

Valgrind是一个很好的工具来帮助发现这些类型的问题。您可以从命令行执行“valgrind myappname”,它将为您提供有关这些类型错误的详细信息。

于 2009-01-11T22:15:11.967 回答