C пока не конец файла while fin eof

Обновлено: 04.07.2024

что не так с этим while( !feof(fp)) петли?

я хотел бы предоставить абстрактную перспективу высокого уровня.

параллелизма и одновременности

операции ввода-вывода взаимодействуют с окружающей средой. Окружающая среда не является частью вашей программы и не находится под вашим контролем. Среда действительно существует "одновременно" с вашей программой. Как и все параллельные вещи, вопросы о " текущем состоянии "не имеют смысла: нет понятия" одновременности " между параллельными событиями. Многие свойства состояния просто не exist по совместительству.

позвольте мне сделать это более точным: Предположим, вы хотите спросить: "у вас есть больше данных". Вы можете задать этот вопрос параллельному контейнеру или вашей системе ввода-вывода. Но ответ, как правило, unactionable, и, следовательно, бессмысленно. Так что, если контейнер говорит "да" – к тому времени, когда вы попытаетесь прочитать, у него может больше не быть данных. Аналогично, если ответ "нет", к тому времени, когда вы попытаетесь прочитать, данные могут прибыть. Вывод состоит в том, что там просто и нет такого свойства, как "у меня есть данные", так как вы не можете действовать осмысленно в ответ на любой возможный ответ. (Ситуация немного лучше с буферизованным вводом, где вы можете предположительно получить "да, у меня есть данные", что представляет собой некоторую гарантию, но вам все равно придется иметь дело с противоположным случаем. И с выходом ситуация, безусловно, так же плоха, как я описал: вы никогда не знаете, заполнен ли этот диск или этот сетевой буфер.)

так мы сделать вывод, что это невозможно, и на самом деле unразумный, чтобы спросить систему ввода-вывода, является ли это будет возможность выполнения операции ввода-вывода. Единственный возможный способ взаимодействия с ним (как и с параллельным контейнером) - это попытка операция и проверьте, удалось ли это или не удалось. В тот момент, когда вы взаимодействуете с окружающей средой, тогда и только тогда вы можете знать, было ли взаимодействие действительно возможным, и в этот момент Вы обязан выполнять взаимодействие. (Это" точка синхронизации", если хотите.)

теперь мы доберемся до EOF. ВФ-это ответ вам попытка операции ввода-вывода. Это означает, что вы пытались что-то прочитать или написать, но при этом вам не удалось прочитать или записать какие-либо данные, а вместо этого был обнаружен конец ввода или вывода. Это верно для практически всех API ввода - вывода, будь то C стандартная библиотека, iostreams C++ или другие библиотеки. Пока операции ввода-вывода успешны, вы просто не знаю ли дальше, будущие операции будут успешными. Вы должны всегда сначала попробовать операцию, а затем реагировать на успех или неудачу.

примеры

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

C stdio, читать из файла:

результат, который мы должны использовать, это n , количество элементов, которые были прочитаны (что может быть всего лишь ноль).

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

C++, отформатированное извлечение iostreams:

результат, который мы должны использовать, это std::cin сам, который может быть оценен в булевом контексте и сообщает нам, находится ли поток все еще в good() государство.

C++, iostreams getline:

результат, который мы должны использовать, снова std::cin , так же как и раньше.

POSIX, write(2) to промывочный буфер:

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

результат, который мы должны использовать, это nbytes количество байт, включая символ новой строки (или EOF если файл не заканчивается переводом строки).

отметим, что функция явно возвращает -1 (и не EOF!) когда происходит ошибка или она достигает EOF.

вы можете заметить, что мы очень редко пишем фактическое слово "EOF". Мы обычно обнаруживаем условие ошибки каким-то другим способом, который более интересен нам (например, неспособность выполнить столько ввода/вывода, сколько мы хотели). В каждом примере есть некоторая функция API, которая может явно сказать нам, что состояние EOF было обнаружено, но это на самом деле не очень полезная информация. Это гораздо больше детали,чем мы часто заботимся. Важно то, что I/O преуспел больше, чем то, как он потерпел неудачу.

последний пример, который фактически запрашивает состояние EOF: Предположим, у вас есть строка и вы хотите проверить, что она представляет целое число целиком, без дополнительных битов в конце, кроме пробелов. Используя C++ iostreams, он выглядит так:

мы используем два результата здесь. Первый is iss , сам объект потока, чтобы проверить, что отформатированное извлечение в value удалось. Но затем, также потребляя пробелы, мы выполняем другую операцию ввода-вывода, iss.get() , и ожидайте, что он завершится ошибкой как EOF, что имеет место, если вся строка уже была потреблена отформатированным извлечением.

в стандартной библиотеке C вы можете добиться чего-то подобного с strto*l функции путем проверки что указатель конца достигал конец входного сигнала строка.

ответ

