如何解决)的fscanf的误差(,检查是否在矩阵的元素是一个整数或者不是在C

问题描述 投票:0回答:3

我任务是从文本文件中读取一个矩阵,并找出它是否是一个神奇的广场,我也有,以确保矩阵的所有条目是整数,如果不是我写的标准输出错误信息同时,也说明这里发生了此错误的位置。

现在,我成功地读取矩阵的所有元素,但我与验证一个问题,如果它是一个整数或没有。

我用的fscanf(),因为我知道,在成功返回它成功地正确读元素的数量,并返回EOF,否则为0。

这里是矩阵:

3
12 3 87
78 a 9
45 0 23

第一元件是行数和列数。

这里是我的代码(我需要帮助的至少部分)

while(!feof(file))
{
    while ( fgets(buffer, sizeof(buffer), file) )
    {

        for ( int j = 0; j < n; j++ )
        {
            if ( i == n )
            {
                break;
            }

            m = fscanf(file, "%d", &a[i][j]);
            printf("\n%d", m);

            if ( m == 0 || m == EOF )
            {
                printf("\nERROR, %d, %d, %d \n", i, j, a[i][j]);
            }

        }
        i++; 

    }



}

这里是我的输出(现在我只是想弄清楚这个问题,所以这不是它怎么会看后面):

1
1
1
1
0
ERROR, 1, 1, 0

0
ERROR, 1, 2, 48

1
1
1
12 3 87
78 0 48
45 0 23

当我替换“A”与一些类型(浮点)的例如,将显示错误消息只为[1] [1],但它会与48取代9。

当我有一个字符(如在这种情况下),将显示错误消息既为一个[1] [1]( 'a')和一个[1] [2]( '9'),并替换它。

我的问题是,为什么会发生这种情况和什么[1] [1]和[1] [2]以及如何解决它的地狱发生。

编辑:我知道我可以简单地退出程序时,我发现1例,但我对为什么会发生这种错误发生真的很好奇。

fscanf(file, "%d", &n );//I read the first integer, which is also the maximum  capacity of my 2d array

int a[n][n];
c scanf
3个回答
1
投票

你的代码的关键问题:你的文件指针不动时,前方遇到的fscanf错误。您需要提前使用FSEEK移动。

一些你需要看的问题:

  • 如何分配足够大小的阵列,以正确地读出所有的输入
  • 基于文件的错误处理,以及如何向前移动文件指针是否在使用的fscanf读取命中一个错误。我下面的代码只考虑单一不正确的字符存在的特定情况下,你必须妥善处理这个问题,如果超过一个字符的情况下。
  • 没有必要为你做既fgets和的fscanf。只有一个就足够了。
  • 重新审视,如果你真的想使用的fscanf。相同的逻辑可使用到的文件的相关其他读取方法来实现。

严格把下面的代码作为一个伪代码,只是给一些迹象。这完全不处理所有条件。您需要在很多代码方面的工作,并处理其他错误条件等。我刚才给你如何能解决它的指针。

#include <stdio.h>
#include <stdlib.h>

int main(void)
{

  FILE *f = fopen("./check.txt", "r");
  int a[3][3] = {0};
  int n, res, i;

  res = fscanf(f, "%d", &n);

  i = 0;
  while(i<n)
  {
    for(int j = 0; j < n; j++)
    {
       int val = 0;
       res = fscanf(f, "%d", &val);
       if ((res == 0) || (res == EOF))
       {
           printf("Error: res = %d for i = %d, j = %d, val = %d\n", res, i, j, val);
           fseek(f, 1, SEEK_CUR);
       }
       else
           a[i][j] = val;
    }
    i++;

  }

  printf("The Matrix\n");
  for(int i = 0; i<n; i++)
  {
    for (int j=0; j<n; j++)
        printf("%d ", a[i][j]);
    printf("\n");
  }

}

输出:

Error: res = 0 for i = 1, j = 1, val = 0
The Matrix
12 3 87
78 0 9
45 0 23

2
投票

第一点:

while(!feof(file))
{

你会想看看Why is while ( !feof (file) ) always wrong?。此外,整个外环是多余的代码,并可以简单地删除。

与任何scanf系列函数,当输入不匹配格式字符串所使用的转换说明时,发生匹配失败,从输入流中字符提取停止在故障点,导致故障的问题的字符被留在输入流(读)就等着咬你在你的下一个尝试的读。试图读取'a'int类型scanf产生匹配失败。

如何处理一个匹配失败?

因为你总是验证所有的用户输入,为您注意,您检测输入故障与scanf当返回小于指定转换次数(或EOF)。在你的循环中fscanf一次读取一个整数告诉你究竟在何处输入故障从行/列的角度读取数据的方阵价值时发生。知道哪里发生故障,您可以输出,其中遇到的无效数据的行/列。

要捕获无效数据报告的目的,你可以简单地用fgetc每次读一个字符,填充违规字符缓冲区,直到下一个有效的digit+/-(明确的标志为一个数字)遇到向前扫描(可以使用ungetc在这一点上把有效位数(或签字)回到输入流中,如果你的想继续阅读其他值)

简单例子

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

#define MAXC 1024

int main (int argc, char **argv) {

    int **m = NULL;
    unsigned dim = 0;
    /* use filename provided as 1st argument (stdin by default) */
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;

    if (!fp) {  /* validate file open for reading */
        perror ("file open failed");
        return 1;
    }

    if (fscanf (fp, "%u", &dim) != 1) { /* read square mtrx dim */
        fputs ("error: invalid format, no dimension.\n", stderr);
        return 1;
    }

    if (!(m = malloc (dim * sizeof *m))) {  /* allocate/validate dim ptrs */
        perror ("malloc-m");
        return 1;
    }

    for (unsigned i = 0; i < dim; i++)   /* allocate dim rows of dim int */
        if (!(m[i] = calloc (dim, sizeof *m[i]))) { /* zero mem w/calloc */
            perror ("calloc-m[i]");
            return 1;
        }

    for (unsigned i = 0; i < dim; i++)              /* for each row */
        for (unsigned j = 0; j < dim; j++) {        /* for each col */
            if (fscanf (fp, "%d", &m[i][j]) != 1) { /* read/validate int */
                char buf[MAXC], *p = buf;   /* buf and ptr to buf */
                int c;                      /* int for char */
                /* read while !EOF, not digit and not -/+ */
                while ((c = fgetc(fp)) != EOF && (c < '0' || '9' < c) &&
                        c != '-' && c != '+')
                    if (!isspace(c))    /* if not a space */
                        *p++ = c;       /* store offending char(s) */
                *p = 0;                 /* nul-terminate buf */
                if (c != EOF)           /* if c a char - put it back */
                    ungetc(c, fp);
                /* output location of invalid input */
                printf ("error: m[%d][%d] - invalid entry '%s'.\n",
                        i, j, buf);
                return 1;   /* and bail - or continue -- your choice */
            }
        }
    if (fp != stdin) fclose (fp);   /* close file if not stdin */

    for (unsigned i = 0; i < dim; i++) {    /* for each row */
        for (unsigned j = 0; j < dim; j++)  /* for each col */
            printf (" %3d", m[i][j]);       /* output value */
        putchar ('\n');                     /* output newline */
        free (m[i]);                        /* free ints in row */
    }
    free (m);   /* free pointers */

    return 0;
}

(注:你没有说你怎么分配的存储空间,所以一个简单的指针指向int被用来分配dim指针和dim整数块被分配和起始地址是分配给每台指针的每一个分配,使索引作为2D阵列)

例如输入文件

使用您的示例输入与int无效[1][1]

$ cat ~/tmpd/mtrx.txt
3
12 3 87
78 a 9
45 0 23

具有良好的价值观的一个例子:

$ cat ~/tmpd/mtrxgood.txt
3
12 3 87
78 8 9
45 0 23

实施例使用/输出

随着在int无效[1][1]

该程序正确报告位置和违规性质:

$ ./bin/readsquaremtrx ~/tmpd/mtrx.txt
error: m[1][1] - invalid entry 'a'.

具有良好的值,所有的值被读出和所有已分配的存储器之前打印在屏幕上的矩阵被释放:

$ ./bin/readsquaremtrx ~/tmpd/mtrxgood.txt
  12   3  87
  78   8   9
  45   0  23

该代码被注释掉,以帮助你跟随。如果您有任何问题,只是让我知道。


1
投票

使用,而不是指针的有点低效“阵列”的指针平面存储器区域中的另一示例:

#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>

int is_magic_square(int *square, size_t dimension)
{
    if(dimension < 3) {
        return 0;
    }

    int prev_row_sum;
    int prev_col_sum;
    int d1_sum = 0;
    int d2_sum = 0;

    for (size_t y = 0; y < dimension; ++y) {
        int curr_row_sum = 0;
        int curr_col_sum = 0;
        for (size_t x = 0; x < dimension; ++x) {
            curr_row_sum += square[y * dimension + x];
            curr_col_sum += square[x * dimension + y];

            if (x == y) {
                d1_sum += square[y * dimension + x];
                d2_sum += square[y * dimension + dimension - 1 - x];
            }
        }

        if (y && (curr_row_sum != prev_row_sum || curr_col_sum != prev_col_sum)) {
            return 0;
        }

        prev_row_sum = curr_row_sum;
        prev_col_sum = curr_col_sum;
    }

    return prev_row_sum == d1_sum && prev_row_sum == d2_sum ? prev_row_sum : 0;
}

int main(void)
{
    char const *filename = "test.txt";
    FILE *input = fopen(filename, "r");
    if (!input) {
        fprintf(stderr, "Couldn't open \"%s\" for reading :(\n\n", filename);
        return EXIT_FAILURE;
    }

    size_t dimension;
    if (fscanf(input, " %zu", &dimension) != 1) {
        fprintf(stderr, "Faild to read squares dimensions from \"%s\" :(\n\n", filename);
        fclose(input);
        return EXIT_FAILURE;
    }

    int result = EXIT_FAILURE;
    printf("Reading a %zu x %zu square from \"%s\" ...\n\n", dimension, dimension, filename);

    int *square = calloc(dimension * dimension, sizeof(*square));
    if (!square) {
        fputs("Not enough memory :(\n\n", stderr);
        goto cleanup;
    }

    for (size_t y = 0; y < dimension; ++y, putchar('\n')) {
        for (size_t x = 0; x < dimension; ++x) {
            int value;
            if (fscanf(input, " %d", &value) != 1 || value < 1) {
                fprintf(stderr, "\n\nFailed to read value at (%zu, %zu) from \"%s\" :(\n\n",
                        x + 1, y + 1, filename);
                goto cleanup;
            }

            for (size_t pos = 0; pos < y * dimension + x; ++pos) {
                if (square[pos] == value) {
                    fprintf(stderr, "\n\nDuplicate value %d found at (%zu, %zu) in \"%s\" :(\n\n",
                            value, x + 1, y + 1, filename);
                    goto cleanup;
                }
            }

            if(value > dimension * dimension) {
                fprintf(stderr, "\n\nValue %d at (%zu, %zu) in \"%s\" is out of range 1, 2, ..., %zu^2 :(\n",
                        value, x + 1, y + 1, filename, dimension);
                goto cleanup;
            }

            printf("%4d ", value);
            square[y * dimension + x] = value;
        }
    }

    int sum = is_magic_square(square, dimension);
    printf("\nThis %s a perfect square!\n", sum ? "is" : "is not");

    if (sum) {
        printf("It's sum is %d.\n", sum);
    }

    putchar('\n');
    result = EXIT_SUCCESS;

cleanup:
    free(square);
    fclose(input);
    return result;
}

Sample Input:

4
10    3   13    8
 5   16    2   11
 4    9    7   14
15    6   12    1

Sample Output:

Reading a 4 x 4 square from "test.txt" ...

  10    3   13    8
   5   16    2   11
   4    9    7   14
  15    6   12    1

This is a perfect square!
It's sum is 34.
© www.soinside.com 2019 - 2024. All rights reserved.