【问题标题】:Problems using fscanf() to scan into an array in C使用 fscanf() 扫描到 C 中的数组时出现问题
【发布时间】:2017-10-16 02:04:52
【问题描述】:

我正在扫描一个文本文件。文件中的第一个数字是矩阵中的行数,第二个数字是矩阵中的列数。

“文本文件”

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[^ ,]"...)。我收到了相同的输出。请让我知道出了什么问题以及如何解决它。

【问题讨论】:

  • array 是如何定义的?
  • 我最初认为 fscanf 遇到了逗号问题:是的。你是对的。使用fscanf(fpointer,"%lf,",&amp;hold); 丢弃逗号
  • 查看fscanf的返回码。返回 0 => 无法读取数据
  • 谢谢,修复逗号解决了我的问题。

标签: c arrays


【解决方案1】:

您可以采取多种方法。这里的关键是你知道你将有 2 个整数(前两行各一个)代表要遵循的 rowscols 的数据数量。然后您将在矩阵中读取rowscols 数量。您的第一个决定将是“我如何处理存储?” (动态分配,或者如果我对矩阵使用可变长度数组(VLA),数据是否足够小它不会StackOverflow?)

使用 VLA 消除了动态分配、跟踪和释放内存的需要,但您必须知道您不需要存储超出堆栈容量的double 值。以下假设您的值小于 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;
}

注意:space"%d %d " 中最后一个转换说明符之后)

有了rowcol 值,您现在可以调整缓冲区的大小,以使用fgets 读取文件中剩余的每一行。将每一行读入缓冲区后,将使用strtod 从缓冲区解析每列值,并根据col 值验证解析的值的数量,以确保填充矩阵的完整行。行缓冲区是一个 VLA,每个要读取的 col 值的大小也是 32-chars50% 应该绰绰有余)。使用 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 扩展,动态内存分配是您的另一个选择,如另一个答案中所述。

【讨论】:

    【解决方案2】:

    您需要处理逗号。这是一种方法:

    #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;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-10-14
      • 2016-03-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多