Стрелка к стрелке (Двойная стрелка) в C
Привет, начинающие программисты! Сегодня мы отправляемся в захватывающее путешествие в мир указателей, именно в мир указателей к указателям. Я знаю, что у вас может возникнуть такое подозрение: "Указатели? Двойные указатели? Это звучит как кошмар!" Но не волнуйтесь, я обещаю сделать это как можно более интересным и понятным. Так что возьмите свой любимый напиток, устройтесь комфортно, и давайте погружимся!
Что такое двойной указатель в C?
Представьте себе, что вы находитесь на охоте за сокровищами. У вас есть карта (позовем ее указателем), которая ведет к сундуку. Но сюрприз! Внутри сундука есть еще одна карта (еще один указатель), которая ведет к настоящему сокровищу. Вот исключительно что такое двойной указатель — указатель, который указывает на другой указатель.
В программировании на C двойной указатель — это именно то, что вы бы подумали — указатель к указателю. Это переменная, которая хранит адрес другого указателя. Это может показаться немного запутывающе в начале, но не волнуйтесь, мы разберем это шаг за шагом.
Объявление указателя к указателю
Начнем с того, как мы объявляем двойной указатель. Синтаксис довольно простой:
int **ptr;
Здесь ptr
— это указатель к указателю к целому числу. Первая звездочка *
делает его указателем, а вторая *
делает его указателем к указателю.
Пример указателя к указателю (двойной указатель)
Давайте рассмотрим простой пример, чтобы лучше понять это:
#include <stdio.h>
int main() {
int x = 5;
int *p = &x;
int **pp = &p;
printf("Значение x: %d\n", x);
printf("Значение x с использованием p: %d\n", *p);
printf("Значение x с использованием pp: %d\n", **pp);
return 0;
}
Вывод:
Значение x: 5
Значение x с использованием p: 5
Значение x с использованием pp: 5
Разберем это:
- Мы объявляем целое число
x
и инициализируем его значением 5. - Создаем указатель
p
, который указывает наx
. - Создаем двойной указатель
pp
, который указывает наp
. - Затем выводим значение
x
тремя разными способами:
- Прямо с использованием
x
- С использованием одиночного указателя
p
(мы dereferencем его один раз с*p
) - С использованием двойного указателя
pp
(мы dereferencем его дважды с**pp
)
Все три метода дадут нам одно и то же значение: 5. Это как достичь сокровища с использованием разных карт!
Как работает обычный указатель в C?
Прежде чем мы погружаемся更深 в двойные указатели, давайте быстро рассмотрим, как работают обычные указатели:
int y = 10;
int *q = &y;
printf("Значение y: %d\n", y);
printf("Адрес y: %p\n", (void*)&y);
printf("Значение q: %p\n", (void*)q);
printf("Значение, на которое указывает q: %d\n", *q);
Вывод:
Значение y: 10
Адрес y: 0x7ffd5e8e9f44
Значение q: 0x7ffd5e8e9f44
Значение, на которое указывает q: 10
Здесь q
— это указатель, который хранит адрес y
. Когда мы используем *q
, мы доступаемся к значению, хранящемуся по этому адресу.
Как работает двойной указатель?
Теперь распространим это на двойные указатели:
int z = 15;
int *r = &z;
int **rr = &r;
printf("Значение z: %d\n", z);
printf("Адрес z: %p\n", (void*)&z);
printf("Значение r: %p\n", (void*)r);
printf("Адрес r: %p\n", (void*)&r);
printf("Значение rr: %p\n", (void*)rr);
printf("Значение, на которое указывает r: %d\n", *r);
printf("Значение, на которое указывает rr: %p\n", (void*)*rr);
printf("Значение, на которое указывает значение, на которое указывает rr: %d\n", **rr);
Вывод:
Значение z: 15
Адрес z: 0x7ffd5e8e9f48
Значение r: 0x7ffd5e8e9f48
Адрес r: 0x7ffd5e8e9f50
Значение rr: 0x7ffd5e8e9f50
Значение, на которое указывает r: 15
Значение, на которое указывает rr: 0x7ffd5e8e9f48
Значение, на которое указывает значение, на которое указывает rr: 15
Это может показаться немного перегружающе, но разберем это:
-
z
— это целое число с значением 15. -
r
— это указатель, который хранит адресz
. -
rr
— это двойной указатель, который хранит адресr
. -
*r
дает нам значениеz
(15). -
*rr
дает нам значениеr
(которое является адресомz
). -
**rr
дает нам значениеz
(15).
Представьте себе так: rr
указывает на r
, который указывает на z
. Так что **rr
— это как сказать "следуйте первому указателю, затем следуйте второму указателю и дайте мне значение там".
Двойной указатель ведет себя так же, как обычный указатель
Вот небольшое секрет: двойной указатель — это просто указатель, но вместо того чтобы указывать на int или float, он указывает на другой указатель. Это означает, что мы можем делать с двойными указателями все те же вещи, что и с обычными указателями.
Например, мы можем использовать двойные указатели с массивами:
int main() {
char *fruits[] = {"Apple", "Banana", "Cherry"};
char **ptr = fruits;
for(int i = 0; i < 3; i++) {
printf("%s\n", *ptr);
ptr++;
}
return 0;
}
Вывод:
Apple
Banana
Cherry
В этом примере fruits
— это массив указателей (каждый из которых указывает на строку), а ptr
— это указатель к указателю к символу (который может указывать на элементы fruits
).
Многоуровневые указатели в C (Возможен ли тройной указатель?)
Да, вы можете иметь тройные указатели, четверные указатели и так далее! Нет теоретических ограничений по количеству уровней отсылки, которые вы можете иметь. Однако на практике редко встречаются более двойных указателей.
Вот пример тройного указателя:
int x = 5;
int *p = &x;
int **pp = &p;
int ***ppp = &pp;
printf("Значение x: %d\n", ***ppp);
Вывод:
Значение x: 5
Но помните, что просто потому, что вы можете, не значит, что вы должны. Многоуровневые отсылки могут сделать код сложнее для чтения и поддержки. Как говорится в старой программистской пословице, "Все проблемы в компьютерной науке можно решить добавлением еще одного уровня отсылки... кроме проблемы слишком многих уровней отсылки!"
Заключение
Поздравляем! Вы только что перенеслись по морскому дну двойных указателей в C. Помните, что как многие концепции в программировании, указатели к указателям могут показаться запутывающими в начале, но с практикой они станут второй натурой.
Вот таблица, подводящая ключевые моменты, которые мы обсудили:
Концепция | Синтаксис | Описание |
---|---|---|
Обычный Указатель | int *p; |
Указывает на целое число |
Двойной Указатель | int **pp; |
Указывает на указатель к целому числу |
Dereferencing | *p |
Доступ к значению, на которое указывает p
|
Двойной Dereferencing | **pp |
Доступ к значению, на которое указывает указатель, на который указывает pp
|
Оператор адреса | &x |
Получение адреса x
|
Продолжайте практиковаться, будьте любознательными, и помните — каждый эксперт когда-то начинал с нуля. Счастливого кодирования!
Credits: Image by storyset