Студопедия

Главная страница Случайная страница

Разделы сайта

АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторикаСоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника






Указатели






Лабораторная работа №7. Указатели и ссылки. Имя массива как указатель. Динамические массивы

Цель и порядок работы

Цель работы – изучить работу с указателями, ссылками, получить навыки программирования с использованием динамических массивов.

 

Порядок выполнения работы:

- ознакомиться с описанием лабораторной работы;

- получить задание у преподавателя, согласно своему варианту;

- написать программу и отладить ее на ЭВМ;

- оформить отчет.

Краткая теория

Указатели

Когда компилятор обрабатывает оператор определения переменной, например

int i = 10;

он выделяет память в соответствии с типом (int) и инициализирует ее указанным значением (10). Все обращения в программе к переменной по ее имени (i) заменяются компилятором на адрес области памяти, в которой хранится значение переменной.

Программист может определить собственные переменные для хранения адресов областей памяти. Такие переменные называются указателями.

Указатели предназначены для хранения адресов областей памяти. В C++ различают три вида указателей – указатели на объект, на функцию и на void отличающиеся свойствами и набором допустимых операций. Указатель не является самостоятельным типом, он всегда связан с каким-либо другим конкретным типом.

Указатель на функцию содержит адрес в сегменте кода, по которому располагается исполняемый код функции, то есть адрес, по которому передается управление при вызове функции. Указатели на функции используются для косвенного вызова функции (не через ее имя, а через обращение к переменной, хранящей ее адрес), а также для передачи имени функции в другую функцию в качестве параметра. Указатель функции имеет тип “указатель функции, возвращающей значение заданного типа и имеющей аргументы заданного типа”:

 

тип (*имя) (список типов аргументов);

 

Например, объявление:

 

int (*fun) (double, double)

 

задает указатель с именем fun на функцию, возвращающую значение типа int и имеющую два аргумента типа double.

Указатель на объект содержит адрес области памяти, в которой хранятся данные определенного типа (основного или составного). Простейшее объявление указателя на объект (в дальнейшем называемого просто указателем) имеет вид:

 

тип *имя;

 

где тип может быть любым, кроме ссылки и битового поля, причем тип может быть к этому моменту только объявлен, но еще не определен (следовательно, в структуре, например, может присутствовать указатель на структуру того же типа).

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

 

int *a, b, *c;

 

описываются два указателя на целое с именами а и с, а также целая переменная b. Размер указателя зависит от модели памяти. Можно определить указатель на указатель и т.д.

Указатель на void применяется в тех случаях, когда конкретный тип объекта, адрес которого требуется хранить, не определен (например, если в одной и той же переменной в разные моменты времени требуется хранить адреса объектов различных типов).

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

Существует специальная операция взятия адреса, обозначаемая символом &. Ее результатом является адрес объекта.

Указатель может быть константой или переменной, а также указывать на константу или переменную. Рассмотрим примеры:

 

int j; // целая переменная

const int ci = 1; // целая константа

int *рi; // указатель на целую переменную

const int *pci; // указатель на целую константу

int * const ср = & i; // указатель-константа на целую переменную

const int * const срс = & ci // указатель-константа на целую константу

 

 

Указатели чаще всего используют при работе с динамической памятью или кучей (от англ. heap). Это свободная память, в которой можно во время выполнения программы выделять место в соответствии с потребностями. Доступ к выделенным участкам динамической памяти, называемым динамическими переменными, производится только через указатели. Время жизни динамических переменных – от точки создания до конца программы или до явного освобождения памяти. В C++ используется два способа работы с динамической памятью. Первый использует семейство функций malloc и достался в наследство от языка C, второй использует операции new и delete.

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

Существуют следующие способы инициализации указателя:

1. Присваивание указателю адреса существующего объекта:

• с помощью операции получения адреса:

 

int а = 5; // целая переменная

int* p = & a; // в указатель записывается адрес а

int* р (& а); // то же самое другим способом

 

• с помощью значения другого инициализированного указателя:

 

int* r = р;

 

• с помощью имени массива или функции, которые трактуются как адрес:

int b[10]; // массив

int* t = b; // присваивание адреса начала массива

 

void f(int а){ /*... */ } // определение функции

void (*pf) (int); // указатель на функцию

pf = f; // присваивание адреса функции

 

2. Присваивание указателю адреса области памяти в явном виде:

 

char* cp = (char *) 0хВ8000000;

 

Здесь 0хВ8000000 — шестнадцатеричная константа, (char *) – операция приведения типа: константа преобразуется к типу «указатель на char».

3. Присваивание пустого значения:

 

int* suxx = NULL;

int* rulez = 0;

 

В первой строке используется константа NULL, определенная в некоторых заголовочных файлах C как указатель, равный нулю. Рекомендуется использовать просто 0, так как это значение типа int будет правильно преобразовано стандартными способами в соответствии с контекстом.

4. Выделение участка динамической памяти и присваивание ее адреса указателю:

• с помощью операции new:

 

int* n = new int; // 1

int* m = new int (10); // 2

int* q = new int [10]; // 3

 

• с помощью функции mallос:

 

int* u = (int *)malloc(sizeof(int)); // 4

 

В операторе 1 операция new выполняет выделение достаточного для размещения величины типа int участка динамической памяти и записывает адрес начала этого участка в переменную n. Память под саму переменную n (размера, достаточного для размещения указателя) выделяется на этапе компиляции. В операторе 2, кроме описанных выше действий, производится инициализация выделенной динамической памяти значением 10.

В операторе 3 операция new выполняет выделение памяти под 10 величин типа int (массива из 10 элементов) и записывает адрес начала этого участка в переменную q, которая может трактоваться как имя массива. Через имя можно обращаться к любому элементу массива.

В операторе 4 делается то же самое, что и в операторе 1, но с помощью функции выделения памяти malloc, унаследованной из библиотеки С. В функцию передается один параметр – количество выделяемой памяти в байтах.

Операцию new использовать предпочтительнее, чем функцию malloc, особенно при работе с объектами.

Освобождение памяти, выделенной с помощью операции new, должно выполняться с помощью delete, а для выделенной с помощь malloc осовобождаться с помощью free.

 

Для описанных выше переменных освобождение памяти будет выглядеть так:

 

delete n; // 1

delete m; // 2

delete []q; // 3

free(u); // 4

 

При выделении памяти с помощью new[], необходимо применять delete[]. Размерность массива при этом не указывается.

 






© 2023 :: MyLektsii.ru :: Мои Лекции
Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав.
Копирование текстов разрешено только с указанием индексируемой ссылки на источник.