我想使用fscanf
来处理描述矩阵的文件的每一行,每个矩阵行有一行。我不知道,先验,任何给定文件中的矩阵包含多少列或行。
处理未知数量的行是可以的,因为当它到达文件末尾时很容易停止循环。例如:
while(!feof(file)){
if (fscanf(file, "%f", &f)==1) {
printf("%f\n",f);
}
}
但我需要知道变量f
属于哪一行。
例如:
n_row = 0;
while(!feof(file)){
if (fscanf(file, "%f", &f)==1) {
printf("a value %f is in row %d\n",f,n_row);
[if you met a "\n"]{
//then increment the row counter
n_row++;
}
}
}
怎么可能这样做?
一个。
答案 0 :(得分:3)
有两种方法可以做到这一点:
fscanf
逐行阅读您的输入,然后使用行缓冲区中的sscanf
或strtok_r
将其分区为单个数字,或float
后阅读一个字符,并检查该字符是否为\n
。以下是第二种方法的工作原理:
while(!feof(file)) {
char next;
int count = fscanf(file, "%f%c", &f, &next);
if (count > 0) {
// There may not be '\n' on the last line,
// in which case count would be equal 1.
if (count == 1 || next == '\n') {
//then increment the row counter
n_row++;
}
printf("a value %f is in row %d\n", f, n_row);
}
}
虽然第二种方法对应于您希望看到的解决方案,但第一种方法更加健壮。
答案 1 :(得分:1)
有很多方法可以做到这一点。正如dasblinkenlight指出的那样,使用line-oriented
输入读取文件然后解析每一行是最强大的方法,因为它允许在将每个元素添加到数组之前对每个元素执行无限量的验证。基于这种方法,我将一个小例子放在一起,提供了一些其他方法来解决这个问题。
您将始终必须选择一些最大列数来启动(您可以动态分配每个元素,但索引管理变得更具挑战性)。所以选择一些合理的数字,然后只使用所需的列数。如果整体内存使用非常宝贵,只需在读取数组后重新分配以减小列大小。有很多很多方法可以做到这一点,这里只是一个例子。它将从文件名读取任意数量的行和列到整数数组(默认最大列数为128 - 根据需要调整)。输入文件可以是space
或comma
个分隔值。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define ARRAY_WIDTH 128
int main (int argc, char *argv[]) {
int *array[ARRAY_WIDTH]; /* create pointer to array of ints of ARRAY_WIDTH */
int ridx = 0; /* row index */
int cidx = 0; /* col index */
char *buffer = NULL; /* getline buffer, NULL forces getline to allocate */
size_t len = 0; /* number of chars for getline to read, 0: no limit */
ssize_t read; /* number of characters read by getline */
char *ptr = NULL; /* pointer used to parse buffer & by strtol */
char *eptr = NULL; /* pointer used with strtol */
int tmp = 0; /* tmp value holding result of strtol conversion */
if (argc < 2) { /* validate sufficient input */
fprintf (stderr,
"Usage: %s filename [array: space or comma separated values]\n", argv[0]);
return 1;
}
FILE *fp = fopen (argv[1], "r"); /* open input file containing array values */
if (!fp) { /* validate file open or return */
fprintf (stderr, "failed to open file for reading\n");
return 1;
}
while ((read = getline (&buffer, &len, fp)) != -1) { /* read each line in file */
array[ridx] = calloc (1, sizeof (array)); /* allocate row */
ptr = buffer;
cidx = 0; /* reset column index for read of each line */
while (*ptr) { /* parse number of elements in row <= ARRAY_WIDTH */
tmp = (int)strtol(ptr, &eptr, 10); /* convert value to integer */
if (ptr != eptr) { /* test that strtol processed chars */
ptr = eptr; /* set ptr to eptr for next value */
array [ridx][cidx] = tmp; /* assign value to array */
cidx++; /* increase column index */
} else {
break;
}
ptr++; /* skip space or comma separator */
}
ridx++; /* increase row index */
}
fclose (fp); /* close the file - done reading */
/* output values stored in array - 2 ways */
/* fist - use last value of cidx as column index */
int i = 0;
int j = 0;
printf ("\nProperties of Matrix Read\n\n");
printf (" size : %d\n rows : %d\n cols : %d\n\n", ridx * cidx, ridx, cidx);
for (i=0; i < ridx; i++)
{
printf (" [");
for (j = 0; j < cidx; j++)
{
printf (" %2d", array[i][j]);
}
printf (" ]\n");
}
/* second - by using calloc, only assigned values of array are not NULL, this */
/* allows iteration over row values without keeping an exact column index */
printf ("\nOutput without any column index:\n\n");
int *p;
for (i=0; i < ridx; i++)
{
printf (" [");
p = *(array + i); /* assign pointer to row of array */
while (*p) /* simply iterate until NULL encountered */
{
printf (" %2d", *p);
p++;
}
printf (" ]\n");
}
printf ("\n");
return 0;
}
<强>输入强>
$ cat dat/intarray.txt
50 10 21 31 19 22
9 34 32 17 99 91
82 56 78 11 88 2
6 14 24 48 64 3
<强>输出:强>
$ ./bin/a2dyn dat/intarray.txt
Properties of Matrix Read
size : 24
rows : 4
cols : 6
[ 50 10 21 31 19 22 ]
[ 9 34 32 17 99 91 ]
[ 82 56 78 11 88 2 ]
[ 6 14 24 48 64 3 ]
Output without any column index:
[ 50 10 21 31 19 22 ]
[ 9 34 32 17 99 91 ]
[ 82 56 78 11 88 2 ]
[ 6 14 24 48 64 3 ]