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


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

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

Подобно тому, как переменная типа char имеет в качестве значения символ, а переменная типа int – целочисленное значение, переменная типа указатель имеет в качестве значения адрес ячейки оперативной памяти. Допустимые значения для переменной-указателя – множество адресов оперативной памяти компьютера. Указатель – это особый вид переменной, значением которой является адрес другой переменной определённого типа. Указатель является одним из наиболее важных понятий языка C++.

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

Под адресом будем понимать местоположение ячейки памяти. В общем случае сам адрес занимает 4 байта.

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

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

тип_данных * имя_указателя;

где тип_данных – тип, на который будет указывать указатель;

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

имя_указателя – имя переменной-указателя.

Примеры объявления указателей:

int * pi; // указатель на тип int

float *pf; // указатель на тип float

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

int x, b, *pint, a[10];

но лучше их объявлять отдельно.

В С++ существует общепринятое соглашение – называть переменные-указатели именами, начинающимися с латинской буквы p. Это позволяет сразу увидеть, какие переменные являются указателями, что, в свою очередь, упрощает восприятие программ.

Операция адреса

Для получения адреса переменной используется операция адреса (&). Она представляет собой унарную операцию, результатом выполнения которой является адрес переменной в памяти – своего операнда.

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

int b =-5;

int c = 27;

double d = 2.15;

cout<<&b<<' '<<&c<<' '<<&d<<endl;

cout<<b<<' '<<c<<' '<<d<<endl;

Результат:

Имя переменной: b c d

Адрес: 0064fe00 0064fdfc 0064fdf4

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

Переменная целого типа int занимает четыре байта, переменная типа doubleвосемь байтов памяти. При таких требованиях к памяти в данном примере &b = 0064fe00, &c = 0064fdfc, &d= 0064fdf4.

Следует отметить, что адреса имеют целочисленные беззнаковые значения, и их можно обрабатывать как целочисленные величины.

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

&(x + 6) и &15не допустимы.

Переменная-указатель хранит адрес ячейки памяти, который можно получить, используя операцию адреса (&):

int x = 5; int *p = &x;

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

float * p; char c; p = &c; //ошибка компиляции

Операция разыменования

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

Выражение *p разыменовывает указатель, разрешая доступ к содержимому ячейки по адресу p:

int x = 5; int *p = &x;

cout<<x<<' '<<*p<<endl; //5 5

Из примера видно, что после присваивания указателю p адреса переменной x, переменная x и указатель p оказываются связанными между собой, и к значению переменной x можно обращаться непосредственно, через имя переменной x, или косвенно, через указательp.

Операция разыменования * (или операция косвенной адресации) – унарная операция для доступа к значению переменной, расположенной по адресу операнда.

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

*p = 10; // запись значения 10 по адресу, хранящемуся в p

После выполнения этого оператора значение переменной x, на которую указывает указатель p, станет равным 10.

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

к = 3 + x * 7; и k = 3 + (*p) * 7; – записи равнозначны.

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

cout<<x<<" "<<&x<<endl;

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

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

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

· присваивание указателю адреса существующего объекта (переменной, массива и др.) с помощью операции адреса (&):

int a = 5;

int * p = &a; или int * p(&a);

· присваивание указателю пустого значения:

int *p = NULL; или int * p = 0

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

int * p1 = p; или int * p1(p);

· c помощью имени массива:

int b[10]; int *p = b; (cм. главу 8)

· присваивание адреса динамической памяти:

int *p = new int; (cм. главу 9)



Дата добавления: 2022-05-27; просмотров: 77;


Поиск по сайту:

Воспользовавшись поиском можно найти нужную информацию на сайте.

Поделитесь с друзьями:

Считаете данную информацию полезной, тогда расскажите друзьям в соц. сетях.
Poznayka.org - Познайка.Орг - 2016-2024 год. Материал предоставляется для ознакомительных и учебных целей.
Генерация страницы за: 0.011 сек.