分段错误测试链表

分享于2023年02月08日 c function-definition linked-list segmentation-fault 问答
【问题标题】:segmentation fault testing linked list分段错误测试链表
【发布时间】:2023-02-07 23:56:49
【问题描述】:

我正在尝试在 C 中构建和测试链表。但我似乎无法弄清楚为什么我在运行测试 (test_linked_list.c) 时会出现分段错误。问题似乎出在运行 gdb 时的 list_delete 函数,但我找不到问题出在哪里。为什么这是错误的?

链表.c

#include 
#include 
#include "linked_list.h"

void list_init(list_t *h) {
    *h = NULL;
}

int list_size(const list_t *h) {
    node_t *p = *h;
    int r = 0;
    do {
        r += 1;
        p = p->next;
    } while (p);
    return r;
}

int list_empty(const list_t *h) {
    return (*h == NULL);
}

void list_insert(list_t *h, node_t *n) {
    n->next = *h;
    *h = n;
}

node_t *list_find(const list_t *h, int id) {
    node_t *p = *h;
    while (p) {
        if (p->id == id) return p;
        p = p->next;
    }
}

node_t *list_find_before(const list_t *h, int id) {
    node_t *p = *h;
    while (p && p->next) {
        if (p->next->id == id) return p;
        p = p->next;
    }
    return NULL;
}

node_t *list_delete(list_t *h, int id) {
    node_t *r = NULL;
    if (*h && (*h)->id == id) {
        r = *h;
        *h = NULL;
        return r;
    }
    // Here we have a syntax bug
    node_t *p = list_find_before(h, id);
    if (p) {
        r = p->next;
        p->next = p->next->next;
        r->next = NULL; 
    }
    return r;
}

void print_list(const list_t *h) {
    node_t *p = *h;
    while (p) {
        printf("%d: %s says %s\n", p->id, p->name, p->msg);
        p = p->next;
    }
}

test_linked_list.c

#include 
#include "linked_list.h"
#include 
#include 
#include 


void test_delete_one() {
    list_t h;
    list_init(&h);
    node_t n;
    n.id = 0;
    strcpy(n.name, "hello");
    strcpy(n.msg, "world");
    list_insert(&h, &n);
    node_t *f = list_delete(&h, 0);
    assert(f == &n);
}


void test_delete() {
    list_t h;
    list_init(&h);
    node_t n[3];
    int i;
    for (i = 0; i < 3; i++) {
        n[i].id = i;
        list_insert(&h, &n[i]);
    }
    list_delete(&h, 1);
    assert(list_size(&h) == 2);
}

void core_dump_test() {
    int size = 0;
    list_t h;
    list_init(&h);
    size = list_size(&h);   
    printf("list size is: %d\n", size);
}

int main () {
    test_delete();
    test_delete_one();
    core_dump_test();
    printf("Pass\n");
}

  • 请尝试创建一个 minimal reproducible example 给我们看。并请使用 debugger 捕捉崩溃并查看在何处 你的 代码它发生了。
  • 作为提示:在 core_dump_test 中, h 在您调用 list_init(&h) 之后指向哪里? list_size 取消引用这个指针吗?
  • 我担心丢失的重新分配,然后我注意到也没有一个分配。请发布 minimal reproducible example

【解决方案1】:

有几个函数是错误的。

例如 list_size

int list_size(const list_t *h) {
    node_t *p = *h;
    int r = 0;
    do {
        r += 1;
        p = p->next;
    } while (p);
    return r;
}

可以为空列表调用未定义的行为。

或者另一个例子。函数 list_find

node_t *list_find(const list_t *h, int id) {
    node_t *p = *h;
    while (p) {
        if (p->id == id) return p;
        p = p->next;
    }
}

如果在列表中找不到指定值,则不返回任何内容。

或者函数 list_find_before

node_t *list_find_before(const list_t *h, int id) {
    node_t *p = *h;
    while (p && p->next) {
        if (p->next->id == id) return p;
        p = p->next;
    }
 
   return NULL;
}

忽略列表的第一个节点。

等等。

至于函数 list_delete ,即使在开始时它也有一个错误设置 *h NULL

node_t *list_delete(list_t *h, int id) {
    node_t *r = NULL;
    if (*h && (*h)->id == id) {
        r = *h;
        *h = NULL;
        return r;
    }
    //...

注意节点必须是动态分配的。否则你的清单没有意义。

【讨论】: