Глава 7. Указатели, динамические массивы



Как видно из рассмотренных ранее примеров, в Си++ массивы статические, их размер задается при описании. Это не всегда удобно, кроме того, при решении некоторых задач заранее неизвестен размер формируемого массива.

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

 

7.1. Указатели в С++

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

Указатель описывается следующим образом:

type * name;

Здесь name – переменная, объявляемая, как указатель. По этому адресу (указателю) храниться значение типа type.

Например:

int *i;

Объявляем указатель (адрес) i. По этому адресу будет храниться переменная типа int. Переменная i указывает на тип данных int.

float *x,*z;

Объявляем указатели с именами x и z, которые указывают на переменные типа float.

 

7.2. Операции * и & при работе с указателями

При работе с указателями в основном используются операции & и *. Операция & возвращает адрес своего операнда.

Например, если объявлена переменная a следующим образом:

float a;

то оператор

adr_a=&a;

записывает в переменную adr_a адрес переменной a, переменная adr_a должна быть указателем на тип float. Ее следует описать следующим образом:

float *adr_a;

Операция * выполняет действие, обратное операции &. Она возвращает значение переменной, хранящееся по заданному адресу.

Например, оператор

a=*adr_a;

записывает в переменную a вещественное значение, хранящееся по адресу adr_a.

Операция присваивания указателей

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

Рассмотрим следующий пример

#include <stdio.h>

#include <math.h>

int main()

{

float PI=3.14159,*p1,*p2;

p1=p2=&PI;

printf("По адресу p1=%p хранится *p1=%g\n",p1,*p1);

printf("По адресу p2=%p хранится *p2=%g\n",p2,*p2);

}

В этой программе определены: вещественная переменная PI=3.14159 и два указателя на тип float p1 и p2. Затем в указатели p1 и p2 записывается адрес переменной PI. Операторы printf выводят на экран адреса p1 и p2 и значения, хранящиеся по этим адресам. Для вывода адреса используется спецификатор типа %p. В результате работы этой программы в переменных p1 и p2 будет храниться значение одного и того же адреса, по которому хранится вещественная переменная PI=3.14159.

По адресу p1=0012FF7C хранится *p1=3.14159

По адресу p2=0012FF7C хранится *p2=3.14159

 

Если указатели ссылаются на различные типы, то при присваивании значения одного указателя другому, необходимо использовать преобразование типов. Без преобразования можно присваивать любому указателю указатель void *. Рассмотрим пример работы с указателями различных типов.

#include <stdio.h>

#include <math.h>

int main()

{

float PI=3.14159,*p1;

double *p2;

//В переменную p1 записываем адрес PI

p1=&PI;

//указателю на double присваиваем

//значение, которое ссылается на тип

//float.

p2=(double *)p1;

printf("По адресу p1=%p хранится *p1=%g\n",p1,*p1);

printf("По адресу p2=%p хранится *p2=%e\n",p2,*p2);

}

 

По адресу p1=0012FF7C хранится *p1=3.14159

По адресу p2=0012FF7C хранится *p2=2.642140e-308

 

В указателях p1 и p2 хранится один и тот же адрес, но значения, на которые они ссылаются, оказываются разными. Это связано с тем, указатель типа *float адресует 4 байта, а указатель *double – 8 байт. После присваивания p2=(double *)p1; при обращении к *p2 происходит следующее: к переменной, хранящейся по адресу p1, дописывается еще 4 байта из памяти. В результате значение *p2 не совпадает со значением *p1.

А что произойдет в результате следующей программы?

#include <stdio.h>

#include <math.h>

int main()

{

double PI=3.14159,*p1;

float *p2;

p1=&PI;

p2=(float *)p1;

printf("По адресу p1=%p хранится *p1=%g\n",p1,*p1);

printf("По адресу p2=%p хранится *p2=%e\n",p2,*p2);

}

После присваивания p2=(double *)p1; при обращении к *p2 происходит следующее: из переменной, хранящейся по адресу p1, выделяется только 4 байта. В результате и в этом случае значение *p2 не совпадает со значением *p1.

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

 

float *p;

p – адрес;

*p – значение, хранящееся по адресу p.

 

float p;

&p – адрес;

p – значение, хранящееся по адресу &p.

 

 


Дата добавления: 2019-09-13; просмотров: 211; Мы поможем в написании вашей работы!

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






Мы поможем в написании ваших работ!