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

C语言从文件读取矩阵的实现及代码复用问题咨询

问题分析与代码修正

核心问题梳理

你当前的代码存在两个致命问题:

  1. 循环逻辑完全错误:你用双层循环遍历矩阵的每个元素,但文件中仅存储非零元素的位置和值,并非每个元素对应一行。嵌套循环会强制读取m*n行数据,远超过文件实际行数,导致读取垃圾数据甚至程序崩溃。
  2. 索引处理硬编码:你固定用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 20:05:31