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


Указатели в языке Си поддерживают ряд операций: присваивание, получение адреса указателя, получение значения по указателю, некоторые арифметические операции и операции сравнения.

Присваивание
Указателю можно присвоить либо адрес объекта того же типа, либо значение другого указателя или константу NULL.

Присвоение указателю адреса уже рассматривалось в прошлой теме. Для получения адреса объекта используется операция &:

1
2
int a = 10;
int *pa = &a; // указатель pa хранит адрес переменной a
Причем указатель и переменная должны иметь тот же тип, в данном случае int.

Присвоение указателю другого указателя:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <stdio.h>

int main(void)
{
int a = 10;
int b = 2;

int *pa = &a;
int *pb = &b;

printf("Variable a: address=%p \t value=%d \n", pa, *pa);
printf("Variable b: address=%p \t value=%d \n", pb, *pb);

pa = pb; // теперь указатель pa хранит адрес переменной b
printf("Variable b: address=%p \t value=%d \n", pa, *pa);

return 0;
}
Когда указателю присваивается другой указатель, то фактически первый указатель начинает также указывать на тот же адрес, на который указывает второй указатель.

Если мы не хотим, чтобы указатель указывал на какой-то конкретный адрес, то можно присвоить ему условное нулевое значение с помощью константы NULL, которая определена в заголовочном файле stdio.h:

1
int *pa = NULL;
Разыменование указателя
Операция разыменования указателя в виде *имя_указателя, позволяет получить объект по адресу, который хранится в указателе.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <stdio.h>

int main(void)
{
int a = 10;

int *pa = &a;
int *pb = pa;

*pa = 25;

printf("Value on pointer pa: %d \n", *pa); // 25
printf("Value on pointer pb: %d \n", *pb); // 25
printf("Value of variable a: %d \n", a); // 25

return 0;
}
Через выражение *pa мы можем получить значение по адресу, который хранится в указателе pa, а через выражение типа *pa = значение вложить по этому адресу новое значение.

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

Адрес указателя
Указатель хранит адрес переменной, и по этому адресу мы можем получить значение этой переменной. Но кроме того, указатель, как и любая переменная, сам имеет адрес, по которому он располагается в памяти. Этот адрес можно получить также через операцию &:

1
2
3
4
5
int a = 10;
int *pa = &a;
printf("address of pointer=%p \n", &pa); // адрес указателя
printf("address stored in pointer=%p \n", pa); // адрес, который хранится в указателе - адрес переменной a
printf("value on pointer=%d \n", *pa); // значение по адресу в указателе - значение переменной a
Операции сравнения
К указателям могут применяться операции сравнения >, >=, <, <=,==, !=. Операции сравнения применяются только к указателям одного типа и константе NULL. Для сравнения используются номера адресов:

1
2
3
4
5
6
7
8
int a = 10;
int b = 20;
int *pa = &a;
int *pb = &b;
if(pa > pb)
printf("pa (%p) is greater than pb (%p) \n", pa, pb);
else
printf("pa (%p) is less or equal pb (%p) \n", pa, pb);
Консольный вывод в моем случае:

pa (0060FEA4) is greater than pb (0060FEA0)
Приведение типов
Иногда требуется присвоить указателю одного типа значение указателя другого типа. В этом случае следует выполнить операцию приведения типов:

1
2
3
4
5
char c = 'N';
char *pc = &c;
int *pd = (int *)pc;
printf("pc=%p \n", pc);
printf("pd=%p \n", pd);