
Какие существуют способы передачи данных между подпрограммой и вызывающей её программой?
Ответы на вопрос

Коротко: данные между вызывающей программой и подпрограммой передают тремя большими способами — через параметры, через возвращаемое значение и через побочные эффекты. Ниже разложу по полочкам с нюансами, которые часто путают.
1) Через параметры (аргументы)
Это главный канал «туда» и «обратно». Семантика бывает разной:
-
По значению (call by value)
В подпрограмму копируется значение аргумента. Меняя локальную копию, вы не влияете на вызывающего.
Пример:int f(int x)
в C/C++ —x
внутри независим. -
По ссылке / по адресу (call by reference / by pointer)
В подпрограмму передаётся не копия значения, а «доступ» к исходной переменной/объекту. Изменения видны снаружи.
Пример:void inc(int& x)
в C++ илиvoid inc(int* px)
в C — меняют исходныйx
. -
По результату (out)
Параметр используется только для вывода: начальное значение не читается, а в конце подпрограмма «кладёт» результат обратно. Встречается, например, в Ada, Pascal (var
иногда трактуют как inout, но есть и чистыеout
). -
По значению-результату (copy-in / copy-out)
На вход — копия значения; на выход — копия обратно в исходную переменную. Если было два параметра, указывающих на одну и ту же переменную, возможны тонкие эффекты перезаписи. -
По имени (call by name)
Историческая семантика Algol-60: выражение подставляется «как есть» и вычисляется каждый раз заново в теле подпрограммы. В современных языках почти не используется. -
По необходимости / лениво (call by need)
Выражение вычисляется только при первом обращении и кэшируется. Типично для чисто функциональных языков. -
По разделяемости (call by sharing)
В интерпретируемых OO-языках (Python, Java) передаётся ссылка на объект по значению. Это значит: переназначить параметр внутри нельзя (вызвавший не увидит), но мутировать сам объект можно — и это увидят.
Пример (Python):def add(a): a.append(1)
изменит список снаружи; аa = a + [1]
— нет. -
Константная ссылка / read-only view
Даёт эффективность без разрешения менять объект (C++const T&
, Rust заимствование&T
).
Практические приёмы на параметрах:
-
Выходные параметры (
out
/inout
) — когда нужно вернуть несколько значений без упаковки в кортеж/структуру. -
Передача буфера (адрес + размер) — когда вызывающая сторона управляет памятью.
2) Через возвращаемое значение функции
Классический способ «обратно». Возможности зависят от языка:
-
Возврат скаляров, структур, кортежей/множественных значений.
-
Возврат «результата + код ошибки/исключение» (см. ниже).
-
Итераторы/генераторы — потоковая передача данных сериями (
yield
), когда результата много или он ленивый.
3) Через побочные эффекты
Иногда данные «просачиваются» не напрямую через сигнатуру:
-
Изменение внешнего состояния
Глобальные/статические переменные, поля синглтонов, базы данных, кэш. Удобно, но снижает прозрачность и тестируемость. -
Замыкания и не-локальные переменные
Подпрограмма (лямбда) может читать/менять переменные из внешней области видимости (если язык позволяетnonlocal
/ref
-захват). -
Мутация разделяемых объектов
Если и вызывающий, и подпрограмма держат ссылку на один и тот же контейнер/объект, подпрограмма может его поменять, и это будет «каналом» передачи. -
Исключения
Формально — канал передачи информации об ошибках/исключительных ситуациях (тип, сообщение, данные внутри исключения). -
Логи/события/коллбеки
Подпрограмма генерирует события или пишет в лог, а вызывающий считывает. Это тоже обмен данными, хоть и асинхронный по духу.
(Опционально) Реализация на уровне платформы
Это не «семантика», а как аргументы реально попадают внутрь: через регистры, стек, иногда через выделенные области памяти (ABI/соглашение о вызовах). Возвращаемые значения нередко идут через специальный регистр. Для проектирования API обычно не важно, но влияет на производительность.
(Отдельный случай) Если подпрограмма в другом потоке/процессе
Это уже межпоточное/межпроцессное взаимодействие:
-
Общая память (shared memory) + синхронизация (мьютексы, атомики).
-
Очереди/каналы/сообщения (message passing, CSP-каналы, почтовые ящики Erlang).
-
IPC/сетевые механизмы: пайпы, сокеты, файлы, RPC/gRPC.
Формально это не «между подпрограммой и вызывающей», а «между сущностями исполнения», но на практике встречается часто.
Что выбирать на практике
-
Нужен один-два результата → возвращаемое значение (или кортеж/структура).
-
Нужно модифицировать переданный объект → по ссылке/указателю/«by sharing» с чётким контрактом мутаций.
-
Много результатов → структура/класс результата или выходные параметры.
-
Большие данные без копий → ссылки/указатели/константные ссылки.
-
Ошибки → исключения или тип «результат/ошибка».
-
Параллелизм → каналы/очереди (предпочтительнее, чем разделяемое состояние, ради простоты и безопасности).
Похожие вопросы









Топ вопросов за вчера в категории Информатика









Последние заданные вопросы в категории Информатика



-
Математика
-
Литература
-
Алгебра
-
Русский язык
-
Геометрия
-
Английский язык
-
Химия
-
Физика
-
Биология
-
Другие предметы
-
История
-
Обществознание
-
Окружающий мир
-
География
-
Українська мова
-
Информатика
-
Українська література
-
Қазақ тiлi
-
Экономика
-
Музыка
-
Право
-
Беларуская мова
-
Французский язык
-
Немецкий язык
-
МХК
-
ОБЖ
-
Психология
-
Физкультура и спорт
-
Астрономия
-
Кыргыз тили
-
Оʻzbek tili