Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Проектирование программ и программирование на С++ Часть 1. Структурное.pdf
Скачиваний:
18
Добавлен:
15.11.2022
Размер:
3.8 Mб
Скачать

13.УКАЗАТЕЛИ

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

Указатели являются специальными объектами в программах на C/C++. Указатели предназначены для хранения адресов памяти.

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

10 int a— 10

Рис. 9. Значение переменной и ее адрес

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

Указатели делятся на две категории: указатели на объекты и ука­ затели на функции. Рассмотрим указатели на объекты, которые хра­ нят адрес области памяти, содержащей данные определенного типа.

В простейшем случае объявление указателя имеет вид

тип* имя;

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

int* i;

double *f, *ff;//flBa указателя char* c;

Тип NK чет быть любым, кроме ссылки.

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

указатель на указатель i n t * * а ;

Указатель может быть константой или переменной, а также ука­

зывать на константу или переменную.

 

 

 

 

i n t i ;

 

//ц е л а я

п ерем ен ная

 

c o n s t

i n t c i = l ; //ц е л а я к о н ст а н т а

 

i n t *

p i ;

 

//у к а з а т е л ь

на

целую

переменную

c o n s t

i n t *

p c i ; //у к а з а т е л ь

на

целую

к о н ста н ту

Указатель можно сразу проинициализировать:

 

//у к а з а т е л ь

на

целую

переменную

 

i n t *

p i= & i;

 

 

 

 

 

 

 

//у к а з а т е л ь

на

целую

к о н ста н ту

 

c o n s t i n t * p c i= & c i;

 

 

 

 

 

//у к а з а т е л ь - к о н с т а н т а

на

переменную

целого типа

i n t * c o n s t c p i= & i;

 

 

 

 

 

//у к а з а т е л ь - к о н с т а н т а

на

целую к о н ст а н т у

c o n s t

i n t *

c o n s t cp c= & ci;

 

 

 

Если модификатор c o n s t относится к указателю (т.е. находится

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

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

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

i n t а = 5 ;

 

i n t *

р=&а; или i n t

р (& а );

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

in t *

г= р;

 

адрес присваивается в явном виде

c h a r*

c p = (c h a r* )0 x

В800 0000;

где Ox

В800 0000 - шестнадцатеричная константа; (c h a r* ) -

операция приведения типа.

 

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

i n t *

N=NULL;

 

i n t *

R=0;

 

13.2. Динамическая память

Все переменные, объявленные в программе, размещаются в од­ ной непрерывной области памяти, которую называют сегментом дан­ ных (64 Кб). Такие переменные не меняют своего размера в ходе вы­ полнения программы и называются статическими. Размера сегмента данных может быть недостаточно для размещения больших массивов информации. Выходом из этой ситуации-является использование ди­ намической памяти. Динамическая память - это память, выделяемая программе для ее работы за вычетом сегмента данных, стека, в кото­ ром размещаются локальные переменные подпрограмм и собственно тела программы.

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

Для создания динамических переменных используют операцию new, определенную в C++:

указатель = new имя_типа[инициализатор];

где инициализатор - выражение в круглых скобках.

Операция new позволяет выделить и сделать доступным участок динамической памяти, который соответствует заданному типу дан­ ных. Если задан инициализатор, то в этот участок будет занесено значение, указанное в инициализаторе.

int* x=new int(5);

Для удаления динамических переменных используется операция delete, определенная в C++:

delete указатель;

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

delete х;

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

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

-арифметические операции (сложение с константой, вычита­ ние, инкремент ++, декремент — );

-сравнение;

-приведение типов.

Операция разыменования предназначена для получения значе­ ния переменной или константы, адрес которой хранится в указателе. Если указатель указывает на переменную, то это значение можно изменять, также используя операцию разыменования.

i n t а ;//п е р е м е н н а я

ти па i n t

i n t *

pa=new

i n t ; / /у к а з а т е л ь и вы деление

//п а м я т и

под динам ическую переменную

* р а = 1 0 ;//п р и с в о и л и

зн ач ен и е дин ам ической

//п е р е м е н н о й ,

на которую у к а зы в а е т у к а з а т е л ь

а = * р а ;//п р и с в о и л и

зн ач ен и е перем енной а

Присваивать значение указателям-константам запрещено. Приведение типов. На одну и ту же область памяти могут ссы­

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

i n t а= 1 2 3 ;

i n t *

pi= & a;

c h a r*

р с = ( c h a r * ) &а;

f l o a t * p f = ( f l o a t * ) & a ;

p r i n t f ( " \n % x \t% i" , p i , * p i ); p r i n t f ( " \ n % x \ t % c " ,p c ,* p c ) ; p r i n t f ( " \ n % x \ t % f " , p f , * p f ) ;

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

6 6 fd 9 c

123

6 6 fd 9 c

{

6 6 fd 9 c

0 .0 0 0 0 0 0

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

В примере при инициализации указателя была использована опе­ рация приведения типов. При использовании в выражении указателей разных типов явное преобразование требуется для всех типов, кроме v o id * . Указатель может неявно преобразовываться в значения типа b o o l, при этом ненулевой указатель преобразуется в t r u e , а нуле­ вой в f a l s e .

Арифметические операции применимы только к указателям од­

ного типа.

• Инкремент увеличивает значение указателя на величину

sizeof(тип). char* рс; int* pi; double* pd;

pc++;

//значение увеличится на 1

pi++;

//значение увеличится на

4

pd++;

//значение увеличится на

8

Декремент уменьшает значение указателя на величину sizeof(тип).

Разность двух указателей - это разность их значений, делен­ ная на размер типа в байтах.

int а=123/ Ь=456, с=789;

int* pil=&a;

int* pi2=&b; int* pi3=&c;

printf("\n%x",pi1-pi2); printf (,f\n%x,f,pil-pi3) ;

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

1

2

Суммирование двух указателей не допускается.

• Можно суммировать указатель и константу: pi3=pi3+2;

pi2=pi2+l;

p r i n t f ( "\ n % x \t % d ,f, p i l , * p i l ) ;

p r i n t f ( " \ n % x \ t % d " , p i 2 , * p i 2 ) ; p r i n t f ( ,,\n % x \t % d ,f, p i 3 / * p i 3 ) ;

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

66fd9c 123

66fd9c 123

66fd9c 123

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]