lightmaker
Участник
Offline
|
|
« : 28-02-2008 12:52 » |
|
Платформа: Unix gcc 2.95 Имеется текстовый файл, содержащий строку "123"
while(!feof(fp)) ch=fgetc(fp);
Напал тупняк и не могу понять, почему цикл выполняется 4 раза??? Работу я себе представляю так: Вначале указатель стоит на самый первое значение. Далее мы читаем его после чего указатель стоит на следующее значение, потом мы проверяем не указывает ли он на конец файла. Соответственно когда мы считаем символ '3', указатель по идее должен стоять на EOF, но почему-то происходит еще одна итерация? Может я чего-то не правельно понял?
|
|
|
Записан
|
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #1 : 28-02-2008 13:01 » |
|
1) возможно, после 3 ещё символ ? (тот же твой любимый \n ) 2) а как себя ведёт с абсолютно пустым файлом?
|
|
|
Записан
|
|
|
|
Антон (LogRus)
|
|
« Ответ #2 : 28-02-2008 13:03 » |
|
ответ прост, потому, что fgetc возвращает следующий элемент, а не текущий
можешь написать по другому int tmp; while((tmp = fgetc(fp)) != EOF) { ch = tmp; }
|
|
|
Записан
|
Странно всё это....
|
|
|
lightmaker
Участник
Offline
|
|
« Ответ #3 : 28-02-2008 13:26 » |
|
ответ прост, потому, что fgetc возвращает следующий элемент, а не текущий
можешь написать по другому int tmp; while((tmp = fgetc(fp)) != EOF) { ch = tmp; }
Хм.. получается, что из файла со строкой 123, символ '1' не будет считан? нЕ понятно
|
|
|
Записан
|
|
|
|
RXL
Технический
Администратор
Offline
Пол:
|
|
« Ответ #4 : 28-02-2008 18:06 » |
|
lightmaker, LogRus дал тебе совершенно верный пример. Выкладывай свой код.
|
|
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
lightmaker
Участник
Offline
|
|
« Ответ #5 : 28-02-2008 20:59 » |
|
RXL, да пример правельный, не спорю! Смутила фраза: ответ прост, потому, что fgetc возвращает следующий элемент, а не текущий Согласно этому самый первый символ не будет считан... А код в первом сообщении! И я не могу понять почему он так работает, т.е. почему 4 итерации. Извеняюсь за тупняк.
|
|
|
Записан
|
|
|
|
RXL
Технический
Администратор
Offline
Пол:
|
|
« Ответ #6 : 28-02-2008 21:27 » |
|
lightmaker, да, несколько путано. Давай лучше так: feof возвращает состояние последнего чтения из потока. Т.е., если при последнем чтении случился конец файла, то feof даст истину, а нет (или чтения еще вообще не производилось) - лож.
|
|
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
lightmaker
Участник
Offline
|
|
« Ответ #7 : 28-02-2008 22:08 » |
|
RXL, спасибо за точное объяснение. Честно говоря фигня какая-то. В большом справочнике по С товарисча Шилдта про ето не написано. А мануал в Линухе вообще говорит: "Функция feof проверяет указатель конца файла для потока stream, возвращая ненулевое значение, если он указывает на конец файла." После этого я не врубаюсь почему fseek устанавливаю указатель на конец файла, а feof молчит засранец:) p.s. Получается, если открыть файл fopen и применить fgetc, получим первый символ. А так, как замечено выше, что fgetc читает не текущий символ, а следующий, получается, что после открытия файловый указатель стоит на "что-то" до первого символа. ) Ну я и занудисчееееее
|
|
« Последнее редактирование: 28-02-2008 23:21 от lightmaker »
|
Записан
|
|
|
|
RXL
Технический
Администратор
Offline
Пол:
|
|
« Ответ #8 : 29-02-2008 00:10 » |
|
lightmaker, feof неудобная функция и, по сути, не нужна совсем.
|
|
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
Антон (LogRus)
|
|
« Ответ #9 : 29-02-2008 07:06 » |
|
lightmaker, ну это просто вопрос восприятия так написано в описании функции. Считай, что до первого чтения указатель в файле стоит перед первым символом или считай, что в конце файла есть символ конца файла CTRL+D можно while, заменить на do while или for(fgetc;feof;fgetc){} второй вариант предпочтительней
|
|
|
Записан
|
Странно всё это....
|
|
|
RXL
Технический
Администратор
Offline
Пол:
|
|
« Ответ #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)
|
|
« Ответ #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
Технический
Администратор
Offline
Пол:
|
|
« Ответ #13 : 29-03-2008 13:23 » |
|
geg Maneg, еще раз: гарантированный результат даст только чтение из файла.
Т.к. здесь использовались потоковые ф-ии, то удавшийся fgetc можно компенсировать ungetc, запихнув символ назад в буфер.
|
|
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
geg Maneg
Гость
|
|
« Ответ #14 : 29-03-2008 14:09 » |
|
Т.к. здесь использовались потоковые ф-ии, то удавшийся fgetc можно компенсировать ungetc, запихнув символ назад в буфер.
да в принципе обратно запихивать и не надо...считываем же с файла а что нету больше каких-нить функций проверки текущуего состояния указателя??
|
|
|
Записан
|
|
|
|
RXL
Технический
Администратор
Offline
Пол:
|
|
« Ответ #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
Технический
Администратор
Offline
Пол:
|
|
« Ответ #17 : 29-03-2008 17:28 » |
|
geg Maneg, погоди... Последний мосй пост к unget отношения не имеет - я описывал особенность чтения и бесполезность eof. Если об иммитации eof чтением: int my_eof(FILE *f) { int c;
c = fgetc(f);
if (c == EOF) return 1;
unget(f, c); return 0; } Такое возможно только с потоковыми функциями, т.к. они используют буферы в памяти и unget просто помещает символ в буфер.
|
|
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
|