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
Другие вопросы по тегам