1

我正在尝试在 C 中实现二叉搜索树,并在尝试运行我的代码时遇到分段错误。基本上在我的代码中,我从文件中读取一行数据,为其创建一个节点,然后将其插入到我的二叉搜索树中。我什至不确定我对这段代码的实现是否正确,因为我在尝试运行它时遇到了分段错误。我对 C 编程特别是内存分配非常陌生,所以我知道我的代码中可能存在大量错误,即使在代码本身的核心结构中也是如此。因此,任何有助于找到分段错误背后的原因或有助于代码本身的核心结构的任何帮助都将不胜感激。

4

4 回答 4

1

这可能更像是一个评论而不是一个答案,但我没有足够的“声誉”来评论,所以......

正如@Lundin 之前评论的那样,问题与指针的使用有关,而不是与指针有关。

在这一行: *node->left = insertNode(node->left, newNode);

node->left 可以为 NULL。在对 insertNode 的调用中,您检查了这一点并将 newNode 分配给node->left的本地副本,但这对 node->left 没有影响,因此当 insertNode 的返回值被写入 node 指向的位置时-left(NULL),你有一个保证崩溃!

于 2018-08-30T07:34:31.703 回答
0

您正在释放指向您的堆栈的指针:

int main(int argc, char *argv[]) {

bst_t root;                                       <<< root is allocated on stack
bst_t newNode;
int c;

while ((c = getchar()) != EOF){
  newNode = createNode();
  root = insertNode(&root,&newNode);
  }
  freeTree(&root);                                <<< Your are passing a pointer to root ( pointer to a stack element )
  return 0;
}



void freeTree(bst_t *parent){                    <<< parent is a pointer to a stack element
  if(! parent){
    return;
  }
  freeTree(parent->left);
  freeTree(parent->right);
  free(parent);                                  <<< you free a stack element => segmentation fault
}

您要么必须分配根节点,以便它可以被释放,要么处理您的根节点freeTree


编辑:这是 malloc 的语法:

bst_t *root = malloc(sizeof(bst_t));

malloc函数返回一个指向新分配空间的指针,并将分配的大小作为参数。

旁注:如果您想真正干净,malloc可以null在没有可用内存的情况下返回(非常罕见),因此检查返回是一个好习惯。
更多信息

于 2018-08-30T07:22:17.220 回答
0

您的代码中有多个问题:

  • rootmain函数中未初始化。NULL在将其传递给 之前,必须对其进行初始化insertNode()

  • 您应该只解析一行readdata()并返回一个成功指示符。

  • 您应该在main循环中迭代,直到readdata无法从文件中读取更多记录。您当前的测试while ((c = getchar()) != EOF)不合适并损坏了此输入流。

以下是readdatamain函数的修改版本:

bst_t *createNode(void) {
    bst_t *newNode;
    newNode = (struct bst_t *)malloc(sizeof(struct bst_t));
    newNode->left = NULL;
    newNode->right = NULL;
    return newNode;
}

int readData(bst_t *node) {
    return scanf("%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],"
                 "%[^,],%[^,],%[^,],%[^,],%[^,]",
                 node->data.ID, node->data.name, node->data.sex,
                 node->data.height, node->data.weight, node->data.team,
                 node->data.NOC, node->data.games, node->data.year,
                 node->data.season, node->data.city, node->data.sport,
                 node->data.event, node->data.medal) == 14;
}

int main(int argc, char *argv[]) {
    bst_t *root = NULL;
    bst_t *newNode;

    while ((newNode = createNode()) != NULL) {
        if (readData(newNode)) {
            /* record was read correctly: insert into the tree */
            root = insertNode(root, newNode);
        } else {
            /* end of file or input error: stop reading the file */
            free(newNode);
            break;
        }
    }
    freeTree(root);
    return 0;
}
于 2018-08-30T12:46:19.907 回答
0

我相信问题出在readData功能上。当你使用 时scanf,你必须使用地址操作符&来读入变量。

以下代码:

void readData(bst_t *node) {
while (scanf("%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],"
             "%[^,],%[^,],%[^,],%[^,],%[^,]",
             node->data.ID, node->data.name, node->data.sex,
             node->data.height, node->data.weight, node->data.team,
             node->data.NOC, node->data.games, node->data.year,
             node->data.season, node->data.city, node->data.sport,
             node->data.event, node->data.medal) == 14) {
    continue;
}

应改为:

void readData(bst_t *node) {
while (scanf("%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],"
             "%[^,],%[^,],%[^,],%[^,],%[^,]",
             &node->data.ID, &node->data.name, &node->data.sex,
             &node->data.height, &node->data.weight, &node->data.team,
             &node->data.NOC, &node->data.games, &node->data.year,
             &node->data.season, &node->data.city, &node->data.sport,
             &node->data.event, &node->data.medal) == 14) {
    continue;
}

您还应该进行一些修改:
1. 使用指向结构而不是结构的指针传递参数和返回值。
2. 在处理链表时,在堆上而不是在栈上分配内存(即使是根节点)。
3. 在堆上分配内存时,确保分配的大小是结构体的大小,而不是结构体指针的大小。
4. 确保释放在堆上分配的所有内存,并且不要像您在这里所做的那样错误地释放在堆栈上分配的内存。

于 2018-08-30T09:04:52.407 回答