Если вы изучали программирование с помощью JavaScript или даже Java, вы, вероятно, не знакомы с концепцией указателей.
Рассмотрим следующую простую программу:
Вывод кода выше:
First: 1 Second: 3
Если вам интересно, почему, тогда, пожалуйста, читайте дальше!
указатели
Ключевое отличие заключается в аргументах, передаваемых через функции addTwo
и add_two
. Обратите внимание, что тип аргумента не int
, а int*
. Это понятие, встречающееся в C/C++ и других C-подобных языках, известное как указатель. Даже если указатели вам незнакомы, вы можете узнать лежащую в их основе концепцию. По сути, указатель — это переменная, которая содержит адрес в памяти, где определен этот тип значения. Звездочка *
после типа указывает, что это указатель этого типа, а не сам тип. Например, int *
— это объявление не целочисленного значения, а адреса в памяти целочисленного значения. Итак, если мы посмотрим на нашу функцию add_two
, то увидим, что она ожидает получить адрес, а не целочисленное значение.
Так как же нам получить значение по тому адресу, на который указывает указатель? Для этого в C/C++ мы используем так называемый оператор разыменования (который по совпадению также является *
). Помещая звездочку перед переменной-указателем, мы сообщаем C/C++, чтобы он предоставил нам значение, хранящееся в этом адресе памяти. Итак, в приведенном выше примере *arg
относится к значению, которое мы передали, то есть 1
.
«Хорошо, но как насчет оператора «&»?»
Амперсанд &
, вероятно, более знаком вам с точки зрения его использования в качестве логического оператора И в форме &&
. Хотя это все еще имеет место в C/C++, одиночный &
представляет собой противоположность звездочке *
, поскольку он известен как оператор ссылки. Точно так же, как у нас есть *
для получения значения по адресу в памяти, мы используем &
для получения адреса в памяти значения. Поскольку add_two
ожидал целочисленный указатель, а мы объявили second
просто целочисленным значением, нам нужно передать &second
, который является адресом, или указатель на значение second
.
Передача по значению против передачи по ссылке
Таким образом, addTwo
— это функция, которая передает аргумент по значению, а add_two
передает аргумент по ссылке. Мы видим разницу между двумя, иллюстрируемую тем фактом, что выходные данные показывают, что наша переменная first
не изменилась, хотя мы якобы увеличили ее на два с помощью строки arg = arg + 2
, а наша переменная second
изменилась.
В Java и Javascript мы знаем, что примитивные типы передаются по значению, а такие объекты, как массивы, передаются по ссылке. Мы можем видеть, как это происходит в следующих двух примерах:
В C (не C++) все передается только по значению. Это означает, что указатели абсолютно необходимы для выполнения манипуляций с массивами, как в приведенных выше примерах JS и Java. В C++ наличие указателей обеспечивает гибкость, хотя классические указатели в последнее время потеряли популярность в пользу умных указателей (мы можем вернуться к этому в другой раз!).