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

3. Адреса и указатели

Адресом величины называется номер первого байта участка ОП, в котором располагается сама величина. Размер этого участка однозначно определяется типом переменной.

Указателем называется переменная, которая содержит адрес другой переменной или указывает адресом на переменную некоторого типа. Тип указателя – беззнаковое целое. Если указатель не указывает ни на какую переменную, то говорят, что он содержит нулевой адрес, записываемый с помощью константы NULL.

Объявление указателей:

< тип_адресуемой_переменной > *< имя_указателя >;

Для того чтобы вывести значение указателя на экран монитора, в функции printf() нужно использовать формат вывода %u.

Замечания:

  1. указатель всегда содержит адрес нулевого байта адресуемой переменной;

  2. тип адресуемой переменной, записанной при объявлении указателя, показывает, сколько байт оперативной памяти (далее ОП) будет адресовать указатель, начиная с нулевого байта адресуемой переменной, например: для символьного типа данных – 1 байт, для целого – 4 байта.

Операции над указателями:

  1. Унарные операции:

&<переменная> – операция получения адреса некоторой <переменной>;

*<переменная> – операция получения значения <переменной> по адресу в оперативной памяти (косвенная адресация):

int *p, t=4;

p=&t;

printf(“t=%i\n”,*p);

Данный пример можно отобразить в табличной форме.

Операция

Переменная

Значения переменных

Адрес переменной t = &p

p

1245048

Значение переменной t = *p

t

4

  1. Операции над указателями:

  • присваивание указателю нулевого адреса или адреса некоторой переменной;

  • увеличение или уменьшение значения указателя;

  • вычитание или сложение двух указателей (в этом случае указатели должны адресовать переменные одного и того же типа);

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

  • сравнение значений двух указателей при помощи операции отношения.

4. Указатели и массивы. Динамические массивы

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

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

При объявлении статического массива:

<тип_элементов_массива> <имя_массива> [<количество_элементов>];

<имя_массива> становится указателем на нулевой байт области памяти, выделяемой для размещения элементов массива, т.е. <имя_массива> будет содержать адрес первого элемента массива. <количество_элементов> – константное выражение, а <тип_элементов_массива> четко определяет размеры памяти, выделяемой для каждого элемента массива.

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

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

Схему решения задач с использованием динамических массивов можно описать следующим образом. Динамический массив объявляется как указатель на некоторый тип данных, затем запрашивается, сколько элементов будет содержать массив (или это число вычисляется). Затем при помощи функции выделения динамической памяти необходимо выделить нужный объем ОП из кучи и нулевой адрес выделенной динамической памяти присвоить объявленному ранее указателю. После этого происходит некоторая обработка элементов массива (решается задача). Если динамический массив будет не нужен для дальнейшего решения задачи, выделенная под него динамическая память освобождается при помощи функции освобождения динамической памяти.

Рассмотрим библиотечные функции выделения и освобождения динамической памяти. Функции malloc(), calloc(), realloc() динамически выделяют память в соответствии со значениями параметров и возвращают адрес нулевого байта выделенного участка памяти. Для универсальности тип возвращаемого значения каждой из этих функций есть void*. Указатель такого типа можно преобразовать к указателю любого типа с помощью операции приведения типа (<имя типа данных>*).

Функция free() освобождает память, выделенную перед этим с помощью одной из трех функций malloc(), calloc(), realloc(). Сведения о выделенном участке памяти передаются в функцию free() с помощью указателя. Функции работы с динамической памятью приведены в табл6.

Таблица 6

Функция

Форма обращения к функции и её краткое описание

malloc

p = (<тип_данных>*)malloc(n);

p – указатель на <тип_данных>; n – переменная типа unsigned int

Указатель p получает адрес нулевого байта выделенной динамической памяти размера в n байт

При неудачном завершении возвращает значение NULL

calloc

p = (<тип_данных>*)calloc(n, m);

p – указатель на <тип_данных>; n и m – переменные типа unsigned int

Указатель p получает адрес нулевого байта выделенной динамической памяти, необходимой для размещения n элементов по m байт каждый

При неудачном завершении возвращает значение NULL

realloc

p = (<тип_данных>*)realloc(pred_p , n);

p – указатель на <тип_данных>; n – переменная типа unsigned int; pred_p – указатель на <тип_данных> содержит адрес нулевого байта изменяемого блока

Указатель p получает адрес нулевого байта ранее выделенной области динамической памяти и изменяет размеры этой области до n байт. Если pred_p равен NULL (память не выделялась), то функция выполняется как malloc()

free

free(p);

p – указатель на <тип_данных>, адресующий ранее выделенный участок динамической памяти. Функция освобождает участок (блок) динамической памяти, адрес нулевого байта содержится в переменной p

При использовании данных функций необходимо подключать головной файл stdlib.h.