Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лекции программирование.doc
Скачиваний:
38
Добавлен:
05.11.2018
Размер:
4.73 Mб
Скачать

Работа с дисками.

Библиотека Си поддерживает следующие три уровня ввода-вывода:

  • ввод-вывод потока;

  • ввод-вывод нижнего уровня;

  • ввод-вывод для консоли и порта.

Ввод-вывод потока.

При вводе вывода потока все данные рассматриваются как поток отдельных байтов. Для пользователя поток – это либо файл на диске, либо физическое устройство, например, такое, как дисплей или печатающее устройство. Поэтому, когда пользователь выполняет операции ввода-вывода для потока, то имеется в виду, что он работает либо с файлами, либо с устройством.

Ввод вывод потока позволяет:

  • открывать и закрывать потоки;

  • создавать и удалять временные потоки;

  • читать и записывать символ;

  • читать и записывать строки;

  • читать и записывать форматированные данные;

  • читать и записывать неформатированные данные;

  • анализировать ошибки ввода-вывода потока и условия конца потока (конца файла);

  • управлять буферизацией потока и размером буфера;

  • выгружать буфера, связанные с потоками;

  • получать и устанавливать указатель текущей позиции в потоке.

Чтобы использовать функции ввода-вывода потока в программе

необходимо директивой #include включить файл stdio.h. Этот файл содержит объявления функций ввода-вывода, а также определения констант, типов и струк4тур, используемых фунциями потока.

Открытие потока.

Перед выполнением операций ввода-вывода для потока его нужно открыть. Когда поток открывается для операций ввода-вывода, он связывается со структурой предопределённого типа 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 тип_элемента[размер ] . . . [размер]

Заметим, что не предусмотрено средств для инициализации динамических массивов, и для размещаемых массивов должны быть определены все размерности, более того, только первая размерность может быть задана с помощью переменой, все остальные размерности многомерных массивов должны быть заданы с помощью константы. Результатом операции является указатель на начало созданного массива.

Пример размещения в памяти трехмерного динамического массива

long (*p) [3][4]; // описание указателя

p=new long [2][3][4]; // размещение массива

p[1][1][1]=1; // обращение к элементу

После того, как в динамической переменной отпала надобность, её можно удалить, освоботив используемую ею память для других целей. Например, созданные переменные уничтожаются следующими командами

delete i; delete j; delete[] p;

Создание многомерных динамических массивов с переменным количеством элементов

double **a=new double *[n];

for(int i=0; i<n;i++) a[i]=new double[m];

a[1][1]=1.0;

for(int i=0; i<n;i++) delete[] a[i]; delete[] a;