C++矩阵乘法函数结果异常:输出值与调试结果不符求助
问题背景
编写了C++矩阵乘法函数multiplication,该函数接收两个ifstream引用,从文件读取矩阵维度与数据,计算乘积后写入output.txt,最后返回ofstream对象。
输入文件内容
1.txt:
1 3 1 2 3
2.txt:
3 1 4 5 6
预期输出
1 1 32
实际输出
1 1 -3.424e+26
调试时显示计算结果为正确的32,但输出结果异常,相关代码如下:
ofstream multiplication(ifstream& lhs, ifstream& rhs) { int rows_lhs = 0, cols_lhs = 0; int rows_rhs = 0, cols_rhs = 0; if (!lhs.eof() && !rhs.eof()) { lhs >> rows_lhs >> cols_lhs; rhs >> rows_rhs >> cols_rhs; } float matrix_lhs[rows_lhs][cols_lhs]; float matrix_rhs[rows_rhs][cols_rhs]; float el = 0.0; for (size_t i = 0; i < rows_lhs; ++i) { for (size_t j = 0; j < cols_lhs; ++j) { lhs >> el; matrix_lhs[i][j] = el; } } for (size_t i = 0; i < rows_rhs; ++i) { for (size_t j = 0; j < cols_rhs; ++j) { rhs >> el; matrix_rhs[i][j] = el; } } float matrix_res[rows_lhs][cols_rhs]; float left_el = 0.0; float right_el = 0.0; for (size_t i = 0; i < rows_lhs; ++i) { for (size_t j = 0; j < cols_rhs; ++j) { for (size_t k = 0; k < cols_lhs; ++k) { left_el = matrix_lhs[i][k]; right_el = matrix_rhs[k][j]; matrix_res[i][j] += left_el * right_el; } } } ofstream out; out.open("output.txt"); out << rows_lhs << ' ' << cols_rhs << '\n'; for (size_t i = 0; i < rows_lhs; ++i) { for (size_t j = 0; j < cols_rhs; ++j) { out << matrix_res[i][j] << ' '; } out << '\n'; } out.close(); return out; } int main(int argc, char* argv[]) { ifstream infile_1("1.txt"); ifstream infile_2("3.txt"); ofstream out = multiplication(infile_1, infile_2); float res = 0; while (!out.eof()) { out << res; } }
问题分析与修复
1. 结果矩阵未初始化,累加前存在垃圾值
float matrix_res[rows_lhs][cols_rhs];是栈上分配的非标准变长数组(VLA),C++标准不支持该写法(仅部分编译器提供扩展支持),且栈数组默认不会初始化,元素值为内存中的随机垃圾值。后续直接执行matrix_res[i][j] += left_el * right_el;时,是在垃圾值基础上累加计算结果,最终输出的是垃圾值与正确值的总和,这是输出异常的核心原因。
调试环境通常会将栈内存初始化为0,因此调试时能看到正确结果,但实际运行时栈内存为随机值,导致输出错误。
修复方式:初始化结果矩阵所有元素为0,或改用std::vector创建动态矩阵并自动初始化。
2. 返回已关闭的ofstream对象,main函数错误复用
multiplication函数中执行了out.close();,返回的ofstream对象已处于关闭状态。main函数接收该对象后,执行while (!out.eof()) { out << res; }的逻辑完全错误:关闭的流无法写入,且!out.eof()不是正确的文件循环判断方式,会导致无意义的无效操作。
同时,main函数中打开的第二个输入文件是3.txt,与实际输入文件2.txt不符,会导致读取失败,矩阵数据为垃圾值(调试时可能文件名正确,因此未暴露该问题)。
修复方式:移除手动关闭out的代码(ofstream析构时会自动关闭文件),修正输入文件名,删除main中错误的写入循环。
3. 非标准变长数组的使用
C++标准不支持float matrix_lhs[rows_lhs][cols_lhs];这种变长数组写法,会降低代码可移植性,建议改用std::vector<std::vector<float>>动态创建二维矩阵。
4. 文件读取未做错误检查
代码仅通过!lhs.eof() && !rhs.eof()判断是否读取维度,但未检查lhs >> rows_lhs >> cols_lhs等读取操作是否成功。若文件格式错误或文件不存在,会导致维度为0,后续数组访问越界。
修复方式:添加读取操作的有效性检查,避免无效数据进入后续计算。
修复后的完整代码
#include <fstream> #include <vector> std::ofstream multiplication(std::ifstream& lhs, std::ifstream& rhs) { int rows_lhs = 0, cols_lhs = 0; int rows_rhs = 0, cols_rhs = 0; // 检查维度读取是否成功 if (!(lhs >> rows_lhs >> cols_lhs) || !(rhs >> rows_rhs >> cols_rhs)) { std::ofstream empty_out; return empty_out; } // 使用vector创建并初始化矩阵 std::vector<std::vector<float>> matrix_lhs(rows_lhs, std::vector<float>(cols_lhs, 0.0f)); std::vector<std::vector<float>> matrix_rhs(rows_rhs, std::vector<float>(cols_rhs, 0.0f)); float el = 0.0f; for (int i = 0; i < rows_lhs; ++i) { for (int j = 0; j < cols_lhs; ++j) { lhs >> el; matrix_lhs[i][j] = el; } } for (int i = 0; i < rows_rhs; ++i) { for (int j = 0; j < cols_rhs; ++j) { rhs >> el; matrix_rhs[i][j] = el; } } // 初始化结果矩阵为0 std::vector<std::vector<float>> matrix_res(rows_lhs, std::vector<float>(cols_rhs, 0.0f)); for (int i = 0; i < rows_lhs; ++i) { for (int j = 0; j < cols_rhs; ++j) { for (int k = 0; k < cols_lhs; ++k) { matrix_res[i][j] += matrix_lhs[i][k] * matrix_rhs[k][j]; } } } std::ofstream out("output.txt"); if (out.is_open()) { out << rows_lhs << ' ' << cols_rhs << '\n'; for (int i = 0; i < rows_lhs; ++i) { for (int j = 0; j < cols_rhs; ++j) { out << matrix_res[i][j] << ' '; } out << '\n'; } } return out; } int main(int argc, char* argv[]) { std::ifstream infile_1("1.txt"); std::ifstream infile_2("2.txt"); // 修正文件名 std::ofstream out = multiplication(infile_1, infile_2); return 0; }
内容的提问来源于stack exchange,提问作者nameisnoname

