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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 09:34:51