Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Вопросик по функции feof  (Прочитано 23396 раз)
0 Пользователей и 1 Гость смотрят эту тему.
lightmaker
Участник

ru
Offline Offline

« : 28-02-2008 12:52 » 

Платформа: Unix
gcc 2.95
Имеется текстовый файл, содержащий строку "123"

while(!feof(fp))
  ch=fgetc(fp);

Напал тупняк и не могу понять, почему цикл выполняется 4 раза??? Работу я себе представляю так: Вначале указатель стоит на самый первое значение. Далее мы читаем его после чего указатель стоит на следующее значение, потом мы проверяем не указывает ли он на конец файла. Соответственно когда мы считаем символ '3', указатель по идее должен стоять на EOF, но почему-то происходит еще одна итерация? Может я чего-то не правельно понял?
Записан
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #1 : 28-02-2008 13:01 » 


1) возможно, после 3 ещё символ ? (тот же твой любимый \n Улыбаюсь)

2) а как себя ведёт с абсолютно пустым файлом?
Записан

Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #2 : 28-02-2008 13:03 » 

ответ прост, потому, что fgetc возвращает следующий элемент, а не текущий

можешь написать по другому
int tmp;
while((tmp = fgetc(fp)) != EOF)
{
   ch = tmp;
}
Записан

Странно всё это....
lightmaker
Участник

ru
Offline Offline

« Ответ #3 : 28-02-2008 13:26 » 

ответ прост, потому, что fgetc возвращает следующий элемент, а не текущий

можешь написать по другому
int tmp;
while((tmp = fgetc(fp)) != EOF)
{
   ch = tmp;
}

Хм.. получается, что из файла со строкой 123, символ '1' не будет считан? нЕ понятно
Записан
RXL
Технический
Администратор

Online Online
Пол: Мужской

WWW
« Ответ #4 : 28-02-2008 18:06 » 

lightmaker, LogRus дал тебе совершенно верный пример. Выкладывай свой код.
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
lightmaker
Участник

ru
Offline Offline

« Ответ #5 : 28-02-2008 20:59 » 

RXL, да пример правельный, не спорю! Смутила фраза:

ответ прост, потому, что fgetc возвращает следующий элемент, а не текущий

Согласно этому самый первый символ не будет считан...

А код в первом сообщении! И я не могу понять почему он так работает, т.е. почему 4 итерации.
Извеняюсь за тупняк.Улыбаюсь
Записан
RXL
Технический
Администратор

Online Online
Пол: Мужской

WWW
« Ответ #6 : 28-02-2008 21:27 » 

lightmaker, да, несколько путано. Давай лучше так: feof возвращает состояние последнего чтения из потока. Т.е., если при последнем чтении случился конец файла, то feof даст истину, а нет (или чтения еще вообще не производилось) - лож.
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
lightmaker
Участник

ru
Offline Offline

« Ответ #7 : 28-02-2008 22:08 » 

RXL, спасибо за точное объяснение.
Честно говоря фигня какая-то. В большом справочнике по С товарисча Шилдта про ето не написано. А мануал в Линухе вообще говорит: "Функция feof проверяет указатель конца файла для потока stream, возвращая ненулевое значение, если он указывает на конец файла."
После этого я не врубаюсь почему fseek устанавливаю указатель на конец файла, а feof молчит засранец:)

p.s. Получается, если открыть файл fopen и применить fgetc, получим первый символ. А так, как замечено выше, что fgetc читает не текущий символ, а следующий, получается, что после открытия файловый указатель стоит на "что-то"Улыбаюсь до первого символа. Улыбаюсь)
Ну я и занудисчееееее Скромно так...
« Последнее редактирование: 28-02-2008 23:21 от lightmaker » Записан
RXL
Технический
Администратор

Online Online
Пол: Мужской

WWW
« Ответ #8 : 29-02-2008 00:10 » 

lightmaker, feof неудобная функция и, по сути, не нужна совсем.
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #9 : 29-02-2008 07:06 » 

lightmaker, ну это просто вопрос восприятия Улыбаюсь так написано в описании функции. Считай, что до первого чтения указатель в файле стоит перед первым символом или считай, что в конце файла есть символ конца файла CTRL+D Улыбаюсь

можно while, заменить на do while или
for(fgetc;feof;fgetc){}

второй вариант предпочтительней
Записан

Странно всё это....
RXL
Технический
Администратор

Online Online
Пол: Мужской

WWW
« Ответ #10 : 29-02-2008 08:29 » 

LogRus, даже второй вариант бессмысленный - можно сравнение с EOF сделать.

do c = fgetc(f); while(feof(f));
Это вообще недопустимо: fgetc вернет EOF, что по сути - значение int, которое преобразуется в char и будет паразитный символ 0xff.

Т.ч. проще просто while - так обычно и делают.
« Последнее редактирование: 29-02-2008 08:32 от RXL » Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #11 : 29-02-2008 11:41 » 

RXL, не люблю я while его почти всегда заменяю на for

