«

»

C++. Указатели

Указатели широко используются в C++. В чем то, именно их наличие сделало этот язык более удобным для системного программирования. Но стоит отметить, что это одна из наиболее сложных для освоения возможностей C++. Идея работы с указателями состоит в том, что пользователь работает с адресом ячейки памяти и имеет возможность динамически создавать и уничтожать переменные.

Как правило, при обработке оператора объявления переменной тип имя_переменной; компилятор автоматически выделяет память под переменную имя_переменной в соответствии с указаннымтипом:

 

1
2
char C='$'; //Будет выделена под символьную переменную С,
//и ей присвоено стартовое значение

 

Доступ к объявленной переменной осуществляется по ее имени. При этом все обращения к переменной меняются на адрес ячейки памяти, в которой хранится ее значение:

 

1
2
cout<<C; //из ячейки памяти с именем C будет извлечено значение
//и выведено на экран

 

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

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

Указатель — это переменная, значением которой является адрес памяти, по которому хранится объект определенного типа (другая переменная). Например, если C — это переменная типа char, а P — указатель на C, значит в находится адрес, по которому в памяти компьютера хранится значение переменной C.

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

тип имя_переменной;

Например:

 

1
2
3
int *p //по адресу, записанному в переменной p,
//будет хранится переменная типа int
//или, другими словами, p указывает на тип данных int

 

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

 

1
2
float *x, y, *z; //описаны указатели на вещественное число - x и z
//а также вещественная переменная y

 

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

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

 

1
2
3
4
float a; //объявлена вещественная переменная a
float *adr_a; //объявлен указатель на тип float
adr_a = &a; //оператор записывает в переменную adr_a
//адрес переменной a

 

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

 

1
2
3
4
float a; //объявлена вещественная переменная a
float *adr_a; //объявлен указатель на тип float
= *adr_a; //оператор записывает в переменную a
//вещественное значение, хранящиеся по адресу adr_a

 

Присваивание указателей

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

 

1
2
3
4
5
6
7
8
9
10
11
12
#include "stdafx.h"
#include <iostream>
using namespace std;
int main()
{setlocale (LC_ALL, "Rus");
float PI=3.14159, *p1, *p2;
p1=p2=&PI;
cout<<"По адресу p1="<<p1<<" хранится *p1="<<*p1<<"\n";
cout<<"По адресу p2="<<p2<<" хранится *p2="<<*p2<<"\n";
system ("pause");
return 0;
}

 

В данной программе определены: вещественная переменная PI=3.14159 и два указателя на тип float — p1 и p2. В указатели записывается адрес переменной PI. В результате работы программы в переменных p1 и p2 будет хранится значение одного и того же адреса, по которому хранится вещественная переменная PI=3.14159.

Результат работы программы:

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

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

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include "stdafx.h"
#include <iostream>
using namespace std;
int main()
{
setlocale (LC_ALL, "Rus");
float PI=3.14159; //объявлена вещественная переменная PI
float *p1; //объявлен указатель на float - p1
double *p2; //объявлен указатель на double - p2
p1=&PI; //переменной p1 присваивается значние адреса PI
p2=(double *)p1; //указателю на double присваивается значение,
//которое ссылается на тип float
cout<<"По адресу p1="<<p1<<" хранится *p1="<<*p1<<"\n";
cout<<"По адресу p2="<<p2<<" хранится *p2="<<*p2<<"\n";
system ("pause");
return 0;
}

 

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

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

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include "stdafx.h"
#include <iostream>
using namespace std;
int main()
{
setlocale (LC_ALL, "Rus");
double PI=3.14159, *p1; float *p2;
p1=&PI;
p2=(float *)p1;
cout<<"По адресу p1="<<p1<<" хранится *p1="<<*p1<<"\n";
cout<<"По адресу p2="<<p2<<" хранится *p2="<<*p2<<"\n";
system ("pause");
return 0;
}

 

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

Результат работы программы:

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

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Вы можете использовать эти теги HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

Проверка на человечность *