C++读取文件存储矩阵时退出返回值3221226356问题排查
问题描述
我尝试从文件读取输入内容,将其存储到自定义矩阵类的动态分配数组中。
每次运行代码时输入和输出结果均正确,但程序总是以返回值 3221226356 退出。
输入文件为.txt格式,首行标注矩阵行数、每行元素个数,文件内容示例如下:
10 15 000000000000000 000999000009900 000999000009900 000000900009900 000090000099900 000099900000000 090000900000000 099999999900000 000090090000000 000000000000000
其中10为矩阵总行数,15为每行的元素个数,需要读取矩阵并存入matArray成员,每个字符对应一个Element节点对象。
原始实现代码如下:
#include <bits/stdc++.h> #include<iostream> #include<fstream> #include<string> #include<cstring> using namespace std; class Element{ private: char value; int processed; public: Element(){ value = 0; processed = 0; } void setContent(char cellValue){ value = cellValue; } void setProcessed(int num1){ processed = num1; } char getContent(){ return value; } int getProcessed(){ return processed; } }; class Matrix{ private: Element* matArray; int rows; int cols; public: Matrix(int nRows, int nCols){ matArray = new Element[nRows * nCols]; rows = nRows; cols = nCols; } void setInput(int r, int c, Element input){ matArray[r * rows + c] = input; } Element getInput(int r, int c){ return matArray[r * rows + c]; } }; int main(){ int numRow = 0; int numCol = 0; string filename = ""; string whiteSpace; string string1; cin >> filename; ifstream inFS; filename = filename + ".txt"; inFS.open(filename.c_str()); if(inFS.fail()){ cout << "fail"; } if(inFS.good()){ cout << "good" << endl; } inFS >> numRow; inFS >> numCol; Matrix mat1(numRow, numCol); Element temp; char display; getline(inFS, whiteSpace); //Reading the matrix from the file and inserting this information to mat1 for(int i = 0; i < numRow; i++){ getline(inFS, string1); cout << endl; for(int j = 0; j < numCol; j++){ temp = mat1.getInput(i, j); temp.setContent(string1[j]); mat1.setInput(i, j, temp); cout << mat1.getInput(i, j).getContent() << " "; } } cout << endl; return 0; }
问题原因
返回值3221226356是Windows平台典型的堆损坏错误(对应十六进制码0xC0000374),说明程序运行过程中非法写入了堆内存,破坏了堆的管理结构,根源是代码存在两个核心问题:
- 矩阵索引计算逻辑错误
二维数组映射到一维数组的正确索引公式是行号 * 列数 + 列号,但Matrix类的setInput和getInput方法里错写为r * rows + c(行号乘了行数而非列数)。
当前10行15列的测试用例中,存和取都用了相同的错误索引,所以打印输出看起来正确,但实际内存布局完全混乱:当测试用例行数大于列数时,索引会直接超出matArray申请的内存边界,写入堆上的非法地址,破坏堆管理结构,最终在程序退出时触发错误。就算是当前10行15列的用例,错误的写入位置也可能覆盖堆块的校验填充字节,被堆检测机制捕获触发报错。 - Matrix类未正确管理动态内存
用new[]申请了matArray的堆内存,但没有编写析构函数释放内存,存在内存泄漏;同时类没有自定义拷贝构造、拷贝赋值规则,后续如果发生对象拷贝会触发双重释放问题。
另外还有健壮性缺陷:文件打开失败时只打印了"fail",没有终止程序,后续逻辑会继续操作无效的文件流,触发未定义行为。
修复方案
- 修正索引计算公式,把
setInput和getInput里的索引计算改为r * cols + c:
void setInput(int r, int c, Element input){ matArray[r * cols + c] = input; } Element getInput(int r, int c){ return matArray[r * cols + c]; }
- 给Matrix类添加析构函数释放内存,同时禁用默认的浅拷贝逻辑避免双重释放,建议调整构造函数初始化顺序更规范:
class Matrix{ private: Element* matArray; int rows; int cols; public: Matrix(int nRows, int nCols){ rows = nRows; cols = nCols; matArray = new Element[rows * cols]; } // 新增析构函数 ~Matrix() { delete[] matArray; } // 禁用浅拷贝 Matrix(const Matrix&) = delete; Matrix& operator=(const Matrix&) = delete; // 其余方法修正索引后保持不变 void setInput(int r, int c, Element input){ matArray[r * cols + c] = input; } Element getInput(int r, int c){ return matArray[r * cols + c]; } };
- 文件打开失败时直接退出程序,不要继续执行后续逻辑:
if(inFS.fail()){ cout << "fail to open file"; return 1; }
main函数中未使用的char display变量可以直接删除,属于冗余代码。
修复后程序即可正常运行,不会再出现异常退出的问题。
内容的提问来源于stack exchange,提问作者Nomnomwom
相关产品推荐
相关产品推荐

