2025-04-14 10:44:02

Урок 10. Указатели

Все данные, которыми оперирует программа, хранятся в ячейках памяти, каждая из которых имеет свой уникальный адрес. Переменные, в которых можно хранить эти адреса называются - указателями. Другими словами, указатель - это переменная, которая хранит адрес другого объекта (переменой, константы, указателя) или функции. Указатели - являются неотъемлемым компонентом для управления памятью в языке Си.

Определение указателя

Для определения указателя надо указать тип объекта, на который указывает указатель, и символ звездочки *.

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

Сначала идет тип данных, на который указывает указатель, и символ звездочки *. Затем имя указателя.

Например, определим указатель на объект типа int:

int *p;

Пока указатель не ссылается ни на какой объект. Теперь присвоим ему адрес переменной:

int main( void )
{
    int x = 10;     // определяем переменную
    int *p;         // определяем указатель
    p = &x;         // указатель получает адрес переменной
    return 0;
}

Получение адреса данных

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

ВАЖНО !!! Указатель и переменная должны быть одного типа !!!

Для вывода значения указателя можно использовать специальный спецификатор %p. Пример:

#include <stdio.h>
 
int main(void)
{
    int x = 10;
    int *p;
    p = &x;
    printf("%p \n", p);
    return 0;
}

Адресом данных является адрес первой ячейки памяти в шестнадцатеричном формате. Например, в памяти компьютера есть адрес 0x0060FEA8, по которому располагается переменная x. Так как переменная x представляет тип int, то на большинстве архитектур она будет занимать следующие 4 байта (на конкретных архитектурах размер памяти для типа int может отличаться). Таким образом, переменная типа int последовательно займет ячейки памяти с адресами 0x0060FEA8, 0x0060FEA9, 0x0060FEAA, 0x0060FEAB.

адреса ячеек

Стоит отметить, что при выводе адреса указателя функция printf() ожидает, что указатель будет представлять void*, то есть указатель на значение типа void. Поэтому некоторые компиляторы могут отображать предупреждения. Чтобы было все канонически правильно переданный указатель нужно преобразовать в указатель типа void *:

printf("%p \n", (void *)p);

Получение значения по адресу

Так как указатель хранит адрес, то мы можем по этому адресу получить хранящееся там значение. Для этого применяется операция * или операция разыменования (dereference operator). Результатом этой операции всегда является объект, на который указывает указатель. Применим данную операцию и получим значение переменной x:

#include <stdio.h>
 
int main(void)
{
    int x = 10;
    int *p;
    p = &x;
    printf("Address = %p \n", (void*) p);
    printf("x = %d \n", *p);
    return 0;
}

Графическое пояснение операций * и &

указатель

Указатели можно объявлять не только на переменные, но и на другие указатели:

#include <stdio.h>
int main()
{
    int a = 77;
    int *ptrA = &a;
    int** ppA = &ptrA;
    *ptrA = 88;
    printf("%d\n",a);// << std::endl; // 88
    **ppA = 99;
    printf("%d\n",a);// << std::endl; // 99
return 0;
}

указатель на указатель

Комментарии ()