while(!eof) неправильно, потому что он проверяет что-то, что не имеет значения, и не может проверить что-то, что вам нужно знать. В результате вы ошибочно выполняете код, который предполагает, что он обращается к данным, которые были успешно прочитаны, когда на самом деле этого никогда не было.

это неправильно, потому что (при отсутствии ошибки чтения) он входит в цикл еще раз, чем ожидает автор. Если есть ошибка чтения, цикл никогда не завершается.

рассмотрим следующий код:

эта программа будет постоянно распечатывать один больше, чем количество символов во входном потоке (при условии отсутствия ошибок чтения). Рассмотрим случай, когда входной поток пуст:

в этом случае feof() вызывается перед любые данные были прочитаны, поэтому он возвращает false. Петля введена, fgetc() вызывается (и возвращает EOF ), и количество увеличивается. Тогда feof() вызывается и возвращает true, вызывая прерывание цикла.

это происходит во всех подобных случаях. feof() не возвращает true до после чтение в потоке встречает конец файла. Цель feof() не проверять, достигнет ли следующее чтение конца файла. Цель feof() различать между ошибкой чтения и дойдя до конца файла. Если fread() возвращает 0, вы должны использовать feof / ferror решать. Аналогично, если fgetc возвращает EOF . feof() только полезным после fread вернул ноль или fgetc вернулся EOF . Прежде чем это произойдет, feof() всегда будет возвращать 0.

всегда необходимо проверить возвращаемое значение чтения (либо fread() или fscanf() или fgetc() ) перед вызовом feof() .

еще хуже, рассмотрим случай, когда происходит ошибка чтения. В таком случае . --3--> возвращает EOF , feof() возвращает false, и цикл никогда не завершается. Во всех случаях, где while(!feof(p)) используется, должна быть по крайней мере проверка внутри цикла для ferror() , или, по крайней мере, условие while должно быть заменено на while(!feof(p) && !ferror(p)) или существует очень реальная возможность бесконечного цикла, вероятно, извергая всевозможный мусор, поскольку недопустимые данные обработанный.

while(!feof(f))" (хотя там должны еще одна проверка внутри цикла с перерывом, чтобы избежать бесконечного цикла при ошибке чтения), это так, что это почти наверняка всегда неправильно. И даже если когда-либо возникал случай, когда это было бы правильно, это настолько идиоматически неправильно, что это не было бы правильным способом написать код. Любой, кто видит этот код, должен немедленно колебаться и сказать: "это ошибка". И, возможно, ударить автора (если автор не является вашим боссом, и в этом случае рекомендуется усмотрение.)

нет, это не всегда так. Если ваше условие цикла "пока мы не пытались прочитать конец файла", то вы используете while (!feof(f)) . Однако это не общее условие цикла-обычно вы хотите проверить что-то еще (например, "могу ли я прочитать больше"). while (!feof(f)) Не неправильно, это просто использовать неправильно.

таким образом, правильной идиомой в C является цикл с успехом операции ввода-вывода Как условие цикла, и затем проверьте причину сбоя. Например:

отличный ответ, я просто заметил то же самое, потому что я пытался сделать такой цикл. Итак, это неправильно в этом сценарии, но если вы хотите иметь цикл, который изящно заканчивается на EOF, это хороший способ сделать это:

Мне сказали, что я должен использовать while(fin) вместо while(!fin.eof()) при чтении файла.

В чем именно разница?

Правка . Я знаю, что while(fin) на самом деле проверяет объект потока и что, когда он становится NULL, цикл прерывается и закрывает флаги eof и fail. Но мой преподаватель курса говорит, что fin.eof() лучше, поэтому мне нужно понять основную операцию, которая здесь происходит.

Какой из них является правильной практикой?

Примечание. Это не дубликат, мне нужна помощь в Turbo C ++ и в двоичных файлах. Я в основном пытаюсь прочитать файл, используя объект класса.

3 ответа

Прежде всего, я предполагаю, что fin является вашим fstream объектом. В этом случае ваш учитель не сказал бы вам использовать while(fin.eof()) для чтения из файла. Она бы сказала использовать while(!fin.eof()) .

Позволь мне объяснить. eof() является членом класса fstream , который возвращает значение true или false в зависимости от того, был ли достигнут конец файла (eof) файла, который вы читаете , Таким образом, хотя функция eof() возвращает 0 , это означает, что конец файла не достигнут и цикл продолжает выполняться, но когда eof() возвращает 1 , конец файла был Достигнута и петля выходит.

Цикл while(fin) введен, потому что fin фактически возвращает значение переменной флага ошибки внутри объекта класса fin , значение которого равно 0, когда любая функция, такая как чтение, запись или открытие, завершается неудачей. Таким образом, цикл работает до тех пор, пока работает функция чтения внутри цикла.

