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

链表结构体中数组内存释放问题:double free错误排查

链表内存释放崩溃问题分析与解决

问题现象

  • 不调用dumpGroupingOrder()函数时,程序可正常运行,但存在内存泄漏,Valgrind检测结果:

LEAK SUMMARY:
definitely lost: 48 bytes in 1 blocks
indirectly lost: 328 bytes in 11 blocks

  • 调用该函数后,无内存泄漏,但程序崩溃,报错double free or corruption (out),Valgrind给出的错误信息:

Invalid free() / delete / delete[] / realloc()
at 0x48399AB: free (vg_replace_malloc.c:538)
by 0x10929A: dumpGroupingOrder (code-stack.c:54)
by 0x10952F: main (code-stack.c:88)
Address 0x1fff0000b0 is on thread 1's stack
in frame #2, created by main (code-stack.c:74)

完整可复现代码

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


struct groupingOrder {
  int *taxa;
  size_t groupeSize;
  long double distance;
  struct groupingOrder* next;
};


void addGroup( struct groupingOrder* HEAD, int * groupe, size_t groupeSize, long double distance ) {

  struct groupingOrder* temp = HEAD;
  // Moving the last unit structure
  while( temp->next != NULL ) {
    temp = temp->next;
  }
  // Allocating space for the unit structure
  struct groupingOrder* nouveau = malloc( sizeof( struct groupingOrder ) );
  nouveau->distance = distance;
  nouveau->groupeSize = groupeSize;
  // Allocating variable space for the list of taxa to be stored
  nouveau->taxa = malloc( groupeSize * sizeof( int ) );
  for( int i = 0; i < groupeSize; i++) {
    nouveau->taxa[i] = groupe[i];
  }
  // Linking the new unit structure to the previous one
  temp->next = nouveau;
  // Specifying the NULL pointer to label the last unit
  nouveau->next = NULL;
}


void dumpGroupingOrder( struct groupingOrder* HEAD ) {

  struct groupingOrder* temp = HEAD;
  while( temp != NULL ) {

    // Copying the address of the current unit
    struct groupingOrder* dumpTarget = temp;
    // Storing the address of the next unit before dumping the
    //  current one.
    temp = temp->next;

    // Dumping the current unit and all its allocated variables
    if( dumpTarget->taxa != NULL ) {
      free( dumpTarget->taxa );
      printf( " #" );
    }
    free( dumpTarget );
    printf( "* " );
  }
}


void showGroupingOrder( struct groupingOrder* HEAD ) {

  struct groupingOrder* temp = HEAD;
  while( temp->next != NULL ) {
    temp = temp->next;
    for( int i = 0; i < temp->groupeSize; i++) {
      printf( " %d", temp->taxa[i] );
    }
    printf( " %Lf\n", temp->distance );
  }
}



int main() {
  
  size_t groupeSize[6] = { 2,2,4,2,5,7 };
  int groupes[][7] = { {2,3}, {5,1}, {2,3,5,1}, {7,4}, {2,3,5,1,6}, {2,3,5,1,6,7,4} };

  struct groupingOrder HEAD = { .next = NULL };
  
  for( int i = 0; i < 6; i++ ){

    addGroup( &HEAD, groupes[i], groupeSize[i], 0.0003 );
  }

  showGroupingOrder( &HEAD );
  printf( "\n\n" );
  dumpGroupingOrder( &HEAD );
  
  return 0;
}

问题根源

main函数中的HEAD节点是栈上分配的变量(struct groupingOrder HEAD = { .next = NULL };),而dumpGroupingOrder()函数从HEAD开始遍历,最终会执行free(dumpTarget)来释放HEAD本身——栈内存不属于堆内存范畴,不能用free()释放,这直接触发了内存错误。

修复方案

修改dumpGroupingOrder()函数,从HEAD->next开始遍历释放,只释放链表中通过malloc分配的节点,跳过栈上的HEAD节点:

void dumpGroupingOrder( struct groupingOrder* HEAD ) {

  // 从第一个堆分配的节点开始,跳过栈上的HEAD
  struct groupingOrder* temp = HEAD->next;
  while( temp != NULL ) {

    struct groupingOrder* dumpTarget = temp;
    temp = temp->next;

    if( dumpTarget->taxa != NULL ) {
      free( dumpTarget->taxa );
      printf( " #" );
    }
    free( dumpTarget );
    printf( "* " );
  }
  // 可选:将HEAD的next置为NULL,避免野指针
  HEAD->next = NULL;
}

验证结果

修改后程序运行无崩溃,Valgrind检测无内存泄漏,也不再出现double free错误。

内容的提问来源于stack exchange,提问作者Goëtay

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 23:00:47