从文件中读取矩阵中的行和列

时间:2016-11-25 14:21:52

标签: c matrix dynamic readfile

我有一个Python脚本,它生成一个带有double值的Matrix并将它们保存在这样的txt文件中:

  

-5.70683 -9.72438 5.62137 -3.52453

     

-3.70381 7.25433 -4.21905 3.88678

     

-1.43741 7.39768 -6.84103 -3.45817

     

-5.66966 3.47989 -5.64204 -6.08512

现在我必须读取C文件中的.txt文件并将其转换为我的结构:

struct Matrix {
    int rows;
    int columns;
    double **matrix;
};

这是我的C档案:

Matrix *readMatrix(const char filename[]) {
    Matrix matrix;
    FILE * matrix_file;
    char * str;
    int i, j;

    //allocate pointer
    matrix.matrix = malloc(4 * sizeof(double *));
    for(i = 0; i < 4; i++)
        matrix.matrix[i] = malloc(4 * sizeof(double *));

    matrix_file = fopen(filename, "r");

    for(i = 0; i < 4; i++) {
        for(j = 0; j < 4; j++) {
            if (!fscanf(matrix_file, "%lf", &matrix.matrix[i][j]))
                break;

            printf("%lf\n",matrix.matrix[i][j]);
        }
    }
    fclose(matrix_file);
    return &matrix;
}

我没有将它分配给4x4矩阵,而是想分配我的Pointer动态。所以我必须从文件中读出行和列。我怎么能这样做?

2 个答案:

答案 0 :(得分:0)

事实证明,我只是写了类似于你问的东西。但是,我用C ++而不是C编写它,尽管大多数逻辑应该是相似的。所以,虽然不是一个完整的答案,但这应该能够引导你一点。

注意:我正在使用方形矩阵,我的文件以逗号分隔(不是空格),第一行包含文件中的行数。最后一点,这是供个人使用(而不是作业或生产代码),因此忽略了大量的错误检查和处理。

因此,值得一提的是,这是代码的缩写版本:

#include <iostream>
#include <iomanip>
#include <fstream>
#include <sstream>
#include <string>


#include <string.h>
#include <random>
#include <math.h>

inline int makeNdx(int r, int c, int max) { return r*max + c;}

int populateMatrix(double**);

int main(int argc, char** argv)
{
    unsigned int      nSize;
    double*           tmatrix = nullptr;

    if(0 != (nSize = populateMatrix(&tmatrix)))
    {
         // the matrix was manipulated here, this code not relevant to 
         // the answer...
    }

    if(nullptr != tmatrix) delete [] tmatrix;
    return 0;
}


int populateMatrix(double** ppmat)
{
    std::string   strFileName;
    std::string   strLine;
    std::string   token;
    unsigned int  row = 0;
    unsigned int  size = 0;
    int*          pnorms = nullptr;

    if(nullptr != *ppmat) delete [] *ppmat;

    std::cout << "Enter the name of the data file: ";
    std::cin >> strFileName;

    std::ifstream infile(strFileName);

    // read file and get matrix size...
    getline(infile, strLine);
    size = atoi(strLine.c_str());

    // allocate space for matrix...
    *ppmat = new double[size*size];

    while(infile.good())
    {
        getline(infile, strLine);
        std::istringstream  strStream(strLine);

        for(unsigned int col = 0; col < size; col++)
        {
            if(strStream)
            {
                getline(strStream, token, ',');
                (*ppmat)[makeNdx(row, col, size)] = atoi(token.c_str());
            }
        }
        row++;
    }
    return size;
}

因此,正如您所看到的,我将矩阵表示为二维的双维数组。因为我希望我的填充矩阵函数能够创建矩阵(即能够修改tmatrix值)我需要通过引用函数来传递指针,因此我将它作为指针传递给它-a-指针。

请记住,在C(和C ++)中,二维数组是以行主体形式实现的,可以考虑放置第一行的一个大数组,然后是第二行,依此类推。因此,因为我更喜欢用行和列来思考,我有一个实用程序函数将行/列索引转换为适当的索引到一维数组中。

答案 1 :(得分:0)

