C语言从文件读取矩阵的实现及代码复用问题咨询
问题分析与代码修正
核心问题梳理
你当前的代码存在两个致命问题:
- 循环逻辑完全错误:你用双层循环遍历矩阵的每个元素,但文件中仅存储非零元素的位置和值,并非每个元素对应一行。嵌套循环会强制读取
m*n行数据,远超过文件实际行数,导致读取垃圾数据甚至程序崩溃。 - 索引处理硬编码:你固定用
i=i-1和j=j-1适配第一个1-based索引的文件,但第二个文件是0-based索引,硬减1会导致位置完全错误。
修正后的可复用代码
下面是调整后的代码,同时支持1-based和0-based两种索引格式,能处理你提供的两个文件:
#include <stdio.h> #include <stdlib.h> // 矩阵内存分配函数(用calloc初始化所有元素为0) int** allocMatrix(int rows, int cols) { int** mat = (int**)calloc(rows, sizeof(int*)); if (!mat) return NULL; for (int i = 0; i < rows; i++) { mat[i] = (int*)calloc(cols, sizeof(int)); if (!mat[i]) { // 分配失败时释放已分配的内存 for (int j = 0; j < i; j++) free(mat[j]); free(mat); return NULL; } } return mat; } /** * 读取矩阵文件 * @param nameFile 文件名 * @param m 输出矩阵行数 * @param n 输出矩阵列数 * @param is1Based 文件中的行列号是否为1-based(是传1,否则传0) * @return 矩阵指针,失败返回NULL */ int** readFile(char *nameFile, int *m, int *n, int is1Based) { int **A; FILE *fp; int val, row, col; fp = fopen(nameFile, "r"); if (fp == NULL) { printf("Error reading file\n"); return NULL; } // 读取首行的行列数,检查格式是否正确 if (fscanf(fp, "%d %d", m, n) != 2) { printf("Invalid file format: first line should be rows cols\n"); fclose(fp); return NULL; } // 分配初始化为0的矩阵 A = allocMatrix(*m, *n); if (A == NULL) { printf("Memory allocation failed\n"); fclose(fp); return NULL; } // 循环读取所有非零元素行,直到文件结束 while (fscanf(fp, "%d %d %d", &val, &row, &col) == 3) { // 根据索引类型调整目标位置 int targetRow = is1Based ? row - 1 : row; int targetCol = is1Based ? col - 1 : col; // 检查索引是否在合法范围内,避免越界 if (targetRow >= 0 && targetRow < *m && targetCol >= 0 && targetCol < *n) { A[targetRow][targetCol] = val; } else { printf("Warning: Position (%d, %d) is out of matrix bounds\n", row, col); } } fclose(fp); return A; } // 辅助打印矩阵的函数 void printMatrix(int** mat, int rows, int cols) { for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { printf("%d ", mat[i][j]); } printf("\n"); } } // 测试示例 int main() { int m, n; // 处理第一个1-based索引的文件 int** mat1 = readFile("matrix1.txt", &m, &n, 1); if (mat1) { printf("Matrix from 1-based file:\n"); printMatrix(mat1, m, n); // 释放内存 for (int i = 0; i < m; i++) free(mat1[i]); free(mat1); } // 处理第二个0-based索引的文件 int** mat2 = readFile("matrix2.txt", &m, &n, 0); if (mat2) { printf("\nMatrix from 0-based file:\n"); printMatrix(mat2, m, n); for (int i = 0; i < m; i++) free(mat2[i]); free(mat2); } return 0; }
关键改进点
- 循环逻辑修正:用
while(fscanf(...) == 3)循环读取所有非零元素行,直到文件结束,适配任意数量的非零元素。 - 可复用索引处理:通过
is1Based参数切换索引规则,处理第一个文件传1(需要减1),处理第二个文件传0(直接使用原索引),实现代码复用。 - 健壮性提升:添加文件格式检查、内存分配失败处理、索引越界检查,避免程序崩溃。
- 资源管理:打开的文件最终会关闭,分配的内存也提供了释放示例,避免资源泄漏。
针对你的问题的直接回答
修改后的代码可以复用处理第二个文件,只需要在调用readFile时将最后一个参数设为0即可,因为第二个文件的行列号是0-based,不需要减1调整。
内容的提问来源于stack exchange,提问作者Offsky
相关产品推荐
相关产品推荐

