Для чего нужен указатель в Си?



Книга Для чего нужен указатель в Си?

Указатель в Си  —  это переменная, содержащая адрес другой переменной. Сложность указателей заключается в понимании где и для чего они могут пригодиться.


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


Указатель


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


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
", i);
increment(i);
printf("After the increment function is called: %d
", i);

printf("Original value: %d
", i);
incrementWorks (&i);
printf("After the increment function is called %d
", 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;
}

600   0  

Comments

    Ничего не найдено.