使用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数。 然后,您将在列表中读取rowscols 。 您的第一个决定将是“我如何处理存储?” (动态分配,或者数据是否足够小,如果我对矩阵使用可变长度数组(VLA),它将不会StackOverflow?)

使用VLA消除了动态分配,跟踪和释放内存的需要,但您必须知道您不需要存储比堆栈上可容纳的更多的double值。 以下假设您的VLA值小于100,000左右,使VLA成为有效选项。

首先,您将如何从文件中拾取(读取) rowcol值? 虽然fgets是迄今为止做面向行的输入的首选方式,但实际上你可以在一次调用fprintf同时获得rowcol ,并且在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

拥有rowcol值后,您现在可以调整缓冲区大小以使用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; }