如何正确释放含动态字符串的嵌套链表动态分配内存?
内存释放崩溃问题排查与修复
在嵌套链表存储球队信息的项目中,程序运行正常但调用内存释放函数时崩溃,经调试发现问题出在字符串内存释放步骤。以下是问题排查与修复方案:
数据结构定义
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; }
崩溃核心原因
- 字符串内存分配不足:所有字符串分配时仅按
strlen(buf)分配,未给字符串终止符\0预留空间,导致strcpy写入越界,破坏堆内存结构,后续释放时触发崩溃。 - 语法/拼写错误:
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(¤t->team->team_members); // 释放球队名称字符串 free(current->team->TeamName); // 释放球队节点 free(current->team); // 释放链表节点 free(current); current = next; } *head = NULL; }
验证说明
修复后,字符串分配预留了终止符空间,所有语法/拼写错误修正,堆内存结构不再被破坏,此时调用delete_list即可正常释放所有动态分配的内存,不会出现崩溃。
内容的提问来源于stack exchange,提问作者AnghelutaVlad
相关产品推荐
相关产品推荐