лично меня конструкция for(int ch = fgetc(fp); ch != EOF; ch = fgetc(fp)) вполне устроит
нет лишней итерации цикла, нет while
Записан

Странно всё это....
geg Maneg
Гость
« Ответ #12 : 29-03-2008 11:52 » 

RXL
лично меня конструкция for(int ch = fgetc(fp); ch != EOF; ch = fgetc(fp)) вполне устроит
нет лишней итерации цикла, нет while
что значит нет лишней итерации?? значение в ch считается 4 раза пусть даже и за 3 итерации...а если эти значения надо обрабатывать постоянно? тогда первый считанный символ будет утерян, а в последнем получем ЕОФ
это не решает проблемы в общем

есть ли еще какой-нибудь способ проверки ТЕКУЩУГО состояния указателя файла, кроме проверки вручную
« Последнее редактирование: 29-03-2008 11:55 от geg Maneg » Записан
RXL
Технический
Администратор

Online Online
Пол: Мужской

WWW
« Ответ #13 : 29-03-2008 13:23 » 

geg Maneg, еще раз: гарантированный результат даст только чтение из файла.

Т.к. здесь использовались потоковые ф-ии, то удавшийся fgetc можно компенсировать ungetc, запихнув символ назад в буфер.
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
geg Maneg
Гость
« Ответ #14 : 29-03-2008 14:09 » 

Т.к. здесь использовались потоковые ф-ии, то удавшийся fgetc можно компенсировать ungetc, запихнув символ назад в буфер.
да в принципе обратно запихивать и не надо...считываем же с файла
а что нету больше каких-нить функций проверки текущуего состояния указателя??
Записан
RXL
Технический
Администратор

Online Online
Пол: Мужской

WWW
« Ответ #15 : 29-03-2008 14:24 » 

geg Maneg, понимаешь, под "файлом" может оказатся что угодно: может быть файл, открытый несколькими программами (напр., другая программа дописывает в него), может оказатся символьное устройство (COM-порт, к примеру) и может быть буфер в памяти и мало ли еще чего. Нет универсального метода. Потому, только чтение из файла даст ответ - есть ли данные. Причем, для файла это будет означать конец файла, для COM-порта и буфера в памяти - пустой буфер приема.

Скажем, ситуация, когда другая программа пишет в файл, а твоя считывает из него. Ты дочитал до конца и получил истину на eof(), но спустя некоторое время другая программа дописала в файл. Тебе eof() по прежнему выдает истину, а если бы ты выполнил чтение, то получил бы еще данные и, возможно, сброс eof().

Конец физического файла можно еще определить, сравнивая размер файла с текущей позицией.

Код:
int fgetpos(FILE *restrict stream, fpos_t *restrict pos);
long ftell(FILE *stream);

int fstat(int fildes, struct stat *buf);
/*
dev_t     st_dev     Device ID of device containing file.
ino_t     st_ino     File serial number.
mode_t    st_mode    Mode of file (see below).
nlink_t   st_nlink   Number of hard links to the file.
uid_t     st_uid     User ID of file.
gid_t     st_gid     Group ID of file.
dev_t     st_rdev    Device ID (if file is character or block special).
off_t     st_size    For regular files, the file size in bytes.
                     For symbolic links, the length in bytes of the
                     pathname contained in the symbolic link.
                     For a shared memory object, the length in bytes.
                     For a typed memory object, the length in bytes.
                     For other file types, the use of this field is
                     unspecified.
time_t    st_atime   Time of last access.
time_t    st_mtime   Time of last data modification.
time_t    st_ctime   Time of last status change.
blksize_t st_blksize A file system-specific preferred I/O block size for
                     this object. In some file system types, this may
                     vary from file to file.
blkcnt_t  st_blocks  Number of blocks allocated for this object.
*/
[/code
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
geg Maneg
Гость
« Ответ #16 : 29-03-2008 14:38 » 

блин ты прав...
запихивать обратно файл надо...токо я вот не пойму почему если у меня файл открыт токо для чтения функции getc() ungetc() меняеют его как ни в чем не бывало...
и в таком случае помоги как правильно считать с файла проверить и обратно запихнуть

делаю
while(int ch=fgetc(stream)!=EOF)
{
    ungetc(ch,stream);
    //..
}

указатель правильно становится на свое место а вот значение левое какое вписывается...че я не так делаю?
из файла у меня структурки считываются файл бинарный
« Последнее редактирование: 29-03-2008 14:40 от geg Maneg » Записан
RXL
Технический
Администратор

Online Online
Пол: Мужской

WWW
« Ответ #17 : 29-03-2008 17:28 » new

geg Maneg, погоди... Последний мосй пост к unget отношения не имеет - я описывал особенность чтения и бесполезность eof.

Если об иммитации eof чтением:

Код: (C)
int my_eof(FILE *f)
{
    int c;

    c = fgetc(f);

    if (c == EOF)
        return 1;

    unget(f, c);
    return 0;
}

Такое возможно только с потоковыми функциями, т.к. они используют буферы в памяти и unget просто помещает символ в буфер.
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines