Segfault от добавления переменной - PullRequest
2 голосов
/ 12 января 2009

По общему признанию, я новичок в классе 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

Почему добавление определения переменной может вызвать ошибку? Похоже, что он разбивает указатель содержимого недавно созданного узла. Я не совсем понимаю; любая помощь?

Ответы [ 3 ]

15 голосов
/ 12 января 2009

Вам необходимо динамически распределить ваши узлы (используя malloc).

Как только он у вас есть, ваш новый узел объявлен в стеке. Когда функция split возвращается, этот новый узел больше не является действительной памятью.

Добавление переменной вызывает segfault, поскольку эта переменная меняет структуру стека, вызывая немного другое поведение при возврате функции.

0 голосов
/ 12 января 2009

Valgrind - отличный инструмент для поиска подобных проблем. Вы можете просто выполнить «valgrind myappname» из командной строки, и он предоставит вам подробную информацию об этих типах ошибок.

0 голосов
/ 12 января 2009

Попробуйте установить для свойства Nodes child значение NULL, C не обнуляет память автоматически, поэтому похоже, что у вас может быть мусор в потомке (или вы можете использовать calloc вместо malloc). Ответ SoapBox также правильный.

...