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

如何正确释放含动态字符串的嵌套链表动态分配内存?

内存释放崩溃问题排查与修复

在嵌套链表存储球队信息的项目中,程序运行正常但调用内存释放函数时崩溃,经调试发现问题出在字符串内存释放步骤。以下是问题排查与修复方案:

数据结构定义

struct player{
                 char* firstName;
                 char* secondName;
                 int score;
                 struct player* next;
              };
typedef struct player Player;
typedef struct {
                 int nr_of_members;
                 char* TeamName;
                 Player* team_members;
                 float teamscore;
             }Node_team;
struct teamlist{
                      Node_team* team;
                      struct teamlist* next;
                   };
typedef struct teamlist Teamlist;

原内存释放实现

void delete_players(Player** head)
{
    Player* p=(*head);
    while(p!=NULL)
    {
        (*head)=(*head)->next;
        free(p->firstName);
        p->firstName=NULL;
        free(p->secondName);
        p->secondName=NULL;
        free(p);
        p=NULL;
        p=(*head);
    }
    (*head)=NULL;
    return;
}
void delete_list(Teamlist** head)
{
    Teamlist* p=(*head);
    while(p!=NULL)
    {
          (*head)=(*head)->next;
          delete_players(&(p->team->team_members));
          free(p->team->TeamName);
          p->team->TeamName=NULL;
          free(p->team);
          p->team=NULL;
          free(p);
          p=NULL;
          p=(*head);
    }
    (*head)=NULL;
    return;
}

原内存分配与文件读取代码(含语法/拼写错误)

void add_player_at_end(FILE* f,Player** head)
{
    Player* newnode=(Player*)malloc(sizeof(Player)),*p;
    char buf[50];
    fscanf(f,"%s",buf);
    newnode->firstName=(char*)malloc(strlen(buf)*sizeof(char));
    strcpy(newnode->firstName,buf);
    fscanf(f,"%s",buf);
    newnode->secondName=(char*)malloc(strlen(buf)*sizeof(char));
    strcpy(newnode->secondName,buf);
    fscanf(f,"%d",&(newnode->score));
    newnode->next=NULL;
    if((*head)==NULL)
        (*head)=newnode;
    else
    {
        p=(*head);
        while((p->next)!=NULL)
            p=p->next;
        p->next=newnode;
    }
    return;
}
Node_team* createNode(FILE* f)
{
     char buf[50];
     int total=0;
     Nod_echipa* newnode=(Nod_echipa*)malloc(sizeof(Nod_echipa));
     Player* p;
     fscanf(f,"%d",&(newnode->nr_of_members));
     fgetc(f);
     fgets(buf,50,f);
     buf[strcspn(buf,"\n")]=0;
     newnode->TeamName=(char*)malloc((strlen(buf))*sizeof(char));
     if(newnode->TeamName==NULL)
        printf("alocare esuata");
     strcpy(newnode->TeamName,buf);
     newnode->team_members=NULL;
     for(int i=0;i<newnode->nr_of_members;i++)
        {
            add_player_at_end(f,&(newnode->team_members));
        }
     p=newnode->team_members;
     while(p!=NULL)
     {
         total+=p->score;
         p=p->next;
     }
     newnode->teamscore=(float)punctaj/(newnode->nr_of_members);
     return newnode;
}
void push(Teamlist** top,Node_team* Team)
{
    Teamlist* newnode=(Lista_de_echipe*)malloc(sizeof(Lista_de_echipe));
    if(newnode==NULL)
    {
        printf("alocare esuata\n");
        exit(1);
    }
    newnode->=Team;
    newnode->next=(*top);
    (*top)=newnode;
    return;
}
Teamlist* read_file(int* nr_of_teams,FILE* f)
{
    Teamlist* head=NULL;
    Node_team* Team;
    fscanf(f,"%d",nr_echipe);
    for(int i=0;i<(*nr_of_teams);i++)
    {
        Team=createNode(f);
        push(&head,Team);
    }
    fclose(f);
    return head;
}

