使用fscanf()扫描到C中的数组的问题
我有一个我正在扫描的文本文件。文件中的第一个数字是矩阵中的行数,第二个数字是矩阵中的列数。
“文本文件”
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[^ ,]"...)
。我收到了相同的输出。请让我知道什么是错的以及如何解决它。
您可以采取多种方法。 这里的关键是你知道你将有2个整数(前两行各占一个),表示要遵循的数据rows
数和rows
数。 然后,您将在列表中读取rows
数cols
。 您的第一个决定将是“我如何处理存储?” (动态分配,或者数据是否足够小,如果我对矩阵使用可变长度数组(VLA),它将不会StackOverflow?)
使用VLA消除了动态分配,跟踪和释放内存的需要,但您必须知道您不需要存储比堆栈上可容纳的更多的double
值。 以下假设您的VLA值小于100,000
左右,使VLA成为有效选项。
首先,您将如何从文件中拾取(读取) row
和col
值? 虽然fgets
是迄今为止做面向行的输入的首选方式,但实际上你可以在一次调用fprintf
同时获得row
和col
,并且在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; }
( 注意: "%d %d "
最后一个转换说明符后面的space
)
拥有row
和col
值后,您现在可以调整缓冲区大小以使用fgets
读取文件中的每个剩余行。 在将每一行读入缓冲区后,将使用strtod
从缓冲区中解析每个列值,并根据col
值validation已解析的值的数量,以确保填充完整的矩阵行。 行缓冲区是一个VLA,可以读取每个col
值的32-chars
(这应该超过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]
。 如果是,则执行并validation转换为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 */ }
在读取了值为col
值的col
,可以根据需要使用矩阵。 以下只是将上述内容放在一起,以便读取和输出您提供的示例数据:
#include #include #include #include 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扩展,则动态内存分配是另一个选项,如另一个答案中所述。
你需要处理逗号。 这是一种方式:
#include #include 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; }