|
Программирование >> Процедурные приложения
требуемому типу. Обобщенный указатель сам по себе не может быть использован для обращения к каким-нибудь данным, так как он не связан ни с одним из базовых типов данных. Но любой указатель может быть приведен к типу void и обратно без потери информации. В следующем фрагменте программы резервируется память для 300 чисел типа float: float *pf; int inura floats = 300; pf = (float *) malloc(inum floats * sizeof(float)); В данном примере функция malloc() резервирует блок памяти, достаточный для хранения 300 значений типа float. Выделенный блок надежно отделен от других блоков и не перекрывается ими. Предугадать, где именно он будет размещен, невозможно. Все блоки особым образом помечаются, чтобы система могла легко их обнаруживать и определять их размер. Если блок ячеек больше не нужен, его можно освободить следующей строкой: free ((void*) pf); В C/C++ резервирование памяти осуществляется двумя способами. Так, при объявлении переменной указатель стека программы продвигается ниже по стеку, захватывая новую ячейку. Когда переменная выходит за пределы своей области видимости, область памяти, отведенная для переменной, автоматически освобождается путем перемещения указателя назад, выше по стеку. Размер необходимой стековой памяти всегда должен быть известен еще до начала компиляции. Но иногда в программе необходимо создавать переменные, размер которых неизвестен заранее. В таких случаях ответственность за резервирование памяти возлагается на программиста, и для этих целей используется динамическая область. В программах на языках C/C++ резервирование и освобождение блоков памяти в динамической области может происходить в любой момент времени. Также важно запомнить, что объекты, хранимые в динамической области, в отличие от обычных переменных, не подчиняются правилам видимости. Они никогда не могут оказаться вне области видимости, поэтому вы же ответственны за то, чтобы освободить зарезервированную память, как только отпадет необходимость в соответствующем объекте. Если вы не позаботитесь об освобождении неиспользуемой памяти, а будете создавать все новые и новые динамические объекты, то рано или поздно программа столкнется с недостатком свободной памяти. В компиляторах языка С для управления динамической памятью используются библиотечные функции malloc() и free(),которые мы только что рассмотрели. Создатели языка C++ посчитали оперирование свободной памятью столь важной задачей для работы программы, что добавили дополнительные операторы new и delete, аналогичные вышеуказанным функциям. Аргументом для оператора new служит выражение, возвращающее число байтов, которое необходимо зарезервировать. Этот оператор возвращает указатель на начало выделенного блока памяти. Аргументом оператора delete выступает адрес первой ячейки блока, который необходимо освободить. В следующих двух примерах демонстрируются различия в синтаксисе программ на языках С и C++, работающих с динамической областью памяти. Вот пример программы на языке С: * malloc.c * Эта программа на языке С демонстрирует применение * функций malloc() иfree() #include <stdio.h> #include <stdlib.h> #define ISIZE 512 void main() int *pimemory buffer; pimemory buffer = malloc(iSIZE * sizeof (int)) ; if(pimemory buffer == NULL) printf( Недостаточно памяти\n ); else printf( Память зарезервирована\n ); free(pimemory buffer) ; Первое, на что следует обратить внимание еще в начале программы, - это подключение к программе файла STDLIB.H, содержащего прототипы функций malloc() и free().Функция malloc() передает указателю pimemory buffer адрес зарезервированного блока размером ISIZE*sizeof(int). Надежный алгоритм всегда должен включать проверку успешности резервирования памяти, поэтому указатель проверяется на равенство значению null, Функция malloc() всегда возвращает null, .если выделить память не удалось. Программа завершается вызовом функции free(), которая освобождает только что зарезервированную область памяти. Программа на языке C++ мало отличается от предыдущего примера: newdel.cpp Эта программа на языке C++ демонстрирует применение операторов new и delete. #include <iostream.h> #define NULL 0 #define ISIZE 512 void main() int *pimemory buffer; pimemory buffer = new int[ISIZE]; if(pimemory buffer == NULL) cout<< Недостаточно памяти\n ; else cout<< Память зареэервирована\n ; delete(pimemory buffer); } Необходимости в подключении файла STDLIB.H здесь нет, так как операторы new и delete являются встроенными компонентами языка. В отличие от функции malloc(), где для определения точного размера блока применяется оператор sizeof, оператор new автоматически выполняет подобного рода вычисления, основываясь на заданном типе объекта. В обеих программах резервируется блок из 512 смежных ячеек типа int. Указатели типа void Если бы все указатели имели стандартный размер, не было бы необходимости на этапе компиляции определять тип адресуемой переменной. Кроме того, с помощью стандартизированного указателя можно было бы передавать в функции адреса переменных любого типа, а затем, в теле функции, привести указатель к требуемому типу в соответствии с полученной дополнительной информацией. Используя такой подход, можно создавать универсальные функции, подходящие для обработки данных разного типа. Вот почему в язык C++ был добавлен указатель типа void. Использование ключевого слова void при объявлении указателя имеет другой смысл, чем в списке аргументов или в качестве возвращаемого значения ( в этих случаях void означает ничего ). Указатель на void - это универсальный указатель на данные любого типа. В следующей программе на языке С++ демонстрируется применение таких указателей: voidpt.cpp Эта программа на языке С++ демонстрирует применение указателей типа void. #include <iostream.h> #define ISTRING MAX 5 0 void voutput(void *pobject, char cflag) void main() { int *pi; char *psz; float *pf; char cresponse, cnewline; cout << Задайте тип данных, которые\n ; cout << вы хотите ввести.\n\n ; cout << (s)tring, (i)nt, (f)loat: ; cin >> cresponse; switch(cresponse) { case s: psz = new char [ISTRING MAX]; cout << \nВведите строку: ; cin.get (psz, cresponse); voutput (pi, cresponse); break; case i: pi = new int; cout << \nВведите целое число : ; cin >> *pi; voutput (pi, cresponse); break; case f: pf = new float; cout << \nВведите число с плавающей запятой: ; cin >> *pf; voutput (pi, cresponse); break; default: cout << \n\nТакой тип данных не поддерживается! ; void voutput(void *pobject, char cflag) switch(cflag) { case s: cout << \пВы ввели строку << (char *) pobject; delete pobject; break; case i: cout<< \пВы ввели целое число << *((int*) pobject); delete pobject; break; case f: cout<< \пВы ввели число с плавающей запятой << *((float *) pobject); delete pobject; break; Прежде всего обратите внимание на прототип функции voutput( ) , в частности на то, что первый параметр функции - pobject- представляет собой обобщенный указатель void*. В функции main()создаются указатели трех конкретных типов: int*, char* и float*. Они будут использоваться в зависимости от того, какого типа данные введет пользователь. Выполнение программы начинается с выдачи пользователю приглашения указать тип данных, которые он собирается вводить. Вас может удивить, почему для считывания ответа используются две различные команды. Первый объект cin считывает символ, введенный
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |