Вы не показываете, как true
установлено в while(true)
, но оно должно основываться на возврате fscanf
в способе, которым вы приближаетесь к нему.Вы должны проверить три случая:
fscanf
возврат равен EOF
, чтение выполнено, true
должно быть установлено на FALSE
для разрыва цикла; fscanf
вернуть менее 4
, совпадение или ошибка ввода , нет гарантии, что это произошло из-за пустой строки;и fscanf
возврат равен 4
, хороший ввод.
Если вы не проверяете все три, вы не можете охватить все случаи для fscanf
и далее, есливо входном файле есть какой-либо дополнительный или посторонний символ, отформатированное чтение не будет выполнено.
Поэтому лучшим вариантом является чтение каждой строки в буфер с помощью fgets
, а затем анализировать необходимую информацию из самого буфера с sscanf
.Это обеспечивает преимущество отдельной проверки (1) чтения;и (2) анализ информации.Кроме того, поскольку вы используете строку за раз, нет никакой неопределенности относительно того, что остается во входном потоке, и сбой при синтаксическом анализе какой-либо одной строки не препятствует успешному чтению остатка.
Короткая реализация с fgets()
и sscanf()
чтением каждой структуры в массив структуры, вы можете сделать что-то похожее на следующее:
#include <stdio.h>
#define MAXN 11 /* if you need a constant, #define one (or more) */
#define MAXC 1024 /* (don't skimp on buffer size) */
typedef struct { /* use a simple typedef */
int id, potencia, avariado;
char name[MAXN];
} carro_t;
int main (int argc, char **argv) {
char buf[MAXC]; /* buffer to read line */
carro_t carro[MAXN] = {{ .id = 0 }}; /* array of struct */
size_t ndx = 0; /* array index */
/* 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;
}
while (ndx < MAXN && fgets (buf, MAXC, fp)) { /* read each line */
carro_t tmp = { .id = 0 }; /* temp struct */
if (*buf == '\n') /* if line empty */
continue; /* get next line */
if (sscanf (buf, "%d %d %d %10[^\n]", /* separate/validate */
&tmp.id, &tmp.potencia, &tmp.avariado, tmp.name) == 4)
carro[ndx++] = tmp; /* add to array of struct */
}
if (fp != stdin) fclose (fp); /* close file if not stdin */
for (size_t i = 0; i < ndx; i++)
printf ("%3d %3d %3d %s\n",
carro[i].id, carro[i].potencia, carro[i].avariado, carro[i].name);
return 0;
}
( note: theимя_файла предоставляется в качестве первого аргумента программы, или, если имя файла не указано, по умолчанию считывается stdin
Хотя с вашим конкретным файлом данных нет причин, по которым вы не можете использовать fscanf
,оно хрупкое и слишком много символов (например, "Anne Belgss"
) приведут к его поломке.Реализация fscanf
, удаляющая true
и просто зацикливающаяся, как вы могли бы быть:
for (;;) {
carro_t tmp = { .id = 0 };
if (fscanf (fp, "%d %d %d %10[^\n]", /* separate/validate */
&tmp.id, &tmp.potencia, &tmp.avariado, tmp.name) == 4)
carro[ndx++] = tmp; /* add to array of struct */
else
break;
}
В любом случае, вы получите тот же вывод с «этим» входным файлом, например,
Пример использования / Вывод
$ ./bin/readwblanks ~/tmpd/file
1 111 1 Peter
22 22 2 John Lays
3 3 3 Anne Belgs