Лично я бы не предложил ни одного из них. Я бы предложил

// предположим, что класс abc.

Этот цикл читает запись файла внутри условия цикла, и если ничего не было прочитано из-за достижения конца файла, цикл завершается.

Проблема с while(!fin.eof()) состоит в том, что он возвращает 1 , если достигнут конец файла. Конец файла - это символ, который помещается в конец файла. Поэтому, когда функция чтения внутри цикла читает этот символ и устанавливает переменную eof в 1. Все, что фактически делает функция - это возвращает это значение.

Это прекрасно работает, когда вы читаете строки в словах, но когда вы читаете последовательные записи класса из файла, этот метод завершится ошибкой. Рассматривать

Таким образом отображается последняя запись дважды. Это связано с тем, что символ конца файла является символом после последнего байта последней записи. Когда последний прочитан, указатель файла находится в байте eof, но еще не прочитал его. Таким образом, он снова войдет в цикл, но на этот раз eof char будет прочитан, но функция read не будет выполнена. Значения уже в переменной a , то есть предыдущие записи, будут отображены снова.

Один хороший метод - сделать что-то вроде этого:

Или в случае текстового файла:

Здесь объект читается в условии условия цикла while, а затем проверяется значение флага eof . Это не приведет к нежелательным результатам.

Здесь мы проверяем состояние фактической операции ввода-вывода и eof вместе. Вы также можете проверить флаг сбоя.

Я хотел бы отметить, что согласно @RetiredNinja, мы можем проверять только операцию ввода-вывода. Это:

Быстрый и простой обходной путь, который помог мне избежать проблем при использовании eof, - это проверить его после первого чтения, а не как условие самого цикла while. Что-то вроде этого:

Что не так с этим циклом?

Я хотел бы представить абстрактную перспективу высокого уровня.

Параллельность и одновременность

Операции ввода / вывода взаимодействуют со средой. Среда не является частью вашей программы и не находится под вашим контролем. Среда действительно существует "одновременно" с вашей программой. Как и в случае с другими вещами, вопросы о «текущем состоянии» не имеют смысла: не существует понятия «одновременности» между одновременными событиями. Многие свойства государства просто не существуют одновременно.

Позвольте мне уточнить это: предположим, вы хотите спросить: «У вас есть больше данных». Вы можете запросить это у параллельного контейнера или вашей системы ввода-вывода. Но ответ, как правило, бездействующий и, следовательно, бессмысленный. Так что, если контейнер скажет «да» - к тому времени, когда вы попытаетесь прочитать, у него больше не будет данных. Точно так же, если ответ «нет», к тому времени, когда вы попытаетесь прочитать, данные, возможно, уже поступили. Вывод таков :нет такого свойства, как «У меня есть данные», так как вы не можете действовать осмысленно в ответ на любой возможный ответ. (Ситуация несколько лучше с буферизованным вводом, где вы можете получить «да, у меня есть данные», что является своего рода гарантией, но вам все равно придется иметь дело с противоположным случаем. И с выводом ситуации это так же плохо, как я описал: вы никогда не знаете, заполнен ли этот диск или сетевой буфер.)

Таким образом , мы приходим к выводу , что это невозможно, и в самом деле ип разумного , чтобы задать систему ввода / вывода ли он будет в состоянии выполнить операцию ввода / вывода. Единственный возможный способ взаимодействия с ним (так же, как с параллельным контейнером) - это попытаться выполнить операцию и проверить, была ли она успешной или неудачной. В тот момент, когда вы взаимодействуете со средой, тогда и только тогда вы можете узнать, действительно ли взаимодействие было возможно, и в этот момент вы должны посвятить себя выполнению взаимодействия. (Это «точка синхронизации», если хотите.)

Теперь мы добрались до EOF. EOF - это ответ, который вы получаете от попытки ввода-вывода. Это означает, что вы пытались что-то прочитать или записать, но при этом вам не удалось прочитать или записать какие-либо данные, и вместо этого был обнаружен конец ввода или вывода. Это верно практически для всех API ввода-вывода, будь то стандартная библиотека C, iostreams C ++ или другие библиотеки. Пока операции ввода-вывода успешны, вы просто не можете знать, будут ли дальнейшие будущие операции успешными. Вы всегда должны сначала попробовать операцию, а затем ответить на успех или неудачу.

Примеры

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

C stdio, читайте из файла:

Результат, который мы должны использовать n , это количество прочитанных элементов (которое может быть равным нулю).

Результатом, который мы должны использовать, является возвращаемое значение scanf количества преобразованных элементов.

C ++, извлечение в формате iostreams:

Результат, который мы должны использовать, std::cin сам по себе, который может быть оценен в логическом контексте и говорит нам, находится ли поток в good() состоянии.

C ++, iostreams getline:

