Указатель в Си — это переменная, содержащая адрес другой переменной. Сложность указателей заключается в понимании где и для чего они могут пригодиться.
Перед тем, как я начну рассказывать об указателях и зачем они программистам, быстренько вспомним основы:
Указатель
В Си указателем называется переменная, содержащая адрес другой переменной. Его можно использовать с любым типом данных, написав:
int i = 0;
int *ptr = &i;
Оператор «&» (амперсанд) определяет адрес переменной, а оператор «*» разыменования позволяет получить значение по адресу, указанным указателем. В примере выше адрес i присваивается к указателю ptr и получается, что ptr указывает на i.
Для чего нужен указатель в Си
Функции в Си принимают аргументы, передавая или копируя значения в стек функции. Такой метод иногда называется передачей по значению. Поскольку функции в Си и переменные, переданные им, в действительности не связываются, любые внесённые изменения в эти переменные не будут сохраняться за пределами действия функции. Это может вызвать сложности, потому что в некоторых функциях необходимо изменять текущие переменные. Здесь-то нам и пригодится указатель. С его помощью можно получить доступ к памяти, находящейся за пределами стекового кадра. Однако важно отметить, что с помощью указателя можно получить доступ лишь к переменным, расположенным ниже текущего кадра.
// gcc -o pointer pointer.c && ./pointer
#include <stdio.h>
#include <stdlib.h>
// Эта функция не будет работать, так как в Си функция передаётся по значению.
// Внесённые изменения не действительны за пределами функции.
void increment(int i) {
i = i + 1;
}
// Передайте указатель на i, а не на само значение, тогда всё заработает.
void incrementWorks ( int* i) {
*i = *i + 1;
}
int main() {
int i = 765;
printf("Original value: %d\n", i);
increment(i);
printf("After the increment function is called: %d\n", i);
printf("Original value: %d\n", i);
incrementWorks (&i);
printf("After the increment function is called %d\n", i);
return (EXIT_SUCCESS);
}
В примере выше простая функция с задачей — увеличить на единицу число, проходящее через параметры. Функция написана следующим образом:
// Эта функция не будет работать, так как в языке Си функция передаётся по значению.
// Внесённые изменения не действительны за пределами функции.
void increment(int i) {
i = i + 1;
}
Однако при запуске кода никаких изменений с переменной не происходит. Связанно это с тем, что в функцию increment (увеличения) копируется только значение переменной, и остальная часть программы не видит изменений, внесённых в эту переменную. Другими словами, переменная i находится внутри функции increment(), и несмотря на одинаковые названия, это не одна и та же переменная, что int i, расположенная за пределами этой функции.
Для того, чтобы решить эту проблему, нужно вместо самой переменной передать в функцию increment указатель этой переменной. Таким образом мы предоставим текущей функции доступ к переменной i, которая не попадает в область действия при выполнении этой функции. Выглядит она вот так:
// Передайте указатель на i, а не на само значение, тогда всё заработает
void increment(int *i) {
*i = *i + 1;
}
Читайте также:
- Использование методов расширения в C# для элегантного и плавного кода
- Игра на C# меньше 8 Кб
- 4 golang-сниппета, которые вводят в заблуждение разработчиков C#!
Читайте нас в Telegram, VK и Яндекс.Дзен
Перевод статьи Book Sadprasid: C Pointer? What is it for?





