- •Пространство имен.
- •Представление целых чисел
- •Определение переменных
- •Особенности использования некоторых типов данных: переполнение регистров переменных
- •Базовые конструкции структурного программирования
- •Условный оператор if
- •Ветвление процесса выполнения программ
- •Тема: Указатели и ссылки
- •Адреса переменных. Оператор взятия адреса
- •Указатели
- •Динамически распределяемая память
- •Указатели на объекты
- •Выделяют два основных отличия между статическими и динамическими объектами.
- •Перегрузка функций
- •Значения параметров функции, используемые по умолчанию
- •Определение массива
- •“Sdjdkjdhkfsdjhvm,c,bnmsierhoerhsdklfhbnasmbf”; //правильно Пустая строка записывается “ ” и имеет тип const char[1]. Использование датчика случайных чисел для формирования массива
- •Конструкторы и деструкторы
Динамически распределяемая память
На практике использование указателей, так как это было показано выше, встречается редко – примеры приведены для демонстрации механизма работы указателей.
Реально указатели применяются в следующих случаях:
управление данными в свободной (динамической) области памяти;
передача данных между функциями по ссылке.
Все переменные, объявленные в программе размещаются в одной непрерывной области памяти, которую называют сегментом данных. Такие переменные не меняют своего размера в ходе выполнения программы и называются статическими. Размера сегмента данных может быть недостаточно для размещения больших массивов информации. Выходом из этой ситуации является использование свободной или динамически распределяемой памяти (динамической памяти).
Динамическая память – может быть представлена как огромный массив последовательно пронумерованных ячеек, предназначенных для хранения данных.
Ячейкам свободной памяти нельзя присвоить имя, можно лишь зарезервировать определенное количество ячеек и запомнить их адрес в указателе. С помощью указателей и осуществляется доступ к участкам динамической памяти.
Важным преимуществом динамической памяти является то, что выделенная в ней область не может использоваться в других целях до тех пор, пока не будет освобождена явно. Поэтому, если во время работы функции в динамической памяти выделяется область, ее можно использовать и по завершении работы функции. Другим преимуществом использования динамической памяти является то, что доступ к данным в ней можно получить только из тех функций, которые обладают доступом к указателю, хранящему нужный адрес. Это позволяет избегать нежелательного или случайного изменения данных.
Для выделения участка памяти в динамически распределяемой области используют ключевое слово new:
указатель = new выражение;
Аргументом для оператора new служит выражение, возвращающее число байтов, которые необходимо зарезервировать в области динамической памяти.
Например, чтобы создать в динамической памяти переменную типа unsigned short необходимо записать:
unsigned short int *ptr = new unsigned short int;
Выражение new unsigned short int выделяет два байта динамической памяти.
Если до этого указатель был инициализирован, то в выделенный участок памяти будет занесено значение, указанное в инициализаторе.
Кроме того, ptr указывает на переменную типа unsigned short int, размещенную в динамически распределяемой памяти. Строку
*ptr = 21;
можно прочитать: «разместить число 21 в той области динамически распределяемой памяти, на которую указывает ptr».
По завершении работы с выделенной областью памяти ее следует освободить. Сама она не освобождается автоматически при выходе из функции и остается занятой, а программа не сможет ею воспользоваться. Если функция часто вызывается, памяти будет оставаться все меньше и наступит момент, когда ее не останется вовсе, и программа аварийно завершиться. Чтобы этого не произошло, когда необходимость в выделенном участке памяти отпадает, его надо освободить используя оператор delete:
delete указатель;
Здесь указатель содержит адрес участка памяти, ранее выделенный с помощью операции new.
Например,
delete p;
где p ранее объявлен как указатель.
Так происходит освобождение участка динамической памяти, адрес которого находится в указателе. Сам указатель при этом сохраняется, как обычная переменная и ему может быть передан на хранение другой адрес.
Когда оператор delete применяется к указателю, происходит освобождение области динамической памяти, на которую этот указатель ссылается. Повторное применение оператора delete к этому же указателю приведет к зависанию программы. Рекомендуется при освобождении области динамической памяти присваивать связанному с ней указателю нулевое значение (0 либо NULL) – вызов оператора delete для нулевого указателя не приведет к описанной выше проблеме.
Ниже приведен пример создания и удаления указателей.
//Пример_9
#include <iostream>
using namespace std;
int main()
{
int Var = 7; // объявление и инициализация переменной Var
int *ptrVar =&Var; // объявление указателя и присвоение ему адреса
int *ptrHeap=new int; // объявлен еще один указатель, а в динамической
// памяти выделено пространство для переменной типа int
*ptrHeap=21; // участку динамической памяти присвоено значение
cout<<"Value Var: "<<Var<<endl; // вывод содержимого переменной Var
cout<<"Value *ptrVar: "<<*ptrVar<<endl; // вывод значения,
//на которое указывает ptrVar
cout<<"Value *ptrHeap: "<<*ptrHeap<<endl; // вывод значения, на
// которое указывает ptrHeap
delete ptrHeap; // освобождение участка динамической памяти,
// указатель ptrHeap пуст и пригоден для записи
// адреса другого участка памяти
ptrHeap = new int; // в динамической памяти вновь выделено
// пространство для переменной типа int
*ptrHeap=3; // участку динамической памяти присвоено новое значение
cout<<"Value *ptrHeap: "<<*ptrHeap<<endl; // вывод значения, на
// которое указывает ptrHeap
delete ptrHeap; // освобождение участка динамической памяти
return 0;
}