You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

将char*赋值给void*字段后,链表队列存文件行重复问题求助

问题与解决方法

问题描述

编写读取文件行并存储到链表队列的程序,队列节点包含void*类型的data字段。打印存储的所有行时,程序重复输出最后读取的行,重复次数等于文件行数。推测原因是每次向节点传递的都是同一指针,读取新行时指针指向的内容被覆盖,求解决办法。

相关代码

文件读取函数

void* readfile(void* arg){
   FILE* fp;
   fp = fopen((char*)arg, "r");
   if(fp==NULL){
      fprintf(stderr, "Error opening file %s\n", (char*)arg);
      exit(EXIT_FAILURE);
   }

   char* line= malloc(sizeof(char)*BUFSIZE); // #define BUFSIZE 1024

   while(fgets(line, BUFSIZE, fp)!=NULL){
      insert_tail(deque_12, (void*)line);
   }
   puts("File read");
   fclose(fp);
   return NULL; 
}

队列结构与实现(deque.h)

typedef struct node{
   void* data;
    struct node *next;
    struct node *prev;
}Node_t;

typedef struct deque{
   Node_t *head;
   Node_t *tail;
}Deque_t;

void insert_tail(Deque_t* d, void* data){

   Node_t *newNode = malloc(sizeof(Node_t*));

   newNode->data = data;
   newNode->next = NULL;

   if(d->head == NULL){
      newNode->prev = NULL;
      d->head = newNode;
   }
   else{
      newNode->prev = d->tail;
      d->tail->next = newNode;
   }
   d->tail = newNode;
}

解决办法

你的推测完全正确:所有节点的data字段都指向同一块内存(line指针指向的缓冲区),每次fgets都会覆盖这块内存的内容,最终所有节点都指向最后一行的内容。此外,代码里还有一个隐藏问题:insert_tail中malloc(sizeof(Node_t*))分配的内存大小错误,应该是malloc(sizeof(Node_t)),否则会因内存不足导致未定义行为。

具体修改步骤

  1. 为每行内容分配独立内存:每次读取一行后,复制该行内容到新分配的内存中,再将新内存的指针传入队列。
  2. 修复节点内存分配错误:将malloc(sizeof(Node_t*))改为malloc(sizeof(Node_t))。

修改后的代码示例

修改后的readfile函数

void* readfile(void* arg){
   FILE* fp;
   fp = fopen((char*)arg, "r");
   if(fp==NULL){
      fprintf(stderr, "Error opening file %s\n", (char*)arg);
      exit(EXIT_FAILURE);
   }

   char line[BUFSIZE]; // 用栈缓冲区替代堆分配,减少内存管理开销
   while(fgets(line, BUFSIZE, fp)!=NULL){
       // 为当前行分配内存并复制内容
       char* line_copy = malloc(strlen(line) + 1);
       if(line_copy == NULL){
           fprintf(stderr, "Memory allocation failed\n");
           exit(EXIT_FAILURE);
       }
       strcpy(line_copy, line);
       insert_tail(deque_12, (void*)line_copy);
   }
   puts("File read");
   fclose(fp);
   return NULL; 
}

修改后的insert_tail函数

void insert_tail(Deque_t* d, void* data){
   // 分配Node_t结构体大小的内存,而非指针大小
   Node_t *newNode = malloc(sizeof(Node_t));
   if(newNode == NULL){
       fprintf(stderr, "Memory allocation for node failed\n");
       exit(EXIT_FAILURE);
   }

   newNode->data = data;
   newNode->next = NULL;

   if(d->head == NULL){
      newNode->prev = NULL;
      d->head = newNode;
   }
   else{
      newNode->prev = d->tail;
      d->tail->next = newNode;
   }
   d->tail = newNode;
}

注意事项

  • 后续释放队列节点时,需要先释放data指向的内存,再释放节点本身,避免内存泄漏。
  • 若文件行长度超过BUFSIZE,fgets会截断行内容,可根据需求调整BUFSIZE或实现动态扩容的行读取逻辑。

内容的提问来源于stack exchange,提问作者DravStart

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 15:52:46