EOF — это не символ
Недавно я читал книгу «Компьютерные системы: архитектура и программирование. Взгляд программиста». Там, в главе про систему ввода-вывода Unix, авторы упомянули о том, что в конце файла нет особого символа EOF .

Если вы читали о системе ввода-вывода Unix/Linux, или экспериментировали с ней, если писали программы на C, которые читают данные из файлов, то это заявление вам, вероятно, покажется совершенно очевидным. Но давайте поближе присмотримся к следующим двум утверждениям, относящимся к тому, что я нашёл в книге:
- EOF — это не символ.
- В конце файлов нет некоего особого символа.
EOF — это не символ
Почему кто-то говорит или думает, что EOF — это символ? Полагаю, это может быть так из-за того, что в некоторых программах, написанных на C, можно найти код, в котором используется явная проверка на EOF с использованием функций getchar() и getc() .
Это может выглядеть так:
#include . while ((c = getchar()) != EOF) putchar(c);
FILE *fp; int c; . while ((c = getc(fp)) != EOF) putc(c, stdout);
Если заглянуть в справку по getchar() или getc() , можно узнать, что обе функции считывают следующий символ из потока ввода. Вероятно — именно это является причиной возникновения заблуждения о природе EOF . Но это — лишь мои предположения. Вернёмся к мысли о том, что EOF — это не символ.
А что такое, вообще, символ? Символ — это самый маленький компонент текста. «A», «a», «B», «b» — всё это — разные символы. У символа есть числовой код, который в стандарте Unicode называют кодовой точкой. Например — латинская буква «A» имеет, в десятичном представлении, код 65. Это можно быстро проверить, воспользовавшись командной строкой интерпретатора Python:
$python >>> ord('A') 65 >>> chr(65) 'A'
Или можно взглянуть на таблицу ASCII в Unix/Linux:
$ man ascii

