我有一个我正在扫描的文本文件。文件中的第一个数字是矩阵中的行数,第二个数字是矩阵中的列数。
"文字文件"
4
10
3.000000,1.000000,1180.000000,1955.000000,221900.000000
3.000000,2.250000,2570.000000,1951.000000,538000.000000
2.000000,1.000000,770.000000,1933.000000,180000.000000
.
.
.
n(4,10)矩阵
我使用fscanf存储读取数组和两个循环来读取二维数组中接收的值。
double hold;
fscanf(fpointer,"%d",&value);//gets me 4
fscanf(fpointer,"%d",&lastvalue);/*gets me 10*/
for (i=0; i<value; i++)
{
for (j=0; j<lastvalue; j++) //Supposed to input the other values
{
fscanf(fpointer,"%lf",&hold); array[i][j]=hold;
我通过两个for循环打印数组内容。
for(i=0;i<value;i++){
for(j=0;j<lastvalue;j++){
printf("%lf\t", array[i][j]);
}
printf("\n");
然而,我收到循环的第一个索引作为输出重复。
3.000000 3.000000 3.000000 3.000000 3.000000 3.000000 3.000000 3.000000 3.000000 3.000000
3.000000 3.000000 3.000000 3.000000 3.000000 3.000000 3.000000 3.000000 3.000000 3.000000
我花了相当长的时间在这上面,我不确定我的逻辑是不正确还是我不了解fscanf。我最初认为fscanf的逗号有问题。我尝试使用逗号作为分隔符,就像我在另一篇文章fscanf(...,"%lf[^ ,]"...)
上看到的那样。我收到了相同的输出。请让我知道错误以及如何修复它。
答案 0 :(得分:1)
你需要处理逗号。这是一种方式:
#include <stdio.h>
#include <stdlib.h>
void die(char *msg) {
fprintf(stderr, "Error: %s\n", msg);
exit(1);
}
double **read_matrix(FILE *f) {
int m, n;
if (fscanf(f, "%d%d", &m, &n) != 2) die("Couldn't scan matrix size");
if (m <= 0 || n <= 0) die("Bad matrix size");
double **matrix = malloc(m * sizeof(double*));
if (!matrix) die("Couldn't allocate matrix spine");
for (int i = 0; i < m; ++i) {
matrix[i] = malloc(n * sizeof(double));
if (!matrix[i]) die("Couldn't allocate matrix row");
// Read the first column. No comma.
if (fscanf(f, "%lf", &matrix[i][0]) != 1) die("Couldn't read matrix (1)");
// Read the other columns. Skip preceding commas.
for (int j = 1; j < n; ++j)
if (fscanf(f, ",%lf", &matrix[i][j]) != 1) die("Couldn't read matrix (2)");
}
return matrix;
}
int main(void) {
double **matrix = read_matrix(stdin);
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) printf(" %lf", matrix[i][j]);
printf("\n");
}
return 0;
}
答案 1 :(得分:1)
您可以采取多种方法。这里的关键是你知道你将有2个整数(前两行各占一个),表示要跟随的rows
和cols
数据的数量。然后,您会在您的矩阵中看到rows
个cols
个数字。您的第一个决定将是“我如何处理存储?” (动态分配,或者数据是否足够小,如果我对矩阵使用可变长度数组(VLA),它将不会StackOverflow?)
使用VLA无需动态分配,跟踪和释放内存,但您必须知道不需要存储比堆栈更多的double
值。以下假设您的VLA值小于100,000
左右,使VLA成为有效选项。
首先,您如何从文件中挑选(读取)row
和col
值?虽然fgets
是迄今为止做面向行的输入的首选方式,但实际上您可以在row
的一次调用中同时获得col
和fprintf
,并享有额外的好处在col
值之后的剩余空格,直到矩阵的第一个值。例如,以下内容将起作用:
/* read row & col and consume all whitespace to first value */
if (fscanf (fp, "%d %d ", &row, &col) != 2) {
fprintf (stderr, "error: failed to read row and col.\n");
return 1;
}
(注意: space
中最后一个转换说明符后面的"%d %d "
拥有row
和col
值后,您现在可以调整缓冲区大小以使用fgets
读取文件中的每个剩余行。在将每一行读入缓冲区后,将使用strtod
从缓冲区中解析每个列值,并根据col
值验证已解析的值的数量,以确保填充完整的矩阵行。行缓冲区是一个VLA,其大小32-chars
每col
个值要读取(这应该超过50%
)。使用VLA调整缓冲区和矩阵的大小可以按如下方式进行:
bufsz = col * 32; /* set read buffer size based on col */
char buf [bufsz]; /* VLA for read buffer */
double mtrx[row][col]; /* VLA for matrix */
memset (mtrx, 0, row * col * sizeof **mtrx); /* zero matrix */
接下来只是用fgets
读取每一行,然后使用指针测试当前字符是否为[+-0-9]
之一。如果是,则执行并验证转换为double
,并且指针前进到转换中结束字符之外的下一个字符(由strtod
本身提供)。
如果当前角色不是您感兴趣的角色,则不要对其进行任何操作并获取下一个角色(这是跳过','
s的简单方法)
转换一行中的所有值后,将成功转换的数量与col
进行比较,以确保填充矩阵中的整行,如果没有处理错误。然后只需读取下一行并重复,直到读取并转换row
行数。您可以完成与以下类似的操作:
/* read each remaining line up to row lines */
while (ridx < row && fgets (buf, bufsz, fp)) {
int cidx = 0; /* column index */
char *p = buf, *ep = NULL; /* pointer & end pointer for strtod */
while (cidx < col && *p && *p != '\n') { /* for each character */
/* if '+-' or '0-9' convert number with strtod */
if (*p == '+' || *p == '-' || ('0' <= *p && *p <= '9')) {
errno = 0; /* set errno for strtod */
double tmp = strtod (p, &ep); /* convert string to value */
if (errno) { /* if errno set, conversion failed */
fprintf (stderr, "error: failed conversion mtrx[%d][%d].\n",
row, col);
return 1;
}
mtrx[ridx][cidx++] = tmp; /* set matrix value, inc. cidx */
p = ++ep; /* set new p to one past ep */
}
else /* if not '+-' or '0-9', just get next char */
p++;
}
if (cidx != col) { /* validate that col values contained in line */
fprintf (stderr, "error: row '%d' has only '%d' values.\n",
ridx, cidx);
return 1;
}
ridx++; /* row done and values validated, read next row */
}
在您阅读row
行值col
后,您可以根据需要使用矩阵。以下仅将上述内容放在一起,以便读取和输出您提供的示例数据:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
int main (int argc, char **argv) {
int bufsz, col, row, ridx = 0; /* buffer size, col, row, row index */
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file open for reading */
fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
return 1;
}
/* read row & col and consume all whitespace to first value */
if (fscanf (fp, "%d %d ", &row, &col) != 2) {
fprintf (stderr, "error: failed to read row and col.\n");
return 1;
}
bufsz = col * 32; /* set read buffer size based on col */
char buf [bufsz]; /* VLA for read buffer */
double mtrx[row][col]; /* VLA for matrix */
memset (mtrx, 0, row * col * sizeof **mtrx); /* zero matrix */
/* read each remaining line up to row lines */
while (ridx < row && fgets (buf, bufsz, fp)) {
int cidx = 0; /* column index */
char *p = buf, *ep = NULL; /* pointer & end pointer for strtod */
while (cidx < col && *p && *p != '\n') { /* for each character */
/* if '+-' or '0-9' convert number with strtod */
if (*p == '+' || *p == '-' || ('0' <= *p && *p <= '9')) {
errno = 0; /* set errno for strtod */
double tmp = strtod (p, &ep); /* convert string to value */
if (errno) { /* if errno set, conversion failed */
fprintf (stderr, "error: failed conversion mtrx[%d][%d].\n",
row, col);
return 1;
}
mtrx[ridx][cidx++] = tmp; /* set matrix value, inc. cidx */
p = ++ep; /* set new p to one past ep */
}
else /* if not '+-' or '0-9', just get next char */
p++;
}
if (cidx != col) { /* validate that col values contained in line */
fprintf (stderr, "error: row '%d' has only '%d' values.\n",
ridx, cidx);
return 1;
}
ridx++; /* row done and values validated, read next row */
}
if (fp != stdin) fclose (fp); /* close file if not stdin */
if (ridx != row) { /* validate that row rows read from file */
fprintf (stderr, "error: file has only row '%d' rows.\n", ridx);
return 1;
}
for (int i = 0; i < row; i++) { /* output the matrix */
for (int j = 0; j < col; j++)
printf (" %9.2f", mtrx[i][j]);
putchar ('\n');
}
return 0;
}
示例使用/输出
$ ./bin/readmtrx dat/matrix.txt
3.00 1.00 1180.00 1955.00 221900.00
3.00 2.25 2570.00 1951.00 538000.00
2.00 1.00 770.00 1933.00 180000.00
仔细看看,如果您有其他问题,请告诉我。如果您没有编译器提供的VLA扩展,则动态内存分配是另一种选择,如另一个答案所述。