我的任务是从文本文件中读取矩阵,并找出它是否是一个魔方,我还必须确保矩阵的所有条目都是整数,如果不是,则必须写入标准输出错误消息,同时还描述了发生此错误的位置。
现在,我成功读取了矩阵的所有元素,但是验证是否为整数还是有问题。
我使用了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”时,它将仅针对a [1] [1]但会显示ERROR消息,但它将9替换为48。
当我有一个字符时(如本例所示),它将同时显示a [1] [1]('a')和a [1] [2]('9')的错误消息,并将其替换太。
我的问题是,为什么会发生这种情况?a [1] [1]和a [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];
答案 0 :(得分:2)
第一点:
while(!feof(file))
{
您将要查看Why is while ( !feof (file) ) always wrong?。此外,整个外部循环对于您的代码来说是多余的,可以轻松删除。
使用任何scanf
系列函数,如果输入与格式字符串中使用的转换说明符不匹配,则匹配失败发生,从输入流中提取字符时会在失败时停止,导致失败的有问题字符留在输入流中(未读),只是在等待下一次尝试读取时咬住您。尝试将'a'
读取为int
类型为scanf
的{{1}}会导致匹配失败。
如何处理匹配失败?
由于您始终验证所有用户输入,因此,当返回值小于指定的转换次数(或scanf
)时,就会检测到EOF
的输入失败。每次在循环中使用fscanf
读取一个整数,可以从行/列的角度准确地告诉您在读取方阵数据时发生输入故障的位置。知道发生故障的位置,您可以输出遇到无效数据的行/列。
要捕获无效数据以作报告之用,您可以简单地向前扫描fgetc
一次读取一个字符,并用有问题的字符填充缓冲区,直到下一个有效的digit
或{{1 }}(遇到数字的显式符号)(如果您想继续读取其他值,可以在此时使用+/-
将有效数字(或符号)放回输入流中>
简短示例
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;
}
来分配{{1} }分配了指针和一个int
整数块,并将每个分配的起始地址分配给每个指针,以允许将其作为2D数组进行索引。
示例输入文件
使用示例输入中dim
处的dim
无效:
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]
对代码进行注释以帮助您遵循。如果您有任何疑问,请告诉我。
答案 1 :(得分:1)
代码的关键问题:当fscanf遇到错误时,FILE指针不会向前移动。您需要使用fseek使其前进。
您需要研究的一些问题:
- 如何分配足够大小的数组以正确读取所有输入
- 基于文件的错误处理以及如何在使用fscanf读取时遇到错误时如何将FILE指针向前移动。 我的以下代码认为 仅存在单个不正确字符的特定情况, 如果有多个字符,则必须适当处理 礼物。
- 您无需同时执行fgets和fscanf。只有一个就足够了。
- 请看,如果您真的想使用fscanf。使用与FILE相关的其他读取方法,可以实现相同的逻辑。
严格地将以下代码作为伪代码进行处理,仅给出一些指示。这根本不能处理所有条件。您需要处理代码的许多方面,并处理其他错误条件等。我刚刚为您提供了如何解决它的指导。
#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 :(得分: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;
}
4
10 3 13 8
5 16 2 11
4 9 7 14
15 6 12 1
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.