Перед выполнением операций ввода-вывода для потока его нужно открыть. Когда поток открывается для операций ввода-вывода, он связывается со структурой предопределённого типа FILE, содержащей всю необходимую информацию для работы с потоком: такую, как указатель текущей позиции в потоке, указатель на буфер связанный с потоком, тип доступа к потоку и др.. При открытии потока возвращается указатель на структуру FILE, называемый указателем потока.
Для открытия потока библиотека Си представляет три функции: fopen и fdopen открывают потоки, а freopen переназначает указатель на другой поток.
При успешном открытии потока функции открытия возвращают указатель на структуру FILE, в противном случае возвращается нулевой указатель (NULL).
#include <stdio.h>
…
FILE *file_ptr;
…
if(file_ptr=fopen(…)== NULL)
printf(“\n Ошибка открытия файла”);
Тип доступа к потоку задаётся как аргумент функции открытия. Он является строковым литералом, который может принимать значения:
“r” - поток открывается для чтения;
“w” - открывается пустой поток для записи. Если поток
существует, его содержимое пропадает;
“a” - поток открывается для записи в конец потока. Если поток
не существует, он создаётся;
“r+” - поток открывается для чтения и записи (поток должен
существовать);
“w+” - открывается пустой поток для чтения и записи. Если
поток существует, его содержимое пропадает;
“a+” - поток открывается для чтения и записи в конец
потока. Если поток не существует, он создаётся.
#include <stdio.h>
…
FILE *file_ptr;
…
if(file_ptr=fopen(“a:file.dat”,”r”)== NULL)
printf(“\n Ошибка открытия файла”);
else
printf(“\n Файл открыт для чтения”);
Операции чтения и записи для потока начинаются с текущей позиции потока, определяемой указателем текущей позиции в потоке.
Библиотека Си предоставляет следующие функции для позиционирования указателя текущей позиции в потоке:
ftell(fp) и fgetpos получают текущую позицию указателя потока
fseek и fsetpos устанавливают текущую позицию указателя в потоке
rewind(fp) позиционирует указатель потока на начало потока.
Новая позиция указателя потока в функции fseek задаётся как смещение от некоторой начальной позиции, которая может быть одним из следующих значений
SEEK_SET - начало потока,
SEEK_CUR – текущая позиия указателя потока,
SEEK_END – конец потока.
ПРИМЕР использования функции fseek
FILE *fp;
long n;
…
fseek(fp,0L, SEEK_SET);//Позиционирование на начало потока
fseek(fp,0L, SEEK_END); //Позиционирование на конец потока
fseek(fp,n, SEEK_SET); //Позиционирование на n
//байт от начала потока
fseek(fp, n, SEEK_END); //Позиционирование на n
//байт от конца потока
fseek(fp, n, SEEK_CUR); //Позиционирование на n
//байт от текущей позиции
fseek(fp,- n, SEEK_CUR); //Позиционирование на n
//байт до текущей позиции
fseek(fp,- n, SEEK_ END); //Позиционирование на n
//байт до конца потока
Пример
Пусть имеется структура
sruct h_main
{
int tipe;
char s[20];
char s2[20];
char s[320];
}
sruct h_main m;
//позиционирование курсора на начало i–й записи структуры в файле
fseek(fmain, i*sizeof(m), SEEK_SET);
чтение
fread(&m, i*sizeof(m), 1, fmain);
запись
fwrite(&m, i*sizeof(m), 1, fmain);
Операции динамического распределения памяти.
Операции new, new[ ],delete, delete[ ] введены в язык С++ с целью решения одной из задач управления памятью, а именно – её динамического распределения. Две операции new, new[ ] предназначены для выделения участков свободной памяти и размещения в них переменных (new[ ] – массивов). Продолжительность существования таким образом созданных (динамических) переменных – от точки создания до конца программы или до явного освобождения соответсвующего участка памяти применением операций delete (delete[] – для удаления массивов).
Первая из рассматриваемых операций предназначена для размещения в динамической памяти переменной заданного аргументом типа (кроме типов массивов) и имеет следующий общий тип
new имя_типа или new имя_типа(выражение)
Вторая форма помимо выделения памяти осуществлвяет её инициализацию значением выражения. В обоих случаях результат операции имеет тип указателя того же типа что и аргумент, (т.е. имя_типа), и значение адреса размещенной динамической переменной. Это значение, очевидно, нужно сохратить в какой-либо переменной-указателе, что обеспечит в дальнейшем доступ к динамической переменной.
Пример создания и использования двух динамических переменных:
int *i = new int, *j = new(5);
*i=*j**j ;
Для размещения динамических массивов предусмотрена специальная операция new[ ], вызываемая следующим образом:
new тип_элемента[размер ] . . . [размер]
Заметим, что не предусмотрено средств для инициализации динамических массивов, и для размещаемых массивов должны быть определены все размерности, более того, только первая размерность может быть задана с помощью переменой, все остальные размерности многомерных массивов должны быть заданы с помощью константы. Результатом операции является указатель на начало созданного массива.
Пример размещения в памяти трехмерного динамического массива