我当然是一个直接的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
为什么添加变量定义会导致段错误?它似乎粉碎了新创建的节点的内容指针。我糊涂了;有什么帮助吗?
答案 0 :(得分:15)
您需要动态分配节点(使用malloc)。
如上所述,您的新节点在堆栈中声明。当split函数返回时,该新节点不再是有效的内存。
添加变量会导致段错误,因为该变量会更改堆栈的布局,从而导致函数返回时的行为略有不同。
答案 1 :(得分:0)
尝试将Nodes子属性设置为NULL,C不会自动将内存清零,因此看起来您可能在子级中有垃圾(或者您可以使用calloc而不是malloc)。 SoapBox的答案也是正确的。
答案 2 :(得分:0)
Valgrind是帮助查找这类问题的绝佳工具。您可以从命令行执行“valgrind myappname”,它将为您提供有关这些类型错误的详细信息。