Первые баллы:
while(!feof(file))
{
Вы захотите посмотреть на Почему while (! Feof (file)) всегда неверно? .Кроме того, весь внешний цикл является излишним для вашего кода и может быть просто удален.
С любой из функций семейства 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
целых чисел, а начальный адрес для каждого выделения назначен каждому из указателейчтобы разрешить индексирование в виде двумерного массива)
Примеры входных файлов
Использование примера ввода с недопустимым 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
Код прокомментирован, чтобы помочь вам следовать.Если у вас есть какие-либо вопросы, просто дайте мне знать.