Выясним, какой код соответствует EOF , написав небольшую программу на C. В ANSI C константа EOF определена в stdio.h , она является частью стандартной библиотеки. Обычно в эту константу записано -1 . Можете сохранить следующий код в файле printeof.c , скомпилировать его и запустить:
#include int main(int argc, char *argv[])
Скомпилируем и запустим программу:
$ gcc -o printeof printeof.c $ ./printeof EOF value on my system: -1
У меня эта программа, проверенная на Mac OS и на Ubuntu, сообщает о том, что EOF равняется -1 . Есть ли какой-нибудь символ с таким кодом? Тут, опять же, можно проверить коды символов в таблице ASCII, можно взглянуть на таблицу Unicode и узнать о том, в каком диапазоне могут находиться коды символов. Мы же поступим иначе: запустим интерпретатор Python и воспользуемся стандартной функцией chr() для того, чтобы она дала бы нам символ, соответствующий коду -1 :
$ python >>> chr(-1) Traceback (most recent call last): File "", line 1, in ValueError: chr() arg not in range(0x110000)
Как и ожидалось, символа с кодом -1 не существует. Значит, в итоге, EOF , и правда, символом не является. Переходим теперь ко второму рассматриваемому утверждению.
В конце файлов нет некоего особого символа
Может, EOF — это особенный символ, который можно обнаружить в конце файла? Полагаю, сейчас вы уже знаете ответ. Но давайте тщательно проверим наше предположение.
Возьмём простой текстовый файл, helloworld.txt, и выведем его содержимое в шестнадцатеричном представлении. Для этого можно воспользоваться командой xxd :
$ cat helloworld.txt Hello world! $ xxd helloworld.txt 00000000: 4865 6c6c 6f20 776f 726c 6421 0a Hello world!.
Как видите, последний символ файла имеет код 0a . Из таблицы ASCII можно узнать о том, что этот код соответствует символу nl , то есть — символу новой строки. Это можно выяснить и воспользовавшись Python:
$ python >>> chr(0x0a) '\n'
Так. EOF — это не символ, а в конце файлов нет некоего особого символа. Что же такое EOF ?
Что такое EOF?
EOF (end-of-file) — это состояние, которое может быть обнаружено приложением в ситуации, когда операция чтения файла доходит до его конца.
Взглянем на то, как можно обнаруживать состояние EOF в разных языках программирования при чтении текстового файла с использованием высокоуровневых средств ввода-вывода, предоставляемых этими языками. Для этого напишем очень простую версию cat , которая будет называться mcat . Она побайтно (посимвольно) читает ASCII-текст и в явном виде выполняет проверку на EOF . Программу напишем на следующих языках:
- ANSI C
- Python 3
- Go
- JavaScript (Node.js)
ANSI C
Начнём с почтенного C. Представленная здесь программа является модифицированной версией cat из книги «Язык программирования C».
/* mcat.c */ #include int main(int argc, char *argv[]) < FILE *fp; int c; if ((fp = fopen(*++argv, "r")) == NULL) < printf("mcat: can't open %s\n", *argv); return 1; >while ((c = getc(fp)) != EOF) putc(c, stdout); fclose(fp); return 0; >
$ gcc -o mcat mcat.c
$ ./mcat helloworld.txt Hello world!
Вот некоторые пояснения, касающиеся вышеприведённого кода:
- Программа открывает файл, переданный ей в виде аргумента командной строки.
- В цикле while осуществляется копирование данных из файла в стандартный поток вывода. Данные копируются побайтово, происходит это до тех пор, пока не будет достигнут конец файла.
- Когда программа доходит до EOF , она закрывает файл и завершает работу.
Python 3
В Python нет механизма явной проверки на EOF , похожего на тот, который имеется в ANSI C. Но если посимвольно читать файл, то можно выявить состояние EOF в том случае, если в переменной, хранящей очередной прочитанный символ, будет пусто:
# mcat.py import sys with open(sys.argv[1]) as fin: while True: c = fin.read(1) # читаем максимум 1 символ if c == '': # EOF break print(c, end='')
Запустим программу и взглянём на возвращаемые ей результаты:
$ python mcat.py helloworld.txt Hello world!
Вот более короткая версия этого же примера, написанная на Python 3.8+. Здесь используется оператор := (его называют «оператор walrus» или «моржовый оператор»):
# mcat38.py import sys with open(sys.argv[1]) as fin: while (c := fin.read(1)) != '': # читаем максимум 1 символ до достижения EOF print(c, end='')
Запустим этот код:
$ python3.8 mcat38.py helloworld.txt Hello world!
Go
В Go можно явным образом проверить ошибку, возвращённую Read(), на предмет того, не указывает ли она на то, что мы добрались до конца файла:
// mcat.go package main import ( "fmt" "os" "io" ) func main() < file, err := os.Open(os.Args[1]) if err != nil < fmt.Fprintf(os.Stderr, "mcat: %v\n", err) os.Exit(1) >buffer := make([]byte, 1) // 1-byte buffer for < bytesread, err := file.Read(buffer) if err == io.EOF < break >fmt.Print(string(buffer[:bytesread])) > file.Close() >
$ go run mcat.go helloworld.txt Hello world!
JavaScript (Node.js)
В среде Node.js нет механизма для явной проверки на EOF . Но, когда при достижении конца файла делается попытка ещё что-то прочитать, вызывается событие потока end.
/* mcat.js */ const fs = require('fs'); const process = require('process'); const fileName = process.argv[2]; var readable = fs.createReadStream(fileName, < encoding: 'utf8', fd: null, >); readable.on('readable', function() < var chunk; while ((chunk = readable.read(1)) !== null) < process.stdout.write(chunk); /* chunk is one byte */ >>); readable.on('end', () => < console.log('\nEOF: There will be no more data.'); >);
$ node mcat.js helloworld.txt Hello world! EOF: There will be no more data.
Низкоуровневые системные механизмы
Как высокоуровневые механизмы ввода-вывода, использованные в вышеприведённых примерах, определяют достижение конца файла? В Linux эти механизмы прямо или косвенно используют системный вызов read(), предоставляемый ядром. Функция (или макрос) getc() из C, например, использует системный вызов read() и возвращает EOF в том случае, если read() указывает на возникновение состояния достижения конца файла. В этом случае read() возвращает 0 . Если изобразить всё это в виде схемы, то получится следующее:

