从文件中读取矩阵

时间:2018-02-22 20:30:05

标签: c

这是我从文件中读取矩阵的功能。在第一行的文本文件中,{2}是n,3是m,接下来的两行是矩阵。 我没有错误,但我的计划"停止工作"而且我不知道为什么。谢谢! 主要是我:readmatrix(n,m,a, "text.txt");

int readmatrix(int* n,int *m, int a[*n][*m], char* filename){
    FILE *pf;
    int i,j;
    pf = fopen (filename, "rt");
    if (pf == NULL)
    return 0;
    fscanf (pf, "%d",n); 
    for (i=0;i<*n;i++) 
    {
        for(j=0;j<*m;j++)
        fscanf (pf, "%d", &a[i][j]);
    }
    fclose (pf); 
    return 1; 
    }

1 个答案:

答案 0 :(得分:2)

如果您的编译器支持VLA或您使用的是C99,那么您可以这样做:

#include <stdio.h>

int readmatrix(size_t rows, size_t cols, int (*a)[cols], const char* filename)
{

    FILE *pf;
    pf = fopen (filename, "r");
    if (pf == NULL)
        return 0;

    for(size_t i = 0; i < rows; ++i)
    {
        for(size_t j = 0; j < cols; ++j)
            fscanf(pf, "%d", a[i] + j);
    }


    fclose (pf); 
    return 1; 
}

int main(void)
{
    int matrix[2][3];

    readmatrix(2, 3, matrix, "file.dat");

    for(size_t i = 0; i < 2; ++i)
    {
        for(size_t j = 0; j < 3; ++j)
            printf("%-3d ", matrix[i][j]);
        puts("");
    }

    return 0;
}

file.dat看起来像这样:

1 2 3
4 5 6

我的程序输出

$ ./a 
1   2   3   
4   5   6   

请注意,这是一个基本示例,您应该始终检查返回值 fscanf。如果file.dat只有一行,那么你会遇到麻烦。也 文件中没有数字,你也会得到未定义的值 基质

我建议用fgets读取整行,然后使用解析行 sscanf或其他一些功能,如strtok,那么它会更容易做出反应 到输入文件中的错误。

修改

更健壮的方式来读取这样的文件将是:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>


int **readmatrix(size_t *rows, size_t *cols, const char *filename)
{
    if(rows == NULL || cols == NULL || filename == NULL)
        return NULL;

    *rows = 0;
    *cols = 0;

    FILE *fp = fopen(filename, "r");

    if(fp == NULL)
    {
        fprintf(stderr, "could not open %s: %s\n", filename, strerror(errno));
        return NULL;
    }

    int **matrix = NULL, **tmp;

    char line[1024];

    while(fgets(line, sizeof line, fp))
    {
        if(*cols == 0)
        {
            // determine the size of the columns based on
            // the first row
            char *scan = line;
            int dummy;
            int offset = 0;
            while(sscanf(scan, "%d%n", &dummy, &offset) == 1)
            {
                scan += offset;
                (*cols)++;
            }
        }

        tmp = realloc(matrix, (*rows + 1) * sizeof *matrix);

        if(tmp == NULL)
        {
            fclose(fp);
            return matrix; // return all you've parsed so far
        }

        matrix = tmp;

        matrix[*rows] = calloc(*cols, sizeof *matrix[*rows]);

        if(matrix[*rows] == NULL)
        {
            fclose(fp);
            if(*rows == 0) // failed in the first row, free everything
            {
                fclose(fp);
                free(matrix);
                return NULL;
            }

            return matrix; // return all you've parsed so far
        }

        int offset = 0;
        char *scan = line;
        for(size_t j = 0; j < *cols; ++j)
        {
            if(sscanf(scan, "%d%n", matrix[*rows] + j, &offset) == 1)
                scan += offset;
            else
                matrix[*rows][j] = 0; // could not read, set cell to 0
        }

        // incrementing rows
        (*rows)++;
    }

    fclose(fp);

    return matrix;
}

int main(void)
{

    size_t cols, rows;
    int **matrix = readmatrix(&rows, &cols, "file.dat");

    if(matrix == NULL)
    {
        fprintf(stderr, "could not read matrix\n");
        return 1;
    }


    for(size_t i = 0; i < rows; ++i)
    {
        for(size_t j = 0; j < cols; ++j)
            printf("%-3d ", matrix[i][j]);
        puts("");

    }


    // freeing memory
    for(size_t i = 0; i < rows; ++i)
        free(matrix[i]);
    free(matrix);

    return 0;
}

现在file.dat看起来像这样:

1 2 3 4 
4 5 6 5 
9 8 8 7 
5 5 5 5 
1 1 1 1 

输出

1   2   3   4   
4   5   6   5   
9   8   8   7   
5   5   5   5   
1   1   1   1   

在此示例中,我仅计算第一列的列数 将该数字用于所有其他列。如果输入文件的行数少于 第一行的列,然后缺少的值存储为0.如果它有行 将修剪比列更多的列。

我计算这样的行数:

            while(sscanf(scan, "%d%n", &dummy, &offset) == 1)
            {
                scan += offset;
                (*cols)++;
            }

首先我声明指针scan指向line,以便我可以修改。{1}} 指针不会丢失原始行。 %n中的sscanf不计算在内 成功转换的次数,这将返回scan的位置 它停止了阅读。我用它来循环sscanf。我明确地检查了一下 sscanf返回1,如果是这种情况,我会增加列数和 我更新scan以更新到sscanf停止阅读的位置。这个 允许我继续扫描,直到到达行尾。我用了一个 类似的技术来解析所有整数。