崩溃核心原因

  1. 字符串内存分配不足:所有字符串分配时仅按strlen(buf)分配,未给字符串终止符\0预留空间,导致strcpy写入越界,破坏堆内存结构,后续释放时触发崩溃。
  2. 语法/拼写错误:
    • createNode中使用未定义的Nod_echipa(应为Node_team)、punctaj(应为total)
    • push中存在语法错误newnode->=Team(应为newnode->team = Team),且错误使用Lista_de_echipe(应为Teamlist)
    • read_file中使用未定义的nr_echipe(应为nr_of_teams)
      这些错误会导致内存分配异常、指针赋值错误,间接引发释放时的非法内存访问。

修复后的完整代码

修复后的内存分配与文件读取代码

void add_player_at_end(FILE* f, Player** head)
{
    Player* newnode = (Player*)malloc(sizeof(Player));
    Player* p;
    char buf[50];

    fscanf(f, "%s", buf);
    // 为字符串终止符预留空间
    newnode->firstName = (char*)malloc(strlen(buf) + 1);
    strcpy(newnode->firstName, buf);

    fscanf(f, "%s", buf);
    newnode->secondName = (char*)malloc(strlen(buf) + 1);
    strcpy(newnode->secondName, buf);

    fscanf(f, "%d", &(newnode->score));
    newnode->next = NULL;

    if ((*head) == NULL)
        (*head) = newnode;
    else
    {
        p = (*head);
        while (p->next != NULL)
            p = p->next;
        p->next = newnode;
    }
}

Node_team* createNode(FILE* f)
{
    char buf[50];
    int total = 0;
    // 修正类型名错误
    Node_team* newnode = (Node_team*)malloc(sizeof(Node_team));
    Player* p;

    fscanf(f, "%d", &(newnode->nr_of_members));
    fgetc(f); // 跳过换行符
    fgets(buf, 50, f);
    buf[strcspn(buf, "\n")] = 0;

    // 为字符串终止符预留空间
    newnode->TeamName = (char*)malloc(strlen(buf) + 1);
    if (newnode->TeamName == NULL)
        printf("alocare esuata");
    strcpy(newnode->TeamName, buf);

    newnode->team_members = NULL;
    for (int i = 0; i < newnode->nr_of_members; i++)
    {
        add_player_at_end(f, &(newnode->team_members));
    }

    // 计算球队总分
    p = newnode->team_members;
    while (p != NULL)
    {
        total += p->score;
        p = p->next;
    }
    // 修正变量名错误
    newnode->teamscore = (float)total / newnode->nr_of_members;

    return newnode;
}

void push(Teamlist** top, Node_team* Team)
{
    // 修正类型名错误
    Teamlist* newnode = (Teamlist*)malloc(sizeof(Teamlist));
    if (newnode == NULL)
    {
        printf("alocare esuata\n");
        exit(1);
    }
    // 修正语法错误
    newnode->team = Team;
    newnode->next = (*top);
    (*top) = newnode;
}

Teamlist* read_file(int* nr_of_teams, FILE* f)
{
    Teamlist* head = NULL;
    Node_team* Team;
    // 修正变量名错误
    fscanf(f, "%d", nr_of_teams);

    for (int i = 0; i < (*nr_of_teams); i++)
    {
        Team = createNode(f);
        push(&head, Team);
    }

    fclose(f);
    return head;
}

优化后的内存释放代码(原逻辑正确,仅提升可读性)

void delete_players(Player** head)
{
    Player* current = *head;
    while (current != NULL)
    {
        Player* next = current->next;
        // 释放球员名字字符串
        free(current->firstName);
        free(current->secondName);
        // 释放球员节点
        free(current);
        current = next;
    }
    *head = NULL;
}

void delete_list(Teamlist** head)
{
    Teamlist* current = *head;
    while (current != NULL)
    {
        Teamlist* next = current->next;
        // 释放球队的球员子链表
        delete_players(&current->team->team_members);
        // 释放球队名称字符串
        free(current->team->TeamName);
        // 释放球队节点
        free(current->team);
        // 释放链表节点
        free(current);
        current = next;
    }
    *head = NULL;
}

验证说明

修复后,字符串分配预留了终止符空间,所有语法/拼写错误修正,堆内存结构不再被破坏,此时调用delete_list即可正常释放所有动态分配的内存,不会出现崩溃。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 05:07:06