#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static void
read_file(const char *fname)
{
FILE *f;
char line[1024];
int lineno, int1, int2, nbytes;
double dbl;
if ((f = fopen(fname, "r")) == NULL) {
perror("fopen");
exit(EXIT_FAILURE);
}
for (lineno = 1; fgets(line, sizeof line, f) != NULL; lineno++) {
int fields = sscanf(line, " %d %d %lg %n", &int1, &int2, &dbl, &nbytes);
if (fields != 3 || (size_t) nbytes != strlen(line)) {
fprintf(stderr, "E: %s:%d: badly formatted data\n", fname, lineno);
exit(EXIT_FAILURE);
}
/* do something with the numbers */
fprintf(stdout, "number one is %d, number two is %d, number three is %f\n", int1, int2, dbl);
}
if (fclose(f) == EOF) {
perror("fclose");
exit(EXIT_FAILURE);
}
}
int main(void)
{
read_file("filename.txt");
return 0;
}
Некоторые примечания к коду:
- Функцию
fscanf
довольно сложно использовать.Мне пришлось немного поэкспериментировать, пока я не понял это правильно.Пробелы между %d
и %lg
необходимы для пропуска любого пробела между числами.Это особенно важно в конце строки, где символ новой строки должен быть прочитан. - Большая часть кода связана с тщательной проверкой ошибок.Почти каждое возвращаемое значение вызова функции проверяется, успешно оно или нет.Кроме того, количество полей и количество прочитанных символов сравниваются с ожидаемыми значениями.
- Строки формата для
fscanf
и fprintf
отличаются тонкими деталями.Обязательно прочитайте для них документацию. - Я использовал комбинацию
fgets
для чтения по одной строке за раз и sscanf
для разбора полей.Я сделал это, потому что мне казалось невозможным сопоставить один \n
с использованием fscanf
. - Я использовал компилятор GNU C со стандартными флагами предупреждений
-Wall -Wextra
.Это помогло избежать некоторых простых ошибок.
Обновление: Я забыл проверить, что каждый вызов fgets
читает ровно одну строку.Там могут быть строки, которые слишком длинные, чтобы поместиться в буфер.Следует убедиться, что строка всегда заканчивается \n
.