Когда / почему плохая идея использовать функцию fscanf ()? - PullRequest
6 голосов
/ 14 мая 2009

В ответе было интересное утверждение: «Почти всегда - плохая идея использовать функцию fscanf(), поскольку она может оставить указатель вашего файла в неизвестном месте на ошибка. Я предпочитаю использовать fgets() для ввода каждой строки, а затем sscanf(), что. "

Не могли бы вы рассказать, когда и почему может быть лучше использовать fgets() и sscanf() для чтения какого-либо файла?

Ответы [ 6 ]

13 голосов
/ 14 мая 2009

Представьте себе файл с тремя строками:

   1
   2b
   c

Используя fscanf() для чтения целых чисел, первая строка будет читаться нормально, но во второй строке fscanf() оставит вас на «b», не зная, что делать дальше. Вам понадобится какой-то механизм, чтобы пройти через ввод мусора, чтобы увидеть третью строку.

Если вы введете fgets() и sscanf(), вы можете гарантировать, что указатель вашего файла перемещает строку за раз, с чем немного легче справиться. В общем, вы все равно должны смотреть на всю строку, чтобы сообщить о любых нечетных символах в ней.

Я предпочитаю последний подход сам, хотя я не согласен с утверждением, что "почти всегда плохая идея использовать fscanf()" ... fscanf() идеально подходит для большинства вещей.

4 голосов
/ 15 мая 2009

Случай, когда это вступает в игру, - это когда вы сопоставляете литералы символов. Предположим, у вас есть:

int n = fscanf(fp, "%d,%d", &i1, &i2);

Рассмотрим два возможных входа "323,A424" и "323A424".

В обоих случаях fscanf() вернет 1, а следующий прочитанный символ будет 'A'. Невозможно определить, была ли найдена запятая или нет.

Это, как говорится, имеет значение, только если важно найти фактический источник ошибки. В случаях, когда достаточно знать, что ошибка ввода неверна, fscanf() на самом деле лучше, чем написание собственного кода синтаксического анализа.

2 голосов
/ 14 марта 2014

Есть две причины:

  • scanf() может оставить stdin в состоянии, которое трудно предсказать; это затрудняет восстановление ошибок, если не делает невозможным (это меньше проблем с fscanf()); и
  • Все семейство scanf() принимает указатели в качестве аргументов, но без ограничения длины, поэтому они могут переполнять буфер и изменять несвязанные переменные, которые оказываются после буфера, вызывая кажущиеся случайными ошибки повреждения памяти, которые очень трудно понять, найти и отладка, особенно для менее опытных C программистов.

Новичок C Программисты часто путают указатели и оператор «address-of» и часто пропускают & там, где это необходимо, или добавляют его «для хорошей меры», где это не так. Это приводит к «случайным» сегментам ошибок, которые им трудно найти. Это не вина scanf(), поэтому я исключаю это из своего списка, но это стоит иметь в виду.

Спустя 23 года я все еще помню, что это было огромной болью, когда я начал программировать C , и не знал, как распознавать и устранять ошибки такого рода, и (как кто-то, кто потратил годы на обучение C новичкам), очень трудно объяснить их новичку, который еще не понимает указатели и стек.

Любой, кто рекомендует scanf() новичку C , должен безжалостно пороть.

ОК, может быть, не беспощадно , но определенная порка определенно нужна; о)

2 голосов
/ 14 мая 2009

При сбое функции fscanf () из-за ошибки ввода или ошибки сопоставления указатель файла (то есть позиция в файле, из которой будет считан следующий байт) остается в позиции, отличной от той, в которой он будет быть FSCANF () успешно. Обычно это нежелательно при последовательном чтении файлов. Чтение одной строки за раз приводит к предсказуемости ввода файла, в то время как сбои одной строки могут обрабатываться индивидуально.

1 голос
/ 15 мая 2009

Почти всегда плохая идея использовать функцию fscanf(), поскольку она может оставить указатель вашего файла в неизвестном месте при ошибке. Я предпочитаю использовать fgets() для ввода каждой строки, а затем sscanf(), что.

Вы всегда можете использовать ftell(), чтобы узнать текущую позицию в файле, а затем решить, что делать дальше. По сути, если вы знаете, что можете ожидать, используйте fscanf().

.
0 голосов
/ 14 мая 2009

По сути, невозможно сказать, что функция , а не выходит за пределы области памяти, выделенной для нее.

Появился ряд замен, например, fnscanf, который пытается исправить эти функции, указав максимальный лимит для записи для читателя, что позволяет ему не переполняться.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...