【问题标题】:how to stop cycle that creates a linked list to create one more empty link?如何停止创建链表的循环以再创建一个空链接?
【发布时间】:2021-09-02 14:35:00
【问题描述】:
struct data {
  int date;
  int temperature;
  char day[11];
  struct data *next;
}; 
typedef struct data Data;

int from_file_to_list(File *fp, Data **list) {
  Data *p;
  int cnt = 0;
  *list = p;
  p = malloc(sizeof(Data));
  while (fscanf(fp, "%d" "%s" "%d", &(p->date), p->day, &(p->temperature)) == 3) {
    p->next =  malloc(sizeof(Data));
    p = p->next;
    cnt++;
  }
  return cnt;
}

我有这个函数,它用文本文件的数据创建一个链表,它返回列表中的链接数,它工作正常,但它在最后为一个额外的空链接分配内存,有没有有办法阻止吗?因为如果我有一个最终添加链接的功能,可能会有问题吗?

【问题讨论】:

    标签: c while-loop linked-list singly-linked-list function-definition


    【解决方案1】:

    对于初学者来说,似乎有一个错字

    int from_file_to_list(File *fp, Data **list) {
                          ^^^^
    

    应该有

    int from_file_to_list(FILE *fp, Data **list) {
                          ^^^^
    

    我有这个函数可以创建一个包含数据的链表 文本文件,它返回列表中的链接数,它可以工作 很好,

    你错了。该函数具有未定义的行为。在此声明中

    int from_file_to_list(File *fp, Data **list) {
      Data *p;
      int cnt = 0;
      *list = p;
      //.. 
    

    您将未初始化的指针 p 分配给了指针 *list。也就是退出函数后main中的指针list会有这个不确定的值。

    函数至少可以定义如下方式

    #include <stdlib.h>
    #include <string.h>
    
    //... 
    
    size_t from_file_to_list( FILE *fp, Data **list ) 
    {
        size_t cnt = 0;
    
        int date;
        int temperature;
        char day[11];
        
        while ( fscanf( fp, "%d" "%s" "%d", &date, day, &temperature ) == 3 && 
                ( *list = malloc( sizeof( Data ) ) ) != NULL ) 
        {
            ( *list )->date = date;
            ( *list )->temperature = temperature;
            strcpy( ( *list )->day, day );
            ( *list )->next = NULL;
            
            list = &( *list )->next;
            ++cnt;
        }
        
        return cnt;
    }
    

    或者在从文件创建新列表之前释放列表会更好

    size_t from_file_to_list( FILE *fp, Data **list ) 
    {
        while ( *list )
        {
            Data *tmp = *list;
            *list = ( *list )->next;
            free( tmp );
        }
        
        size_t cnt = 0;
    
        int date;
        int temperature;
        char day[11];
        
        while ( fscanf( fp, "%d" "%s" "%d", &date, day, &temperature ) == 3 && 
                ( *list = malloc( sizeof( Data ) ) ) != NULL ) 
        {
            ( *list )->date = date;
            ( *list )->temperature = temperature;
            strcpy( ( *list )->day, day );
            ( *list )->next = NULL;
            
            list = &( *list )->next;
            ++cnt;
        }
        
        return cnt;
    }
    

    如果您将编写一个单独的函数来清除列表,例如

    void clear( Data **list )
    {
        while ( *list )
        {
            Data *tmp = *list;
            *list = ( *list )->next;
            free( tmp );
        }
    }    
    

    那么上面的函数可以这样写

    size_t from_file_to_list( FILE *fp, Data **list ) 
    {
        clear ( list );
        
        size_t cnt = 0;
    
        int date;
        int temperature;
        char day[11];
        
        while ( fscanf( fp, "%d" "%s" "%d", &date, day, &temperature ) == 3 && 
                ( *list = malloc( sizeof( Data ) ) ) != NULL ) 
        {
            ( *list )->date = date;
            ( *list )->temperature = temperature;
            strcpy( ( *list )->day, day );
            ( *list )->next = NULL;
            
            list = &( *list )->next;
            ++cnt;
        }
        
        return cnt;
    }
    

    【讨论】:

    • 非常感谢。一切都很清楚,但我不明白list = &amp;( *list )-&gt;next; 是如何工作的
    • @Skelemen 您通过指向它的指针通过引用将指针列表传递给函数,不是吗?因此,在函数中取消引用指向 *list 等指针的指针,您可以直接访问 main 中声明的原始指针列表。现在在这个语句之后 list = &( *list )->next;指向指针列表的指针指向当前节点的下一个指针(数据成员),您可以更改此指针,就像您通过指向它的指针更改 main 中声明的原始指针列表一样。
    • 非常感谢,我从来没有想过像这样使用那个指针,它太聪明了。
    【解决方案2】:

    您正在设置 *list = p; 之前 p 已设置,因此您有 UB(未定义的行为)。

    修复后,您的代码将不会正确处理空列表。

    最好将值读入temp 变量并仅在存在有效数据行时才执行malloc

    不要为 next 记录执行malloc。在文件的最后一行,你会有一个extra struct 分配。

    这是一些重构的代码。它是注释的。我已经编译它但没有测试它:

    #include <stdio.h>
    #include <stdlib.h>
    
    struct data {
        int date;
        int temperature;
        char day[11];
        struct data *next;
    };
    typedef struct data Data;
    
    int
    from_file_to_list(FILE *fp, Data **list)
    {
        Data temp;
        Data *prev;
        Data *cur;
        int cnt = 0;
    
        // make the list empty
        *list = NULL;
    
        prev = NULL;
    
        // loop on all lines/records in the file
        while (fscanf(fp, "%d" "%s" "%d",
            &temp.date, temp.day, &temp.temperature) == 3) {
    
            // allocate new record
            cur = malloc(sizeof(*cur));
    
            // copy in the data we just read
            *cur = temp;
    
            // append to non-empty list
            if (prev != NULL)
                prev->next = cur;
    
            // the first record
            else
                *list = cur;
    
            // remember the previous record
            prev = cur;
    
            // advance the count of number of records
            cnt++;
        }
    
        return cnt;
    }
    

    【讨论】:

      猜你喜欢
      • 2015-06-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多