Получается, что функция getc() основана на read() .
Напишем версию cat , названную syscat , используя только системные вызовы Unix. Сделаем мы это не только из интереса, но и из-за того, что это вполне может принести нам какую-то пользу.
Вот эта программа, написанная на C:
/* syscat.c */ #include #include #include #include int main(int argc, char *argv[])
$ gcc -o syscat syscat.c $ ./syscat helloworld.txt Hello world!
В этом коде используется тот факт, что функция read() , указывая на достижение конца файла, возвращает 0 .
Вот та же программа, написанная на Python 3:
# syscat.py import sys import os fd = os.open(sys.argv[1], os.O_RDONLY) while True: c = os.read(fd, 1) if not c: # EOF break os.write(sys.stdout.fileno(), c)
$ python syscat.py helloworld.txt Hello world!
Вот — то же самое, написанное на Python 3.8+:
# syscat38.py import sys import os fd = os.open(sys.argv[1], os.O_RDONLY) while c := os.read(fd, 1): os.write(sys.stdout.fileno(), c)
Запустим и этот код:
$ python3.8 syscat38.py helloworld.txt Hello world!
Итоги
- EOF — это не символ.
- В конце файлов нет некоего особого символа.
- EOF — это состояние, о котором сообщает ядро, и которое может быть обнаружено приложением в том случае, когда операция чтения данных доходит до конца файла.
- В ANSI C EOF — это, опять же, не символ. Это — константа, определённая в stdio.h , в которую обычно записано значение -1.
- «Символ» EOF нельзя найти в таблице ASCII или в Unicode.

Правильное использование проверки конца файла
в C++ получаются неприятности — лишняя считанная строка, например. Почему? Как правильно проверить, что достигнут конец файла?
Отслеживать
задан 27 мая 2018 в 4:12
218k 15 15 золотых знаков 117 117 серебряных знаков 229 229 бронзовых знаков
связанный вопрос Читать строки из файла, пока они есть
27 мая 2018 в 6:04
2 ответа 2
Сортировка: Сброс на вариант по умолчанию
Признак достижения конца файла выставляется только после неудачной попытки чтения за его концом. Поэтому, если в теле цикла нет проверки, успешно ли выполнено чтение из файла — последнее чтение окажется именно тем неудачным чтением, которое выставит признак достигнутого конца файла (а для вас это будет выглядеть как, например, еще раз считанная последняя строка, если она находилась в буфере для чтения).
Лучше в заголовке цикла while выполнять само чтение с проверкой — например, в программе на C это могло бы выглядеть как
while(fread(&data,sizeof(data),1,file)==1) < // Обработка считанных данных >/* Или, скажем, while(fgets(buf, bufsize, file)) < . >*/ if (feof(file)) // Достигнут конец файла puts("Ошибка чтения: достигнут конец файла"); else if (ferror(file)) < puts("Ошибка чтения файла");
или на C++ - наподобие
for(int n; file >> n; ) < // Обработка считанного значения n >if (file.bad()) std::cout
Отслеживать
ответ дан 27 мая 2018 в 4:12
218k 15 15 золотых знаков 117 117 серебряных знаков 229 229 бронзовых знаков
@ДжонниКэтсвилл А вы что, не понимаете, что c>>n выполняет попытку считать дальше этой 1 - ну, вдруг там 123 или 11 🙂 - т.е. он таки пытается читать за концом файла. Замените int на char и убедитесь, что выводится 000 . Так что, простите, мимо кассы.
Как определить конец файла?
Как различается конец и начало файла
Прочитал о файловой системе языке Си в книге Кернигана и Ричи, потом прочитал о ней же в книге.
Как определить конец файла?
В файле лежит одно число, которое нужно проверить на делимость на 11. Число большое-до 10^10000.
Как определить конец файла?
Здравствуйте, есть программа, в которой я открываю поток с помощью такой строки: file =.
Почетный модератор
7391 / 2637 / 281
Регистрация: 29.07.2006
Сообщений: 13,696
while(!feof(fp)).
Регистрация: 24.06.2013
Сообщений: 9
Спасибо, нашел ошибку в scanf'e
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
Помогаю со студенческими работами здесь
Как определить конец файла?
Добрый день! пищу скрипрт на WHS(VBS), нужно преребрать все строки в файле и что-то не.

