【问题标题】:C passing a linked list struct to a functionC将链表结构传递给函数
【发布时间】:2021-03-17 07:28:17
【问题描述】:

我在 C 中实现了一个链表。

问题是,每当我尝试使用函数print_list(struct linked_list *list) 打印节点数据时,都会出现分段错误。

我不确定是什么原因造成的,因为当我尝试print(struct linked_list *list) 时,它工作正常。

而且,当我尝试动态分配内存时,它也可以正常工作。但我很好奇这样的代码有什么问题?为什么使用print 不会导致同样的错误?

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

struct node{
    char data;
    struct node* next;
};

struct linked_list{
    struct node *head;
};

void concat(struct linked_list* list1, struct linked_list* list2)
{
    struct node* tmp = list1->head;
    
    while(tmp->next != NULL)
        tmp = tmp->next;
    tmp->next = list2->head;
}

void print_list(struct linked_list *list)
{
    struct node* tmp = list->head;
    while(tmp != NULL){
        printf("%c - ", tmp->data);
    tmp = tmp->next;}
    printf("\n");
}

void print(struct linked_list *list)
{
    struct node* tmp = list->head;
    printf("%c\n", tmp->data);
    tmp = tmp->next;
    printf("%c\n", tmp->data);
    tmp = tmp->next;
    printf("%c\n", tmp->data); 
}

int main()
{
    struct linked_list list1,list2;
    struct node n1,n2,n3,n4,n5;
    n1.data = 'A';
    n2.data = 'B';
    n3.data = 'C';
    n4.data = 'D';
    n5.data = 'E';
    n1.next = &n2;
    n2.next = &n3;
    
    n4.next = &n5;
    list1.head = &n1;
    list2.head = &n4;
    printf("List 1 containes :\n");
    print_list(&list1);
    concat(&list1,&list2);
    printf("List 1 after concat: \n" );
    print_list(&list1);

    return 0;
}

【问题讨论】:

  • 我的猜测是列表中的最后一个节点没有NULLas next 链接。您将节点创建为本地数据而不初始化它们,这在 C 中意味着它们具有“垃圾”值。说struct node n1 = {'a'}; 应该可以。 next 字段被隐式初始化为空指针。
  • 我在here 中复制粘贴相同的内容,我没有看到任何段错误。

标签: c struct linked-list segmentation-fault


【解决方案1】:

首先尝试了解segmentation fault是什么。

根据Wikipedia

在计算中,分段错误(通常缩写为 segfault)或访问冲突是由具有内存保护的硬件引发的故障或故障条件,通知操作系统 (OS) 软件已尝试访问受限区域内存(内存访问冲突)。

之所以发生这种情况,是因为您的程序正在访问它不应访问的受限位置。但为什么?因为在while(tmp-&gt;next != NULL) 中,程序完成遍历所有元素后不一定会找到NULL。因此,在这种情况下,循环不会中断,它允许循环继续进行,最终程序会尝试访问受限位置。

为了解决这个问题,请在 node 结构的定义中初始化 node* Next = NULL。喜欢:

struct node{
    char data;
    struct node* next = NULL;
};

现在next 的默认值显式设置为NULL。因此,除非您将其更改为指向另一个节点,否则它仍将保持为NULL。并且问题应该得到解决。

【讨论】:

    【解决方案2】:

    这里:

    struct node n1,n2,n3,n4,n5;
    

    您创建五个节点而不初始化它们。 C 不会将局部变量初始化为 null 或零,因此节点的字段具有不确定(“垃圾”)值。稍后,您初始化了一些字段,但没有初始化列表中最后一个节点的 next 字段。

    有几种解决方案,例如:

    (1) 显式初始化最后一个节点的next字段:

    n1.next = &n2;
    n2.next = &n3;
    n3.next = NULL;
    
    n4.next = &n5;
    n5.next = NULL;
    

    (2)用数据初始化节点,然后设置链接:

    struct node n1 = {'A'};
    struct node n2 = {'B'};
    struct node n3 = {'C'};
    struct node n4 = {'D'};
    struct node n5 = {'E'};
    
    n1.next = &n2;
    n2.next = &n3;
    
    n4.next = &n5;
    

    一旦你初始化了一个结构,所有的字段都会被初始化,即使没有明确给出值(比如next)。根据类型,这些字段用零或 null 隐式初始化。现在您有了有效(但未连接)的节点,然后再设置链接。

    (3) 通过初始化定义一切:

    struct node n5 = {'E', NULL};
    struct node n4 = {'D', &n5};
    struct linked_list list2 = {&n4};
    
    struct node n3 = {'C', NULL};
    struct node n2 = {'B', &n3};
    struct node n1 = {'A', &n2};
    struct linked_list list1 = {&n1};
    

    现在您已准备好列表,但您必须向后定义它,以便在您引用它时知道 next 节点。

    还有其他可能建立一个链表而不在堆上分配内存,例如一个节点数组,但我想你明白了。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-06
      • 1970-01-01
      • 2013-04-12
      • 2015-01-03
      相关资源
      最近更新 更多