Fscanf перемещает указатель файла назад?
Это содержимое моего файла 'unsorted.txt':
3 Роберт Джастин Трамп
Это мой код:
#include <stdio.h>
int main(void) {
FILE *f = fopen("unsorted.txt", "r");
char n;
printf("%d\n", ftell(f));
fscanf(f, "%s", &n);
int l = n - '0';
printf("%d %d\n", l, ftell(f));
return 0;
}
при исполнении он дает следующий вывод:
0
3 -1
почему он вернулся -1
во втором случае? Это должно двигаться от 0
в 1
право?
ПРИМЕЧАНИЕ: файл может быть открыт, потому что тогда как он будет печатать 0 при первом вызове и первый символ из файла без возможности открытия?
2 ответа
fscanf(f,"%s",&n);
очень неправильно, так как вы объявили char n;
(только одного байта). Вы получили неопределенное поведение. Быть очень напуганным (и в следующий раз стыдно).
Рекомендую:
Проверьте это fopen
не подведи
FILE *f = fopen("unsorted.txt","r");
if (!f) { perror("fopen unsorted.txt"); exit(EXIT_FAILURE); };
Объявите буфер разумного размера (80 было размером перфокарт в 1970-х).
char buf[80];
очистите его (вы хотите защитное программирование):
memset(buf, 0, sizeof(buf));
Тогда внимательно прочитайте о fscanf. Прочитайте эту документацию несколько раз. Используйте его с фиксированным размером и проверьте его результат:
if (fscanf(f, "%72s", buf) > 0) {
(72 был применимым размером в программах перфокарт PL/1; он меньше 80)
Не забудьте прочитать документацию по другим функциям, включая ftell.
Важный совет:
компилировать все предупреждения и отладочную информацию (gcc -Wall -Wextra -g
с GCC), улучшите код, чтобы не получать предупреждений, используйте отладчик gdb
запустить его шаг за шагом.
PS. В качестве упражнения найдите возможное содержание unsorted.txt
что заставило вашу начальную программу работать правильно. Не могли бы вы в этом случае предсказать его выход? Если нет, то почему?
В вашем коде несколько проблем:
Вы не проверяете возвращаемое значение
fopen()
, призваниеftell()
сNULL
указатель имеет неопределенное поведение. Вы не можете делать выводы из наблюдаемого поведения.printf("%d\n", ftell(f));
неверно, потому что возвращаемое значениеftell()
этоlong
, Вы должны использовать формат%ld
,fscanf(f, "%s", &n);
неверно, потому что вы передаете адрес одногоchar
заfscanf()
для хранения строки с нулевым символом в конце.fscanf()
будет иметь доступ к памяти за пределы размераchar
, который имеет неопределенное поведение. Определить массивchar
такие какchar buf[80];
и передать максимальное количество символов для хранения как:fscanf(f, "%79s", buf);
и проверьте возвращаемое значение, или используйте%c
читать один байт.int l = n - '0';
не является строго неправильным, но подвержен ошибкам: избегайте именования переменныхl
как это выглядит до степени смешения1
,printf("%d %d\n", l, ftell(f));
неверно как предыдущий звонокprintf
: использовать спецификатор конверсии%ld
для возвращаемого значенияftell()
,
Обратите внимание, что возвращаемое значение ftell()
в текстовом потоке не обязательно смещение байта в файле.
Вот исправленная версия:
#include <stdio.h>
int main(void) {
FILE *f = fopen("unsorted.txt", "r");
char c;
if (f != NULL) {
printf("%ld\n", ftell(f));
if (fscanf(f, "%c", &c) == 1) {
int diff = c - '0';
printf("%d %ld\n", diff, ftell(f));
}
}
return 0;
}
Выход:
0
3 1