Результат, который мы должны использовать, снова std::cin , как и прежде.

POSIX, write(2) чтобы очистить буфер:

В результате мы используем k количество записанных байтов. Дело в том, что мы можем знать только, сколько байтов было записано после операции записи.

Результат, который мы должны использовать nbytes , это число байтов до новой строки (включая EOF, если файл не заканчивался новой строкой).

Обратите внимание, что функция явно возвращает -1 (а не EOF!), Когда возникает ошибка или она достигает EOF.

Вы можете заметить, что мы очень редко произносим слово «EOF». Обычно мы обнаруживаем состояние ошибки другим способом, который более интересен для нас (например, невозможность выполнить столько операций ввода-вывода, сколько мы хотели). В каждом примере есть некоторая функция API, которая может явно сообщить нам, что с состоянием EOF было обнаружено, но на самом деле это не очень полезная часть информации. Это гораздо больше деталей, чем мы часто заботимся. Важно то, был ли ввод / вывод успешным, в большей степени, чем как он провалился.

Последний пример, который фактически запрашивает состояние EOF: предположим, что у вас есть строка и вы хотите проверить, что она представляет собой целое число полностью, без лишних битов в конце, кроме пробелов. Используя C ++ iostreams, это выглядит так:

Мы используем два результата здесь. Первый - iss это сам объект потока, чтобы проверить, что отформатированное извлечение выполнено value успешно. Но затем, после использования пустого пространства, мы выполняем еще одну операцию ввода-вывода iss.get() и ожидаем, что она завершится с ошибкой как EOF, что является случаем, если вся строка уже была использована форматированным извлечением.

В стандартной библиотеке C вы можете добиться чего-то похожего с strto*l функциями, проверив, что указатель конца достиг конца входной строки.

Ответ

while(!feof) неправильно, потому что он проверяет что-то, что не имеет значения и не может проверить то, что вам нужно знать. В результате вы ошибочно выполняете код, который предполагает, что он обращается к данным, которые были успешно прочитаны, хотя на самом деле этого никогда не происходило.

Мне сказали, что я должен использовать while(fin) а не while(!fin.eof()) при чтении файла.

В чем же разница?

Редактирование: я знаю, что while(fin) фактически проверяет объект потока и что, когда он становится NULL, цикл прерывается и он охватывает флагом eof и fail. Но мой преподаватель курса говорит, что fin.eof() лучше, поэтому мне нужно понять основную операцию, которая здесь происходит.

Какая из них правильная практика?

Примечание. Это не дубликат, мне нужна помощь в Turbo C++ и с двоичными файлами. Я в основном пытаюсь прочитать файл, используя объект класса.

спросил(а) 2021-01-04T14:26:58+03:00 10 месяцев, 2 недели назад

Прежде всего, я предполагаю, что fin является вашим объектом fstream . В этом случае ваш учитель не сказал бы вам использовать while(fin.eof()) для чтения из файла. Она бы сказала, чтобы использовать в while(!fin.eof()) .

Позволь мне объяснить. eof() является членом класса fstream который возвращает true или false значение в зависимости от того, достигнут ли конец файла (eof) файла, который вы читаете. Таким образом, в то время как eof() возвращает 0 это означает, что конец файла не был достигнут, и цикл продолжает выполняться, но когда eof() возвращает 1 конец файла достигнут, и цикл завершается.

while(fin) цикл вводится, потому что fin фактически возвращает значение переменной флага ошибки внутри объекта fin объекта класса, значение которого установлено равным 0, когда любая функция, такая как чтение, запись или открытие, терпит неудачу. Таким образом, цикл работает до тех пор, пока работает функция чтения внутри цикла.

Лично я бы не предложил ни одного из них. Я бы предложил

//Предположим, что класс abc.

Этот цикл считывает запись файла внутри условия цикла, и если ничего не было прочитано из-за окончания файла, то цикл завершается.

Проблема с while(!fin.eof()) том, что она возвращает 1 если конец файла достигнут. Конец файла на самом деле является символом, который помещается в конец файла. Поэтому, когда функция чтения внутри цикла считывает этот символ и устанавливает переменную eof равным 1. Вся функция на самом деле возвращает это значение.

Таким образом, работает отлично, когда вы читаете строки в словах, но когда вы читаете последовательные записи класса из файла, этот метод не удастся. Рассматривать

Таким образом, отображает последнюю запись дважды. Это связано с тем, что конец символа файла является символом после последнего байта последней записи. Когда последнее считывается, указатель файла находится в байтах eof, но еще не прочитал его. Таким образом, он снова войдет в цикл, но на этот раз считывается символ eof, но функция чтения не работает. Значения, уже внесенные в переменную a , то есть предыдущие записи, будут отображаться снова.

Читайте также: