Возник один вопрос , если кто подскажет буду премного благодарен .
Пусть есть файл 1.txt и в нём записано что-то типо a b c d e f .
А теперь сравним 2 следующих куска кода :

while (!feof(f))
{
c = getc(f);
cout << c ;
}


while (!feof(f))
{
fscanf(f,"%c",&c) ;
cout << c ;
}
В первом случае вывод : a b c d e f (после f ещё 1 пробел )
Во втором случае вывод : a b c d e ff

А теперь вопрос : откуда эта разница ? Правильно ли я понимаю , что комманда feof срабатывает тогда ,
когда будет считан специальный символ конца файла(или же когда указатель только указывает на этот символ и он ещё не считан) ?
То есть интересует , что происходит после того момента , когда уже считана последняя буква f .
Заранее спасибо .

@темы: C++

Комментарии
31.03.2011 в 20:47

Складывается такое ощущение , что всё-таки символ конца файла считывается в цикле , но вместо него в 1-ом случае почему-то высвечивется пробел , а во 2-ом то старое значение символьной переменной то есть как раз f .
31.03.2011 в 22:19

Those wings... I want them too.
Насколько я понимаю, никакого специального "символа конца файла" нет, EOF - просто некоторый глобальный флажок, который устанавливают функции работы с файловым потоком.
Вот тут
http://www.cplusplus.com/reference/clibrary/cstdio/getc/

про getc пишут:
Return Value
The character read is returned as an int value.
If the End-of-File is reached or a reading error happens, the function returns EOF and the corresponding error or eof indicator is set


т.е. последний возвращённый getc символ, при неудаче чтения из-за окончания файла - это EOF, а не пробел, просто у EOF нет графического представления.

Что делает fscanf могу только предполагать; вероятно, он при невозможности считать следующий символ просто не меняет то, что лежало в ячейке памяти &c
31.03.2011 в 22:28

Я знаю, что я гений, но мне от этого ничуть не легче.
таки EOF превращается в 0, что не отображается при выводе в консоли, но можно увидеть, если вывести в файл и посмотреть его в HEX-viewer-е.
При этом getc выдает этот 0, а scanf игнорирует.
feof срабатывает, когда указатель потока оказывает за границей потока.
31.03.2011 в 22:29

Беги, беги, не бойся играть судьбою вновь и вновь.
К предыдущему комменту добавлю:
1. По крайней мере в VC++ при неудачном чтении с помощью getc(), символу присваивается код -1. Он как раз и отображается как пробел.
2. fscanf() не меняет значение переменной, т.к. все равно не логично ее использовать - чтение ведь произошло неудачно.
3. Чтобы избежать этих недочетов нужно проверку на конец файла делать после считывания очередного символа, но перед его использованием
c = getc(f)
while (!feof(f))
{
cout << c;
c = getc(f);
}
///////////////////////////////////////////////////////////////
fscanf(f,"%c",&c) ;
while (!feof(f))
{
cout << c ;
fscanf(f,"%c",&c) ;
}
31.03.2011 в 22:33

Я знаю, что я гений, но мне от этого ничуть не легче.
Merzley, может и -1, не помню, давно было... но char(-1)==char(255), емнип.. т.е. это совсем не пробел, что сути не меняет :)
31.03.2011 в 22:40

Беги, беги, не бойся играть судьбою вновь и вновь.
mikluho Дык я и написал "отображается как пробел", т.к. символ с этим кодом, не смотря на то что он кривой, все равно по этому алгоритму выводится на экран :-)
01.04.2011 в 00:37

Кажется разобрался , спасибо . В общем при считывании EOF fscanf возвращает старое значение переменной , а fgetc код -1 ( или буква я ) . Отсюда сразу вопрос , как считывать букву я )
01.04.2011 в 01:08

Пау-чок
Как написано в стандарте C99, fscanf возвращает количество удачно считанных элементов строки-формата и EOF в случае ошибки (возможных случаев ошибки вообще-то множество, от невозможности считать следующий символ до попытки считать "100e" с помощью формата "%f%c")
Так что я бы на вашем месте сделал бы вот так:
while ( fscanf(f,"%c",&c) != EOF){
cout << c ;
}

Устанавливает ли fscanf указатель end-of-file, в стандарте не описано. Зато про fgetc сказано вполне конкретно, что по достижении конца файла, потоку ставится маркер end-of-file. fgetc возвращает прочитанный unsigned char, преобразованный в int, либо EOF в случае достижения конца файла или ошибки чтения. Так что цикл с fgetc можно было бы тоже написать как:
while ((c=getc(f))!=EOF)
{
cout << c;
}
01.04.2011 в 10:18

Я знаю, что я гений, но мне от этого ничуть не легче.
nvse, так, чисто для большего понимания... при считывании EOF fscanf не меняет значение переменной по указателю &c.
а fgetc код -1 ( или буква я ) - а вот это зависит от кодировки. в стандартной ascii - там непечатный символ.

O :hlop:
01.04.2011 в 16:59

Всем спасибо , но видимо я всё-таки до конца с этим feof() не понял . Файл 1.txt :aa(две буквы a и всё)
Тупо пишем :
fscanf(f,"%c",&c);
fscanf(f,"%c",&c);

if (feof(f))
cout<<;"END";

