使用fscanf()扫描到C

时间:2017-10-16 02:04:52

标签: c arrays

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

"文字文件"

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 个答案:

答案 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个整数(前两行各占一个),表示要跟随的rowscols数据的数量。然后,您会在您的矩阵中看到rowscols个数字。您的第一个决定将是“我如何处理存储?” (动态分配,或者数据是否足够小,如果我对矩阵使用可变长度数组(VLA),它将不会StackOverflow?)

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

首先,您如何从文件中挑选(读取)rowcol值?虽然fgets是迄今为止做面向行的输入的首选方式,但实际上您可以在row的一次调用中同时获得colfprintf,并享有额外的好处在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,其大小32-charscol个值要读取(这应该超过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扩展,则动态内存分配是另一种选择,如另一个答案所述。