Найти тему
ZDG

Новичку-программисту: Что передаётся в функцию на самом деле?

Предыдущие части: Как не запутаться в именах-2, Как не запутаться в именах-1

В предыдущих выпусках речь шла о параметрах функции. Мы передавали в функцию одну переменную, или другую переменную, или просто число.

Во всех этих случаях возникает общий вопрос:

Что конкретно, куда и как передаётся?

Рассмотрим такую ситуацию. Вы находитесь в комнате. В комнате есть книга. Можно назвать её "A". Вам нужно эту книгу передать в другую комнату. Вы берёте её в руки, несёте в другую комнату, и вот – вы передали книгу "A".

Произошла операция над физическим объектом "книга". Он был в одной комнате, теперь его там нет, он находится в другой. Он остался тем же физическим объектом, не исчез и не появился в лишнем экземпляре.

В программировании, хотя мы и говорим постоянно "передать что-то куда-то", ничего подобного не происходит.

Когда мы, например, завели переменную с именем "a" и присвоили ей значение 5:

a = 5

то транслятор языка автоматически подобрал для нас некий адрес в памяти, дал ему условное имя "a", и записал в него число 5.

Чтобы передать переменную "a" в функцию, мы не можем взять эту ячейку памяти, оторвать её и переместить куда-то. Нет, ячейка остаётся на своём месте. Мы берём из неё содержимое, то есть число 5, и передаём в функцию.

Когда мы взяли содержимое, произошло копирование:

  1. адрес "а" по-прежнему содержит число 5
  2. мы также имеем число 5, которое скопировано из адреса "a"

Эта копия пока нигде конкретно не хранится, мы, грубо говоря, "держим её в руках" (физически она находится во временном регистре процессора).

-2

Теперь эту копию надо передать в функцию. Никакого физического перемещения опять же не происходит. У функции есть свой собственный адрес, выделенный под параметр, который ей должны передать.

Допустим, функция выглядит так (Python):

-3

Буква "x" в скобках говорит нам: В этой функции зарезервирован адрес памяти для параметра, который условно называется "x".

-4
Можете обратить внимание, что у параметра "х" адрес равен 16. Это потому, что адрес относительный – параметры функции существуют в стеке, а адреса отсчитываются относительно вершины стека. Но это неважно, я написал так просто для порядка.

Важно только то, что для каждого параметра, который объявлен в скобках, зарезервирован свой физический адрес. Всё, что мы положим в адрес, который называется "x" – будет считаться значением параметра "x".

Значит, чтобы передать параметр в функцию, нужно то, что мы сейчас держим в руках (число 5) записать в адрес, предназначенный для параметра "x":

-5

Вся вышеописанная последовательность действий укладывается в один вызов функции:

a = 5
test(a)

Как видим, при передаче параметра произошло два копирования:

  1. Сначала значение 5 было скопировано из адреса "a" в процессор
  2. Затем значение 5 было скопировано из процессора в адрес параметра "x" функции test().

Таким образом, мы передали значение 5 из переменной "a" в функцию test().

Инструкция print(x) напечатает нам значение параметра "x", то есть содержимое адреса, условно называемого "x", то есть число 5.

Обратите внимание, что print() – тоже функция, и в неё тоже передаётся параметр. Только на этот раз он копируется из параметра "x" функции test().

Для краткости мы можем говорить, что передали в функцию test() переменную "a", но очевидно, что сама переменная никуда не передаётся.

Если же мы напишем вот так, без участия переменной:

test(100)

То процессор не будет копировать число 100 из значения какой-либо переменной (её просто нет). Машинная инструкция, в которую будет транслировано это выражение, уже будет содержать число 100 в самой себе, и так как машинные инструкции находятся тоже по каким-то адресам, то процессор возьмёт число 100 оттуда.

А дальше это число будет записано в параметр "x" функции test() как обычно, и функция напечатает число 100.

Давайте повторим

  • Названия параметров функции это просто условные названия выделенных для этой функции адресов, в которых хранятся параметры.
  • Сами адреса параметров – нечто вроде почтовых ящиков. Мы бросаем туда то, что хотим передать в функцию. Как известно, в почтовый ящик можно положить письмо, журнал, газету и т.д., но в нашем случае мы не можем это сделать – мы можем положить только ксерокопию, но не оригинал.

Из этого следует, что функция может делать со своими параметрами что угодно. Порвав копию газеты, вы ничем не навредите оригиналу. В самом деле, если в функцию под именем параметра "x" передано число 5, скопированное из переменной "a", мы можем написать в функции:

x = 0

Это изменит только значение по адресу параметра "x", но никак не изменит значение по адресу переменной "a". Это просто разные адреса.

Однако существуют ситуации, когда функция, изменив свой параметр, может изменить внешнюю переменную. Это называется "передача параметра по ссылке", и мы обсудим её в следующем выпуске.

Читайте дальше: Передача по ссылке

Читайте также:

  • Что такое стек
  • Типы данных и указатели
  • Глобальные и локальные переменные

Наука
7 млн интересуются