Как загрузить матрицу из файла, не зная его размера и без многократного чтения? - PullRequest
0 голосов
/ 14 декабря 2018

Мое упражнение - загрузить 2 матрицы из 2 файлов с неизвестными размерами и умножить их вместе, если это возможно.Я также должен загрузить каждый файл один раз.Я мог бы сделать это с загрузкой файла дважды, как вы можете видеть ниже, но как я могу сделать с загрузкой файла только один раз?

typedef struct matrix_ {
    int r, c;
    double* dat;
} matrix;

int rows(char* fn) {
    int lines = 1;
    int ch;
    FILE* fp = fopen(fn, "r");
    while(!feof(fp)) {
        ch = fgetc(fp);
        if(ch == '\n') {
            lines++;
        }
    }
    return lines;
}

matrix loadmatrix(char* fn) {
    FILE* file = fopen(fn, "r");
    int size = 5*5;
    matrix mat;
    mat.r = rows(fn);
    mat.dat = malloc(size*sizeof(double));
    double input;
    int i = 0;
    do {
        if (fscanf(file, "%lf", &input)==1) {
            if(i == size-1) {
                size = 4*size;
                mat.dat = realloc(mat.dat, size*sizeof(double));
            }
            mat.dat[i] = input;
            i+=1;
        }
    } while (!feof(file));
    mat.c = ((i+1)/(mat.r));
    return mat;
}

1 Ответ

0 голосов
/ 14 декабря 2018

Прочитайте файл построчно, и для каждой строки прочитайте в каждом значении с sscanf.

Каждая строка является строкой, и каждое значение в ней находится встолбец.В первой строке подсчитывайте столбцы по мере продвижения и подсчитывайте строки на каждой новой строке.Если вам нужно больше места в вашем массиве data, realloc место еще одной строки (matrix.cols * sizeof(double)).

Использование read_line дляпереносимо читая в строке, имеем:

#define MIN_SIZE (5 * 5)

typedef struct matrix {
    size_t  rows;
    size_t  cols;
    double *data;
} matrix;

matrix loadmatrix(const char *filename)
{
    FILE *file = fopen(filename, "r");
    if (file == NULL) {
        fprintf(stderr, "could not open file '%s' for reading\n", filename);
        exit(1);
    }
    matrix mat = {
        .rows = 0,
        .cols = 0,
        .data = calloc(MIN_SIZE, sizeof(double)),
    };
    // You should check mat.data != NULL here, but I omit it to ease reading
    char *line = NULL;
    size_t index = 0;
    size_t data_size = MIN_SIZE;
    while (read_line(file, &line) > 0) {
        double value;
        // Keep reading values into this row
        size_t offset = 0;
        int read_chars = 0;
        while (sscanf(line + offset, "%lf%n", &value, &read_chars) == 1) {
            offset += read_chars;
            if (mat.rows == 0) {
                ++mat.cols;
            }
            // Increase the size of the matrix by one more row if more space is needed
            if (index >= data_size) {
                data_size += mat.cols;
                mat.data = realloc(mat.data, sizeof(double) * data_size);
                if (mat.data == NULL) {
                    fprintf(stderr,
                        "could not allocate more space for matrix: %zu\n",
                        data_size);
                    exit(1);
                }
            }
            mat.data[index++] = value;
        }
        ++mat.rows;
        free(line);
    }
    return mat;
}
...