System.IO Как определить конец файла?
Пишу программу которая симулирует авторизацию(логин\пароль, правильно не правильно). И столкнулся с.
Как определить конец текстового файла?
Собственно весь вопрос в заголовке. Пробовал с eof, но не получается. #include <fstream.h>.
Как определить конец файла при его считывании
Вот код программы, который должен выводить символы из файле input.txt в output но она выводит их.
Работа с текстовыми файлами
Теги: Текстовые файлы, fopen, fclose, feof, setbuf, setvbuf, fflush, fgetc, fprintf, fscanf, fgets, буферизированный поток, небуферизированный поток.
Работа с текстовыми файлами
Р абота с текстовым файлом похожа работу с консолью: с помощью функций форматированного ввода мы сохраняем данные в файл, с помощью функций форматированного вывода считываем данные из файла. Есть множество нюансов, которые мы позже рассмотрим. Основные операции, которые необходимо проделать, это
- 1. Открыть файл, для того, чтобы к нему можно было обращаться. Соответственно, открывать можно для чтения, записи, чтения и записи, переписывания или записи в конец файла и т.п. Когда вы открываете файл, может также произойти куча ошибок – файла может не существовать, это может быть файл не того типа, у вас может не быть прав на работу с файлом и т.д. Всё это необходимо учитывать.
- 2. Непосредственно работа с файлом - запись и чтение. Здесь также нужно помнить, что мы работаем не с памятью с произвольным доступом, а с буферизированным потоком, что добавляет свою специфику.
- 3. Закрыть файл. Так как файл является внешним по отношению к программе ресурсом, то если его не закрыть, то он продолжит висеть в памяти, возможно, даже после закрытия программы (например, нельзя будет удалить открытый файл или внести изменения и т.п.). Кроме того, иногда необходимо не закрывать, а "переоткрывать" файл для того, чтобы, например, изменить режим доступа.
Кроме того, существует ряд задач, когда нам не нужно обращаться к содержимому файла: переименование, перемещение, копирование и т.д. К сожалению, в стандарте си нет описания функций для этих нужд. Они, безусловно, имеются для каждой из реализаций компилятора. Считывание содержимого каталога (папки, директории) – это тоже обращение к файлу, потому что папка сама по себе является файлом с метаинформацией.
Иногда необходимо выполнять некоторые вспомогательные операции: переместиться в нужное место файла, запомнить текущее положение, определить длину файла и т.д.
Для работы с файлом необходим объект FILE. Этот объект хранит идентификатор файлового потока и информацию, которая нужна, чтобы им управлять, включая указатель на его буфер, индикатор позиции в файле и индикаторы состояния.
Объект FILE сам по себе является структурой, но к его полям не должно быть доступа. Переносимая программа должна работать с файлом как с абстрактным объектом, позволяющим получить доступ до файлового потока.
Создание и выделение памяти под объект типа FILE осуществляется с помощью функции fopen или tmpfile (есть и другие, но мы остановимся только на этих).
Функция fopen открывает файл. Она получает два аргумента – строку с адресом файла и строку с режимом доступа к файлу. Имя файла может быть как абсолютным, так и относительным. fopen возвращает указатель на объект FILE, с помощью которого далее можно осуществлять доступ к файлу.
FILE* fopen(const char* filename, const char* mode);
Например, откроем файл и запишем в него Hello World
#include #include #include void main() < //С помощью переменной file будем осуществлять доступ к файлу FILE *file; //Открываем текстовый файл с правами на запись file = fopen("C:/c/test.txt", "w+t"); //Пишем в файл fprintf(file, "Hello, World!"); //Закрываем файл fclose(file); getch(); >
Функция fopen сама выделяет память под объект, очистка проводится функцией fclose. Закрывать файл обязательно, самостоятельно он не закроется.
Функция fopen может открывать файл в текстовом или бинарном режиме. По умолчанию используется текстовый. Режим доступа может быть следующим
| Тип | Описание |
|---|---|
| r | Чтение. Файл должен существовать. |
| w | Запись нового файла. Если файл с таким именем уже существует, то его содержимое будет потеряно. |
| a | Запись в конец файла. Операции позиционирования (fseek, fsetpos, frewind) игнорируются. Файл создаётся, если не существовал. |
| r+ | Чтение и обновление. Можно как читать, так и писать. Файл должен существовать. |
| w+ | Запись и обновление. Создаётся новый файл. Если файл с таким именем уже существует, то его содержимое будет потеряно. Можно как писать, так и читать. |
| a+ | Запись в конец и обновление. Операции позиционирования работают только для чтения, для записи игнорируются. Если файл не существовал, то будет создан новый. |
Если необходимо открыть файл в бинарном режиме, то в конец строки добавляется буква b, например “rb”, “wb”, “ab”, или, для смешанного режима “ab+”, “wb+”, “ab+”. Вместо b можно добавлять букву t, тогда файл будет открываться в текстовом режиме. Это зависит от реализации. В новом стандарте си (2011) буква x означает, что функция fopen должна завершиться с ошибкой, если файл уже существует. Дополним нашу старую программу: заново откроем файл и считаем, что мы туда записали.
#include #include #include void main() < FILE *file; char buffer[128]; file = fopen("C:/c/test.txt", "w"); fprintf(file, "Hello, World!"); fclose(file); file = fopen("C:/c/test.txt", "r"); fgets(buffer, 127, file); printf("%s", buffer); fclose(file); getch(); >
Вместо функции fgets можно было использовать fscanf, но нужно помнить, что она может считать строку только до первого пробела.
fscanf(file, "%127s", buffer);
Также, вместо того, чтобы открывать и закрывать файл можно воспользоваться функцией freopen, которая «переоткрывает» файл с новыми правами доступа.
#include #include #include void main() < FILE *file; char buffer[128]; file = fopen("C:/c/test.txt", "w"); fprintf(file, "Hello, World!"); freopen("C:/c/test.txt", "r", file); fgets(buffer, 127, file); printf("%s", buffer); fclose(file); getch(); >
Функции fprintf и fscanf отличаются от printf и scanf только тем, что принимают в качестве первого аргумента указатель на FILE, в который они будут выводить или из которого они будут читать данные. Здесь стоит сразу же добавить, что функции printf и scanf могут быть без проблем заменены функциями fprintf и fscanf. В ОС (мы рассматриваем самые распространённые и адекватные операционные системы) существует три стандартных потока: стандартный поток вывода stdout, стандартный поток ввода stdin и стандартный поток вывода ошибок stderr. Они автоматически открываются во время запуска приложения и связаны с консолью. Пример
#include #include #include void main() < int a, b; fprintf(stdout, "Enter two numbers\n"); fscanf(stdin, "%d", &a); fscanf(stdin, "%d", &b); if (b == 0) < fprintf(stderr, "Error: divide by zero"); >else < fprintf(stdout, "%.3f", (float) a / (float) b); >getch(); >
Ошибка открытия файла
Если вызов функции fopen прошёл неудачно, то она возвратит NULL. Ошибки во время работы с файлами встречаются достаточно часто, поэтому каждый раз, когда мы окрываем файл, необходимо проверять результат работы
#include #include #include #define ERROR_OPEN_FILE -3 void main() < FILE *file; char buffer[128]; file = fopen("C:/c/test.txt", "w"); if (file == NULL) < printf("Error opening file"); getch(); exit(ERROR_OPEN_FILE); >fprintf(file, "Hello, World!"); freopen("C:/c/test.txt", "r", file); if (file == NULL) < printf("Error opening file"); getch(); exit(ERROR_OPEN_FILE); >fgets(buffer, 127, file); printf("%s", buffer); fclose(file); getch(); >
Проблему вызывает случай, когда открывается сразу несколько файлов: если один из них нельзя открыть, то остальные также должны быть закрыты
. FILE *inputFile, *outputFile; unsigned m, n; unsigned i, j; inputFile = fopen(INPUT_FILE, READ_ONLY); if (inputFile == NULL) < printf("Error opening file %s", INPUT_FILE); getch(); exit(3); >outputFile = fopen(OUTPUT_FILE, WRITE_ONLY); if (outputFile == NULL) < printf("Error opening file %s", OUTPUT_FILE); getch(); if (inputFile != NULL) < fclose(inputFile); >exit(4); > .
В простых случаях можно действовать влоб, как в предыдущем куске кода. В более сложных случаях используются методы, подменяющиее RAII из С++: обёртки, или особенности компилятора (cleanup в GCC) и т.п.
Буферизация данных
- 1) Если он заполнен
- 2) Если поток закрывается
- 3) Если мы явно указываем, что необходимо очистить буфер (здесь тоже есть исключения:)).
- 4) Также очищается, если программа завершилась удачно. Вместе с этим закрываются и все файлы. В случае ошибки выполнения этого может не произойти.
Форсировать выгрузку буфера можно с помощью вызова функции fflush(File *). Рассмотрим два примера – с очисткой и без.
#include #include #include void main() < FILE *file; char c; file = fopen("C:/c/test.txt", "w"); do < c = getch(); fprintf(file, "%c", c); fprintf(stdout, "%c", c); //fflush(file); >while(c != 'q'); fclose(file); getch(); >
Раскомментируйте вызов fflush. Во время выполнения откройте текстовый файл и посмотрите на поведение.
Буфер файла можно назначить самостоятельно, задав свой размер. Делается это при помощи функции
void setbuf (FILE * stream, char * buffer);
которая принимает уже открытый FILE и указатель на новый буфер. Размер нового буфера должен быть не меньше чем BUFSIZ (к примеру, на текущей рабочей станции BUFSIZ равен 512 байт). Если передать в качестве буфера NULL, то поток станет небуферизированным. Можно также воспользоваться функцией
int setvbuf ( FILE * stream, char * buffer, int mode, size_t size );
- _IOFBF - полная буферизация. Данные записываются в файл, когда он заполняется. На считывание, буфер считается заполненным, когда запрашивается операция ввода и буфер пуст.
- _IOLBF - линейная буферизация. Данные записываются в файл когда он заполняется, либо когда встречается символ новой строки. На считывание, буфер заполняется до символа новой строки, когда запрашивается операция ввода и буфер пуст.
- _IONBF – без буферизации. В этом случае параметры size и buffer игнорируются.
Пример: зададим свой буфер и посмотрим, как осуществляется чтение из файла. Пусть файл короткий (что-нибудь, типа Hello, World!), и считываем мы его посимвольно
#include #include #include void main() < FILE *input = NULL; char c; char buffer[BUFSIZ * 2] = ; input = fopen("D:/c/text.txt", "rt"); setbuf(input, buffer); while (!feof(input)) < c = fgetc(input); printf("%c\n", c); printf("%s\n", buffer); _getch(); >fclose(input); >
Видно, что данные уже находятся в буфере. Считывание посимвольно производится уже из буфера.
feof
Функция int feof (FILE * stream); возвращает истину, если конец файла достигнут. Функцию удобно использовать, когда необходимо пройти весь файл от начала до конца. Пусть есть файл с текстовым содержимым text.txt. Считаем посимвольно файл и выведем на экран.
#include #include #include void main() < FILE *input = NULL; char c; input = fopen("D:/c/text.txt", "rt"); if (input == NULL) < printf("Error opening file"); _getch(); exit(0); >while (!feof(input)) < c = fgetc(input); fprintf(stdout, "%c", c); >fclose(input); _getch(); >
Всё бы ничего, только функция feof работает неправильно. Это связано с тем, что понятие "конец файла" не определено. При использовании feof часто возникает ошибка, когда последние считанные данные выводятся два раза. Это связано с тем, что данные записывается в буфер ввода, последнее считывание происходит с ошибкой и функция возвращает старое считанное значение.
#include #include #include void main() < FILE *input = NULL; char c; input = fopen("D:/c/text.txt", "rt"); if (input == NULL) < printf("Error opening file"); _getch(); exit(0); >while (!feof(input)) < fscanf(input, "%c", &c); fprintf(stdout, "%c", c); >fclose(input); _getch(); >
Этот пример сработает с ошибкой (скорее всего) и выведет последний символ файла два раза.
Решение – не использовать feof. Например, хранить общее количество записей или использовать тот факт, что функции fscanf и пр. обычно возвращают число верно считанных и сопоставленных значений.
#include #include #include void main() < FILE *input = NULL; char c; input = fopen("D:/c/text.txt", "rt"); if (input == NULL) < printf("Error opening file"); _getch(); exit(0); >while (fscanf(input, "%c", &c) == 1) < fprintf(stdout, "%c", c); >fclose(input); _getch(); >
Примеры
1. В одном файле записаны два числа - размерности массива. Заполним второй файл массивом случайных чисел.
#include #include #include #include //Имена файлов и права доступа #define INPUT_FILE "D:/c/input.txt" #define OUTPUT_FILE "D:/c/output.txt" #define READ_ONLY "r" #define WRITE_ONLY "w" //Максимальное значение для размера массива #define MAX_DIMENSION 100 //Ошибка при открытии файла #define ERROR_OPEN_FILE -3 void main() < FILE *inputFile, *outputFile; unsigned m, n; unsigned i, j; inputFile = fopen(INPUT_FILE, READ_ONLY); if (inputFile == NULL) < printf("Error opening file %s", INPUT_FILE); getch(); exit(ERROR_OPEN_FILE); >outputFile = fopen(OUTPUT_FILE, WRITE_ONLY); if (outputFile == NULL) < printf("Error opening file %s", OUTPUT_FILE); getch(); //Если файл для чтения удалось открыть, то его необходимо закрыть if (inputFile != NULL) < fclose(inputFile); >exit(ERROR_OPEN_FILE); > fscanf(inputFile, "%ud %ud", &m, &n); if (m > MAX_DIMENSION) < m = MAX_DIMENSION; >if (n > MAX_DIMENSION) < n = MAX_DIMENSION; >srand(time(NULL)); for (i = 0; i < n; i++) < for (j = 0; j < m; j++) < fprintf(outputFile, "%8d ", rand()); >fprintf(outputFile, "\n"); > //Закрываем файлы fclose(inputFile); fclose(outputFile); >
2. Пользователь копирует файл, при этом сначала выбирает режим работы: файл может выводиться как на консоль, так и копироваться в новый файл.
#include #include #include #define ERROR_FILE_OPEN -3 void main() < FILE *origin = NULL; FILE *output = NULL; char filename[1024]; int mode; printf("Enter filename: "); scanf("%1023s", filename); origin = fopen(filename, "r"); if (origin == NULL) < printf("Error opening file %s", filename); getch(); exit(ERROR_FILE_OPEN); >printf("enter mode: [1 - copy, 2 - print] "); scanf("%d", &mode); if (mode == 1) < printf("Enter filename: "); scanf("%1023s", filename); output = fopen(filename, "w"); if (output == NULL) < printf("Error opening file %s", filename); getch(); fclose(origin); exit(ERROR_FILE_OPEN); >> else < output = stdout; >while (!feof(origin)) < fprintf(output, "%c", fgetc(origin)); >fclose(origin); fclose(output); getch(); >
3. Пользователь вводит данные с консоли и они записываются в файл до тех пор, пока не будет нажата клавиша esc. Проверьте программу и посмотрите. как она себя ведёт в случае, если вы вводите backspace: что выводится в файл и что выводится на консоль.
#include #include #include #define ERROR_FILE_OPEN -3 void main() < FILE *output = NULL; char c; output = fopen("D:/c/test_output.txt", "w+t"); if (output == NULL) < printf("Error opening file"); _getch(); exit(ERROR_FILE_OPEN); >for (;;) < c = _getch(); if (c == 27) < break; >fputc(c, output); fputc(c, stdout); > fclose(output); >
4. В файле записаны целые числа. Найти максимальное из них. Воспользуемся тем, что функция fscanf возвращает число верно прочитанных и сопоставленных объектов. Каждый раз должно возвращаться число 1.
#include #include #include #define ERROR_FILE_OPEN -3 void main() < FILE *input = NULL; int num, maxn, hasRead; input = fopen("D:/c/input.txt", "r"); if (input == NULL) < printf("Error opening file"); _getch(); exit(ERROR_FILE_OPEN); >maxn = INT_MIN; hasRead = 1; while (hasRead == 1) < hasRead = fscanf(input, "%d", &num); if (hasRead != 1) < continue; >if (num > maxn) < maxn = num; >> printf("max number = %d", maxn); fclose(input); _getch(); >
Другое решение считывать числа, пока не дойдём до конца файла.
#include #include #include #include #define ERROR_FILE_OPEN -3 void main() < FILE *input = NULL; int num, maxn, hasRead; input = fopen("D:/c/input.txt", "r"); if (input == NULL) < printf("Error opening file"); _getch(); exit(ERROR_FILE_OPEN); >maxn = INT_MIN; while (!feof(input)) < fscanf(input, "%d", &num); if (num >maxn) < maxn = num; >> printf("max number = %d", maxn); fclose(input); _getch(); >
5. В файле записаны слова: русское слово, табуляция, английское слово, в несколько рядов. Пользователь вводит английское слово, необходимо вывести русское.
Файл с переводом выглядит примерно так
солнце sun
карандаш pen
шариковая ручка pencil
дверь door
окно windows
стул chair
кресло armchair
и сохранён в кодировке cp866 (OEM 866). При этом важно: последняя пара cлов также заканчивается переводом строки.
Алгоритм следующий - считываем строку из файла, находим в строке знак табуляции, подменяем знак табуляции нулём, копируем русское слово из буфера, копируем английское слово из буфера, проверяем на равенство.
#include #include #include #include #define ERROR_FILE_OPEN -3 void main() < FILE *input = NULL; char buffer[512]; char enWord[128]; char ruWord[128]; char usrWord[128]; unsigned index; int length; int wasFound; input = fopen("D:/c/input.txt", "r"); if (input == NULL) < printf("Error opening file"); _getch(); exit(ERROR_FILE_OPEN); >printf("enter word: "); fgets(usrWord, 127, stdin); wasFound = 0; while (!feof(input)) < fgets(buffer, 511, input); length = strlen(buffer); for (index = 0; index < length; index++) < if (buffer[index] == '\t') < buffer[index] = '\0'; break; >> strcpy(ruWord, buffer); strcpy(enWord, &buffer[index + 1]); if (!strcmp(enWord, usrWord)) < wasFound = 1; break; >> if (wasFound) < printf("%s", ruWord); >else < printf("Word not found"); >fclose(input); _getch(); >
6. Подсчитать количество строк в файле. Будем считывать файл посимвольно, считая количество символов '\n' до тех пор, пока не встретим символ EOF. EOF – это спецсимвол, который указывает на то, что ввод закончен и больше нет данных для чтения. Функция возвращает отрицательное значение в случае ошибки.
ЗАМЕЧАНИЕ: EOF имеет тип int, поэтому нужно использовать int для считывания символов. Кроме того, значение EOF не определено стандартом.
#define _CRT_SECURE_NO_WARNINGS #include #include #include int cntLines(const char *filename) < int lines = 0; int any; //any типа int, потому что EOF имеет тип int! FILE *f = fopen(filename, "r"); if (f == NULL) < return -1; >do < any = fgetc(f); //printf("%c", any);//debug if (any == '\n') < lines++; >> while(any != EOF); fclose(f); return lines; > void main() < printf("%d\n", cntLines("C:/c/file.txt")); _getch(); >
ru-Cyrl 18- tutorial Sypachev S.S. 1989-04-14 sypachev_s_s@mail.ru Stepan Sypachev students

Всё ещё не понятно? – пиши вопросы на ящик