OP 在 cmets 中写道:
很抱歉,我的老师刚刚澄清了一切......事实证明,对于每一行,第一个数字是行,第二个是列,第三个是元素。上面的例子,@ 987654321@ 必须进入[0][3] 的位置。矩阵不必是方阵。
这让每一件事都变得不同。如果你不知道尺寸
矩阵,那么你必须先阅读所有内容,然后计算矩阵
维度,为矩阵分配空间,然后用值填充它。
我会这样做:
#include <stdio.h>
#include <stdlib.h>
#define BLOCK 1024
struct matrix_info {
int col;
int row;
double val;
};
void free_matrix(double **matrix, size_t rows)
{
if(matrix == NULL)
return;
for(size_t i = 0; i < rows; ++i)
free(matrix[i]);
free(matrix);
}
double **readmatrix(const char *fname, size_t *rows, size_t *cols)
{
if(fname == NULL || rows == NULL || cols == NULL)
return NULL;
double **matrix = NULL;
struct matrix_info *info = NULL;
size_t mi_idx = 0; // matrix info index
size_t mi_size = 0;
FILE *fp = fopen(fname, "r");
if(fp == NULL)
{
fprintf(stderr, "Cannot open %s\n", fname);
return NULL;
}
*rows = 0;
*cols = 0;
for(;;)
{
if(mi_idx >= mi_size)
{
struct matrix_info *tmp = realloc(info, (mi_size + BLOCK) * sizeof *info);
if(tmp == NULL)
{
fprintf(stderr, "not enough memory\n");
free(info);
fclose(fp);
return NULL;
}
info = tmp;
mi_size += BLOCK;
}
int ret = fscanf(fp, "%d %d %lf", &info[mi_idx].row, &info[mi_idx].col,
&info[mi_idx].val);
if(ret == EOF)
break; // end of file reached
if(ret != 3)
{
fprintf(stderr, "Error parsing matrix\n");
free(info);
fclose(fp);
return NULL;
}
if(*rows < info[mi_idx].row)
*rows = info[mi_idx].row;
if(*cols < info[mi_idx].col)
*cols = info[mi_idx].col;
mi_idx++;
}
fclose(fp);
// mi_idx is now the length of info
// *cols and *rows have the largest index
// for the matrix, hence the dimension is (rows + 1) x (cols + 1)
(*cols)++;
(*rows)++;
// allocating memory
matrix = calloc(*rows, sizeof *matrix);
if(matrix == NULL)
{
fprintf(stderr, "Not enough memory\n");
free(info);
return NULL;
}
for(size_t i = 0; i < *rows; ++i)
{
matrix[i] = calloc(*cols, sizeof **matrix);
if(matrix[i] == NULL)
{
fprintf(stderr, "Not enough memory\n");
free(info);
free_matrix(matrix, *rows);
return NULL;
}
}
// populating matrix
for(size_t i = 0; i < mi_idx; ++i)
{
int r,c;
r = info[i].row;
c = info[i].col;
matrix[r][c] = info[i].val;
}
free(info);
return matrix;
}
int main(void)
{
const char *fn = "/tmp/matrix.txt";
size_t rows, cols;
double **matrix = readmatrix(fn, &rows, &cols);
if(matrix == NULL)
return 1;
for(size_t i = 0; i < rows; ++i)
{
for(size_t j = 0; j < cols; ++j)
printf("%0.3f ", matrix[i][j]);
puts("");
}
free_matrix(matrix, rows);
return 0;
}
输出是(对于包含您的示例数据的文件)
5.200 0.000 0.000 1.200 0.000 0.000
0.000 0.000 0.000 0.000 0.000 0.000
0.000 0.000 0.000 0.000 0.000 3.200
2.100 0.000 0.000 0.000 0.000 4.200
0.000 0.000 0.000 0.000 0.000 2.200
所以快速解释一下我在做什么:
我读取文件并将信息存储在动态分配的数组中
关于列、行和值。此信息存储在
struct matrix_info *info.
我的想法是读取每一行并提取三个值。当我阅读
文件,我还存储了列和行的最大索引
...
if(*rows < info[mi_idx].row)
*rows = info[mi_idx].row;
if(*cols < info[mi_idx].col)
*cols = info[mi_idx].col;
...
所以当读取文件时,我知道矩阵的尺寸。现在所有值
他们的行和列存储在info 数组中,所以下一步是
为矩阵分配内存并根据info[i] 填充值
条目。
for(size_t i = 0; i < mi_idx; ++i)
{
int r,c;
r = info[i].row;
c = info[i].col;
matrix[r][c] = info[i].val;
}
最后我为info 释放内存并返回矩阵。
另一个有趣的部分是:
if(mi_idx >= mi_size)
{
struct matrix_info *tmp = realloc(info, (mi_size + BLOCK) * sizeof *info);
if(tmp == NULL)
{
fprintf(stderr, "not enough memory\n");
free(info);
fclose(fp);
return NULL;
}
info = tmp;
mi_size += BLOCK;
}
因为您提到您对矩阵的唯一了解就是它
可能包含多达 10000 个元素,那么输入文件可能非常大。
我没有在每个循环上为 info 元素重新分配内存,而是分配
一次包含 1024 个 (BLOCK) info 个元素的块。因此,一旦一个块已满,
下一个块被分配等等。所以我每 1024 次才打电话给realloc
迭代。