C代码创建链表分割错误

时间:2020-04-30 00:38:23

标签: c linked-list segmentation-fault

好吧,所以对于我的家庭作业,我有一个函数可以从文件输入中创建一个链表,就像日历一样,因此它可以从文件中读取日期和标题。我使用的是全局声明的头节点 更易于使用其他功能。
这是我的节点结构:

typedef struct event_t{  
    char title[20];  
    event_date_t date;  
    struct event_t *next;  
}event_t;

event_date_t只是日期的简单结构 功能如下:

void insert_events_linked_list(FILE *file, int n){
    //printf("LL function started\n"); //self-explanatory test line
    event_t last;
    head.next = &last;
    int i;
    //This loop will create a ll of the specified length
    for(i=0; i<n; i++){
        event_t *last = malloc(sizeof(event_t));
        int title_test = fscanf(file, "%20s%*c", last->title);
        printf("%s\n", last->title); //test line to make sure names are grabbed properly
        //This skips the rest of the event and prints error message if title is too long
        if(title_test != 1){
            fscanf(file, "%*s %*d %*d");
            printf("Error: LL event %d title too long\n", i++);
            continue;
        }
        else{
            fscanf(file, "%d %d", &last->date.month, &last->date.day);
            last = last->next;
        }
    }
    printf("Loop exited");
}

测试行将打印所有标题,但显示分段错误并在打印“退出循环”之前中止

2 个答案:

答案 0 :(得分:0)

这行代码,

event_t *last = malloc(sizeof(event_t));
每次last循环返回时,

都会声明一个全新的for。将其声明为static并相应地调整您的代码,这样就不会有任何问题了。

演示

for (i=0;i<5;i++){
    int x=6;
    x++;
    printf("%d ",x);
}

输出

7 7 7 7 7

您应该看到问题了。

答案 1 :(得分:0)

测试行将打印所有标题,但显示分段错误并在打印“退出循环”之前中止

程序中有很多错误。您应该阅读this post。您还应该学习使用调试器。

我怀疑未打印Loop exited的原因是您没有用换行符终止它,所以printf正在等待您完成一行或致电fflush 。默认情况下,printf输出是 line 缓冲的。这就是您应该始终始终使用fprintf(stderr, ...)的原因之一。 stderr(默认情况下)是无缓冲的。

关于错误。

  1. 在同一个作用域中有两个名为last的变量。这几乎从来不是一个好主意。
  2. 此语句:

    head.next = &last;

    local 变量的地址分配给 global head指针。当前函数返回后,该地址将变为无效,这几乎肯定不是您想要的。特别是,head.next 从不指向循环中您malloc的任何内存(并且泄漏!)。

  3. 您的循环看起来像这样:

    for (...) {
      event_t *last = malloc(sizeof(event_t));  // last->next is uninitialized
      ...
      last = last->next;  // leak the memory allocated above 
                          // by overwriting the pointer with garbage
    }
    

    那显然也不是你想要的。

这是一种逐步建立链表的方法:

   event_t **link = &head.next;

   for (...) {
     event_t *ev = calloc(...);  // Initializes ev->next to NULL.

     // Fill the rest of ev ...

     // Link it into the list:
     *link = ev;
     link = &ev->next;
   }