假设您不知道先验行数和列数并希望从文件中推导出它,一种简单的方法是:

  • 读取第一行,解析它并推断出cols的数量,比如说M
  • 分配N个M个M个阵列的数组 - &gt;如果分配错误,那么致命错误
  • 存储数组第一行第一行的值
  • 循环:
    • 读取新行并解析它 - &gt;如果空行或文件结尾返回矩阵(其地址!)
    • 确保它包含M个元素 - &gt;如果不是致命错误
    • 如果数组realloc中没有更多位置,新大小为N = 2 * N或N = N + M
      • 如果分配错误,则致命错误
    • 存储下一行中的行

以下是可能代码的示例:

typedef struct _Matrix {
    int rows;
    int columns;
    double ** matrix; // a pointer to an array of pointers is not a pointer to a 2D array!
    double *data;     // pointer to a 2D array
} Matrix;

#define MAX_LINE_SIZE 256

const char delim[] = " \t";

/*
Find the number of double presents on a line 
*/
int getColumns(char *line) {
    char *ix;
    int cols = 0;
    double val;

    ix = strtok(line, delim);
    for (;;) {
        if(ix == NULL) break;
        if (sscanf(ix, "%lg", &val) == 1) {
            cols +=1;
        }
        else break;
        ix = strtok(NULL, delim);
    }
    return cols;
}

/*
Parse a line on which strtok has been used to find the number of elements
*/
int parseLine(char * line, int ncols, double *val) {
    int i;

    for (i=0; i<ncols; i++) {
        if (sscanf(line, "%lg", val) != 1) return 0;
        line += strlen(line) + 1;  /* skip over the null put here by strtok */
        val += 1;
    }
    return 1;
}

/*
Return (by value) a matrix read from an already opened file
The elements data and matrix must be freed by caller if they are not null
rows is 0 if file is empty, -1 if it is incorrect
*/
Matrix readMatrix(FILE *fd) {
    char line[MAX_LINE_SIZE];
    Matrix matrix;
    int maxrows, row = 0;
    double *val;  /* val will point the the beginning of the next row */

    /* initializes the matrix */
    matrix.rows = matrix.columns = 0;
    matrix.matrix = matrix.data = NULL;

    /* process first line to discover the number of columns */
    if (NULL == fgets(line, sizeof(line), fd)) return matrix;

    matrix.columns = getColumns(line);
    maxrows = matrix.columns;

    /* allocate the 2D array for data and 1D array of pointers for matrix
    (to be able to use matrix.matrix[row][col] instead of
    matrix.data[col + row.matrix.columns])
    */
    matrix.matrix = malloc(maxrows * sizeof(double *));
    val = matrix.data = malloc(maxrows * matrix.columns * sizeof(double));

    if (parseLine(line, matrix.columns, val) == 0) {
        matrix.rows = -1;
        return matrix;
    }
    /* Ok one row have been read */
    matrix.matrix[matrix.rows++] = val;
    val += matrix.columns;

    /* let's process the other rows */
    for(;;) {
        int cols;
        if (NULL == fgets(line, sizeof(line), fd)) return matrix;
        cols = getColumns(line);
        if (cols == 0) return matrix; /* empty line denotes also the end of data to allow and empty last line */
        if (cols != matrix.columns) {
            matrix.rows = -1; /* incorrect number of cols: fatal */
            return matrix;
        }
        if (matrix.rows == maxrows) { /* data is full: reallocate some more room */
            int r;
            maxrows += matrix.columns;
            matrix.matrix = realloc(matrix.matrix, maxrows * sizeof(double *));
            matrix.data = realloc(matrix.data, maxrows * matrix.columns * sizeof(double));
            for (r=0; r<matrix.rows; r++) {      /* ensure that the pointers from matrix actually point in data */
                matrix.matrix[r] = matrix.data + r * matrix.columns;
            }
            val = matrix.data + matrix.rows * matrix.columns; /* ensure val points to the beginning of next row */
        }
        /* Ok, load the line */
        matrix.matrix[matrix.rows++] = val;
        if (parseLine(line, matrix.columns, val) == 0) {
            matrix.rows = -1;
            return matrix;
        }
        val += matrix.columns;
    }

    return matrix;
}

应该测试分配错误......