C++内存分配异常排查:循环中malloc错误与段故障问题
问题分析与修复
核心问题
你的代码存在野指针访问和错误内存管理问题,处理大文件时多次触发非法内存操作,导致malloc错误或段错误:
- 创建新Artist/Album并插入map后立刻执行
delete,导致map中保存的指针变成野指针,后续循环访问时触发非法内存操作。 curSong实例从未被添加到任何Album的songs集合中,直接delete属于无效操作,同时缺失核心逻辑。- 小文件操作次数少,野指针访问可能未触发崩溃,但大文件中多次重复操作后必然触发错误。
修复后的代码
#include <string> #include <vector> #include <list> #include <cmath> #include <algorithm> #include <map> #include <set> #include <iostream> #include <cstdio> #include <cstdlib> #include <fstream> using namespace std; class Song { public: string title; int time; int track; }; class Album { public: map<int, Song *> songs; string name; int time; }; class Artist { public: map<string, Album *> albums; string name; int time; int nsongs; }; int stringToInt(string s) { int i = 0; i += ((s.c_str())[0] - '0') * 60; i += ((s.c_str())[2] - '0') * 10; i += ((s.c_str())[3] - '0'); return i; } string intToString(int i) { string s; int m, s1, s2; char mc, s1c, s2c; m = i / 60; i -= m * 60; s1 = i / 10; i -= s1 * 10; s2 = i; mc = m + '0'; s1c = s1 + '0'; s2c = s2 + '0'; s.push_back(mc); s.push_back(':'); s.push_back(s1c); s.push_back(s2c); return s; } int main(int argc, char *argv[]) { string filename = argv[1]; ifstream fin; string title, time, artist, album, genre; int track; map<string, Artist *> artists; fin.open(filename); while (fin >> title >> time >> artist >> album >> genre >> track) { replace(title.begin(), title.end(), '_', ' '); replace(artist.begin(), artist.end(), '_', ' '); replace(album.begin(), album.end(), '_', ' '); Artist* curArtist = nullptr; Album* curAlbum = nullptr; Song* curSong = new Song(); // 查找或创建Artist auto artistIt = artists.find(artist); if (artistIt != artists.end()) { cout << "Old Artist: " << artist << endl; curArtist = artistIt->second; } else { cout << "New Artist: " << artist << endl; curArtist = new Artist(); curArtist->name = artist; artists.insert({artist, curArtist}); } // 查找或创建Album auto albumIt = curArtist->albums.find(album); if (albumIt != curArtist->albums.end()) { cout << "Old Album: " << album << endl; curAlbum = albumIt->second; } else { cout << "New Album: " << album << endl; curAlbum = new Album(); curAlbum->name = album; curArtist->albums.insert({album, curAlbum}); } // 初始化Song并添加到Album curSong->title = title; curSong->track = track; curSong->time = stringToInt(time); curAlbum->songs.insert({track, curSong}); // 更新Artist和Album的统计信息 curArtist->nsongs++; curArtist->time += curSong->time; curAlbum->time += curSong->time; } // 统一释放所有动态分配的内存,避免内存泄漏 for (auto& artistPair : artists) { Artist* art = artistPair.second; for (auto& albumPair : art->albums) { Album* alb = albumPair.second; for (auto& songPair : alb->songs) { delete songPair.second; } delete alb; } delete art; } return 0; }
关键修改点
- 按需分配实例:仅在需要创建新Artist/Album时执行
new,避免不必要的内存分配。 - 避免野指针:不再删除被map引用的实例,而是在程序结束前统一遍历所有容器,释放所有动态分配的内存。
- 完善业务逻辑:将创建的Song实例添加到对应Album的
songs集合中,补充Artist和Album的统计信息更新。 - 修复内存泄漏:新增末尾的内存释放逻辑,确保所有动态分配的对象都被正确回收。
内容的提问来源于stack exchange,提问作者Ian Burns
相关产品推荐
相关产品推荐