Но условие не срабатывает . В определении feof написано : Если текущая позиция является концом файла (EOF), функция feof возвращает ненулевое значение.
После того как последняя буква a считана , разве текущая позиция файла не EOF ? Если потом 3-ий раз написать fscanf(f,"%c",&c) то только тогда условие срабатывает почему-то(то есть уже когда сам EOF читается) . В отладчике после второго fscanf(f,"%c",&c) смотрел f , в нём написано что-то типа HHHHHHHHHHHHH(как я понимаю это как раз конец) .То есть не совсем понятно почему после 2-го fscanf(f,"%c",&c) указатель не выходит за границу.
01.04.2011 в 17:37

Я знаю, что я гений, но мне от этого ничуть не легче.
nvse, нет, всё не так :)
fscanf сначала смещает указатель потока, а затем считывает символ в текущей позиции. и feof получается только если очередной сдвиг вышел за границы потока.
01.04.2011 в 21:23

mikluho и feof получается только если очередной сдвиг вышел за границы потока.
То есть EOF это ведь тоже часть потока ?
02.04.2011 в 09:02

Я знаю, что я гений, но мне от этого ничуть не легче.
nvse, нет.
02.04.2011 в 15:25

Ладно , видимо я и впрямь чего-то не догоняю
1-ая комманда : указатель сдвигается на 2-ую a , 1-ая a считывается
2-ая комманда : указатель сдвигается на EOF a , 2-ая a считывается
Если EOF это не поток , то почему тогда feof() не срабатывает после 2-ой комманды ,когда указатель за потоком?
02.04.2011 в 16:32

Пау-чок
nvse feof() не читает сам поток. Он просто проверяет установлен ли в структуре FILE так называемый end-of-file indicator. Как я писал, fgetc() устанавливает этот индикатор только если при его, fgetc'а, очередном вызове в потоке уже не осталось больше данных, т.е. когда возвращать нечего. Как устанавливает этот флаг fscanf(), я нигде не нашёл. Вероятнее всего так же - если при очередном вызове fsacnf() в процессе чтения потока этой функцией заканчиваются данные, то ставится end-of-file indicator.
02.04.2011 в 17:52

O то есть на момент считывания файла никакого маркера EOF в нём нет , а создатся этот маркер fscanf - ом только тогда , когда будет нечего считывать ? Потом этот маркер создатся и указатель будет на EOF , а значит feof() сработает ? Жалко , что про такие нюансы я в ни одной книге по С не видел .
02.04.2011 в 21:44

Ещё 1 вопрос возник по файлам , если кого не затруднит :
В общем можно ли из файла сразу считать какую-нибудь свою(составную) структуру с помощью fread() , чтобы при этом некоторые поля этой структуры заполнялись не как
char , а к примеру int ?
К примеру есть структура :

struct some_structure
{
char a[10] ;
int b ;
float c ;
}
Мог бы конечно по отдельности через fscanf считывать отдельные поля, но было вообще супер если бы сразу можно было считать всю струртуру целиком .
03.04.2011 в 05:09

Пау-чок
nvse то есть на момент считывания файла никакого маркера EOF в нём нет , а создатся этот маркер fscanf - ом только тогда , когда будет нечего считывать ?

===
7.21.1.1. The header declares three types, several macros, and many functions for performing input and output.
7.21.1.2. The types declared are ... FILE which is an object type capable of recording all the information needed to control a stream, including its file position indicator, a pointer to its associated buffer (if any), an error indicator that records whether a read/write error has occurred, and an end-of-file indicator that records whether the end of the file has been reached.
===
7.21.1.1. Заголовочный файл объявляет три типа, несколько макроссов и множество функция для выполнения ввода и вывода.
7.21.1.2. Объявляемыми типами являются ... FILE - объектный тип, способный хранить всю информацию, необходимую для контроля за потоком, включая индикатор позиции файла, указатель на связанный с файлом буффер (если таковой имеется), индикатор ошибок, отражающий, возникали ли ошибки чтения/записи, и индикатор конца файла, который хранит, был ли достигнут конец файла.
===

===
7.21.10.2.3. The feof function returns nonzero if and only if the end-of-file indicator is set for stream.
===
7.21.10.2.3. Функция feof возвращает ненулевое значение исключительно в том случае, если индикатор конца файла установлен для потока.
===

Это выдержки из стандарта ISO/IEC 9899:201x (у меня на руках только черновая версия от 16 ноября 2010). Очень советую найти и скачать - я к нему иногда обращаюсь, если встают вопросы по работе стандартных функций.

В общем можно ли из файла сразу считать какую-нибудь свою(составную) структуру с помощью fread(), чтобы при этом некоторые поля этой структуры заполнялись не как char, а к примеру int ?

С помощью fread() это обычно и делается. Но структура записывается в бинарном виде. Вот например:

typedef struct{
    char a[10] ;
    int b ;
    float c ;
} some_structure;

/*код-код-код*/

some_structure some_var;
FILE * f;
/*открыли файл*/
fread(
    &some_var, //куда записать прочитанное
    sizeof(some_var), //сколько весит блок, который надо прочитать
    1, //сколько блоков прочитать (чтобы можно было считать сразу массив)
    f // собственно, откуда читать будем
);