Инициализация указателей

Пермский национальный исследовательский

Политехнический университет

Кафедра «Информационные технологии и автоматизированные системы»

Лабораторная работа № 4,5

"Указатели"

 

 

Выполнила: студент группы РИС-16-1б

Муйдинов Б.М.

Проверил: доцент кафедры ИТАС

Полякова О.А.

 

Пермь, 2017

Содержание.

 

1. Понятие указателей

2. Виды указателей

3. Примеры указателей

4. Ссылки

5. Инициализация указателей

6. Операции с указателями

7. Указатели и одномерные массивы

8. Указатели и многомерные массивы

9. Использованная литература

 

Указатели.

Понятие указателей.

Указатель – переменная, которая хранит адрес области памяти.

Указатель не является самостоятельной типом, он всегда связан с другим конкретным типом.

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

 

Виды указателей.

Указатель на объект

- Содержит адрес области памяти, в которой хранятся данные определенного типа (основного или составного).

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

тип *имя;

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

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

Например: int *a, b, *с;

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

Размер указателя зависит от модели памяти.

Указатель на функцию

- Содержит адрес в сегменте кода, по которому располагается исполняемый код функции.

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

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

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

int (*fun) (double, double);

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

Указатель на void

- Указатель на неопределенный тип.

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

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

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

 

Примеры указателей:

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

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

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

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

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

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

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

 

Как видно из примеров, модификатор const, находящийся между именем указателя и звездочкой, относится к самому указателю и запрещает его изменение, а const слева от звездочки задает постоянство значения, на которое он указывает. Для инициализации указателей использована операция получения адреса &.

 

Ссылки.

Ссылка представляет собой синоним имени, указанного при инициализации

ссылки. Ссылку можно рассматривать как указатель, который всегда разыменовывается.

 

Формат объявления ссылки:

тип & имя;

где тип — это тип величины, на которую указывает ссылка, & — оператор ссылки, означающий, что следующее за ним имя является именем переменной ссылочного типа, например:

1nt kol;

1nt& pal = kol; // ссылка pal - альтернативное имя для kоl

const char& CR = ' \ n '; // ссылка на константу

Правила для ссылок:

1) Переменная-ссылка должна явно инициализироваться при ее описании, кроме случаев, когда она является параметром функции, описана как extern или ссылается на поле данных класса.

2) После инициализации ссылке не может быть присвоена другая переменная.

3) Тип ссылки должен совпадать с типом величины, на которую она ссылается.

4) Не разрешается определять указатели на ссылки, создавать массивы ссылок и ссылки на ссылки.

Ссылка, в отличие от указателя, не занимает дополнительного пространства в памяти и является просто другим именем величины. Операция над ссылкой приводит к изменению величины, на которую она ссылается.

Инициализация указателей.

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

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

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

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

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

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

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

int* г = р;

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

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

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

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

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

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

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

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

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

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

1nt* suxx = NULL;

1nt* rulez = 0;

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

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

Указатели чаще всего используют при работе с динамической памятью («куча»).

Динамическая память – это свободная память, в которой можно во время выполнения программы выделять место в соответствии с потребностями.

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

В C++ используется два способа работы с динамической памятью:

1) Через операции new и delete:

int * n = new int: //1

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

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

1: операция new выполняет выделение достаточного для размещения величины типа int участка динамической памяти и записывает адрес начала этого участка в переменную n. Память под саму переменную n выделяется на этапе компиляции.

2: кроме описанных выше действий, производится инициализация

выделенной динамической памяти значением 10.

3: операция new выполняет выделение памяти под 10 величин типа

int (массива из 10 элементов) и записывает адрес начала этого участка в переменную q. которая может трактоваться как имя массива.

Если память выделить не удалось, по стандарту должно порождаться исключение bad_alloc. Старые версии компиляторов могут возвращать 0.

Освобождаем память с помощью delete:

delete n; delete m; delete [ ] q;

Если память выделялась с помощью new[], для освобождения памяти необходимо применять delete[]. Размерность массива при этом не указывается. Если квадратных скобок нет, то никакого сообщения об ошибке не выдается, но помечен как свободный будет только первый элемент массива, а остальные окажутся недоступны для дальнейших операций. Такие ячейки памяти называются мусором.

 

2) Через семейство функций malloc, который достался в наследство от C:

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

4: операция malloc выполняет выделение достаточного для размещения величины типа int участка динамической памяти и записывает адрес начала этого участка в переменную u.

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

Освобождаем память с помощью функции free:

free(u);

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

Для того чтобы использовать malloc, требуется подключить к программе заголовочный файл <malloc.h>.

 


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: