Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Семестр_2_С++.doc
Скачиваний:
4
Добавлен:
23.04.2019
Размер:
217.09 Кб
Скачать

7. Указатели, массивы

7.1. Понятие адреса

Оперативная память компьютера в простейшем случае может быть представлена в виде последовательности пронумерованных по порядку ячеек. Каждая переменная занимает одну или несколько ячеек памяти, в зависимости от ее типа. Номер первой ячейки, занимаемой переменной, называется ее адресом. При этом, имя переменной можно представить как надпись на ячейках памяти, по которой, не зная адреса, можно ее найти. Однако существует ряд задач, в которых этой информации не достаточно, и работать с адресами необходимо.

Чтобы получить адрес переменной перед ее именем следует поставить знак & (амперсант). Выражение вида &Имя имеет результатом адрес переменной. В данном случае операция & является унарной и называется операцией получения адреса.

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

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

int L =-5;

int D = 27;

double S = 2.15;

Имя переменной: L D S

Машинный адрес: 0064fe00 0064fdfc 0064fdf4

Значение в памяти: -5 27 2.15

В соответствии с приведенной таблицей объявленные переменные размещены в памяти с байта, имеющего шестнадцатеричный адрес 0064fdf4. Переменная целого типа (int) занимает четыре байта, переменная типа double - восемь байт памяти. При таких требованиях к памяти в данном примере &L = 0064fe00, &D = 0064fdfc, &S = 0064fdf4. Следует отметить, что адреса имеют целочисленные беззнаковые значения, и их можно обрабатывать как целочисленные величины.

В большинстве современных компьютеров адрес представляет собой четырехбайтовое число. Программа для демонстрации адресов переменных и функций:

include <stdio.h>

int a, b;

int main()

{

int k, m;

cout << "Глобальные переменные:" << endl;

cout << &a << " " << &b << endl;

cout << "Локальные переменные:" << endl;

cout << &k << " " << &m << endl;

return 0;

}

Результат выполнения программы:

Глобальные переменные:

0x0040b8c8 0x0040b8cc

Локальные переменные:

0x0064fe00 0x0064fdfc

7.2. Указатели

Для работы с адресами в языке Си++ предусмотрен специальный тип переменных - указатели. Указатель - переменная, содержащая адрес другой переменной некоторого типа. Указатель объявляется как и переменная, на которую он указывает, только перед его именем ставится знак *(звездочка):

Тип * ИмяУказателя;

где Тип - тип данных, адрес которых может содержаться в данном указа теле;

*- признак того, что объявлена не обычная переменная, а указатель;

ИмяУказателя – любой идентификатор.

Указатель может быть объявлен в одном списке с переменными и массивами, например:

float a, b, *p, А[10];

Переменной типа указатель можно присвоить адрес любой переменной, тип которой совпадает с типом указателя. Например, p=&a;

Если переменная, адрес которой должен содержаться в указателе, объявлена до объявления указателя, то указателю можно присвоить адрес переменной прямо при его объявлении, т.е. проинициализировать указатель адресом переменной:

int a;

int *b = &a;

После выполнения данной операции указатель b будет хранить адрес переменной a, и доступ к значению переменной a будет возможен как с помощью ее имени а, так и с помощью адреса, являющего значением указателя в. В последнем случае должна применяться операция разыменования * (операция получения значения через указатель), например, *b. Присвоив указателю адрес конкретного участка памяти, можно с помощью операции разыменования не только получать его содержимое, но и изменять его. Таким образом, записи

a=5; и *b = 5; равнозначны.

С помощью операции разыменования значение переменной можно использовать в математических и логических выражениях:

Записи k=3+a*7; и k = 3 + (*b) * 7; равнозначны.

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

Например, cout<<a<<' '<<&a; распечатаем значение и адрес переменной а.

Некоторые особенности объявления и использования указателей

Указателю можно присвоить нулевой адрес.

b = 0;

Существует стандартная описанная во многих заголовочных файлах константа NULL, обозначающая нулевой адрес. Таким образом, предыдущему оператору равносилен следующий:

b = NULL;

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

int a = 15, k=10;

const int* b =&a;

наличие ключевого слова const означает, что указатель содержит адрес константы, следовательно, значение, находящиеся по адресу, меняться не может. В данном случае при выполнении оператора *b = 7; компилятором будет выдано сообщение об ошибке, но возможно выполнение оператора b = &k;.

Если же слово const стоит между символом * и именем указателя, то сам указатель является константой:

int a = 15, k=10;

int* const b = &a;

При этом, можно выполнить оператор *b = 7;, но b = &k; - нельзя, компилятором будет выдано сообщение об ошибке.

Если же в объявлении будет два ключевых слова const,

const int a = 15, k = 10;

const int* const b = &a;

нельзя изменить ни сам указатель, ни значение, находящееся по адресу в нем.