通过链表进行迭代会导致分段错误

时间:2012-06-04 19:39:37

标签: c list

我刚写了一个简单的链表,但是当通过add()display()遍历列表时,程序会出错。

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

typedef struct entry {
    void *value;
    struct entry *next;
} entry;

typedef struct list {
    entry *items;
} list;

list *create(void) {
    list *l;

    l = malloc (sizeof(list));
    l->items = malloc(sizeof(entry*));
    l->items->next = NULL;

    return l;
}

void add(list *l, void *value) {
    entry *temp, *last, *new;

    for (temp = l->items; temp != NULL; temp = temp->next) {
        last = temp;
    }

    new = malloc(sizeof(*new));

    new->value = value;
    new->next = NULL;

    last->next = new;
}

void display(list *l) {
    entry *temp;

    for (temp = l->items; temp != NULL; temp = temp->next) {
        printf("%s\n", temp->value);
    }
}

int main(void) {
    list *l = create();

    add(l, "item1");
    add(l, "item2");
    add(l, "item3");
    add(l, "item4");

    display(l);

    return 0;
}

我已经在一些机器上测试了代码,但是它可以在少数机器上运行而在其他机器上运行。我对错误的来源一无所知。

4 个答案:

答案 0 :(得分:6)

这没有分配足够的空间:

l->items = malloc(sizeof(entry*));

它应该是sizeof(entry),或者如果您想要遵循您在其他地方使用的模式:

l->items = malloc(sizeof(*l->items));

结果,你现在正在践踏记忆。

答案 1 :(得分:3)

除了传递给FatalError提到的malloc的错误大小外,您还为l->items分配了内存

list *create(void) {
    list *l;

    l = malloc (sizeof(list));
    l->items = malloc(sizeof(entry*));
    l->items->next = NULL;

    return l;
}

但是不要将l->items->value设置为任何内容,因此它是一个未初始化的指针,当您尝试在打印时取消引用它

void display(list *l) {
    entry *temp;

    for (temp = l->items; temp != NULL; temp = temp->next) {
        printf("%s\n", temp->value);
    }
}

在循环的第一次迭代中,即使分配大小不足也不会导致一个段错误,很容易导致段错误。

答案 2 :(得分:2)

FatalError已经发现问题并发布了一个解决方案。我想补充说,比询问这样一个特定问题更好的方法是调试你的代码。

valgrind是一个Linux工具,允许调试内存管理。您需要做的就是在应用程序中运行该工具,并查看其输出中的错误。

如果您使用“./myapp”运行应用程序,则只需运行:

# valgrind -v --leak-check=full --show-reachable=yes ./myapp

答案 3 :(得分:0)

要证明你不需要列表结构,因为它只带有一个“head”指针(我将原始条目重命名为llist,最后删除了列表和typedef):

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

struct llist {
    char *value;
    struct llist *next;
};

void add(struct llist **ll, void *value) {

      /* find the end of the list;
      ** keeping a pointer to the (final NULL) pointer.
      ** If this function is called with the first argument pointing to
      ** a NULL pointer (the empty list),
      ** this loop will iterate zero times.
      */
    for ( ; *ll != NULL; ll = &(*ll)->next) {;}

    *ll = malloc(sizeof(**ll));

    (*ll)->value = value;
    (*ll)->next = NULL;

}

void display(struct llist *l) {

    for (; l != NULL; l = l->next) {
        printf("%s\n", l->value);
    }
}

int main(void) {
    struct llist *l = NULL;

    add(&l, "item1");
    add(&l, "item2");
    add(&l, "item3");
    add(&l, "item4");

    display(l);

    return 0;
}