Interested Article - Параметр (программирование)
- 2020-06-28
- 2
Пара́метр в программировании — принятый функцией аргумент. Термин «аргумент» подразумевает, что конкретно и какой конкретной функции было передано, а параметр — в каком качестве функция применила это принятое. То есть вызывающий код передает аргумент в параметр, который определен в члене спецификации функции.
Формальные и фактические параметры
Важно различать:
- формальный параметр — аргумент, указываемый при объявлении или определении функции .
- фактический параметр — аргумент, передаваемый в функцию при её вызове;
Пример на языке Си :
// Описание функции. int a - формальный параметр, имя параметра может отсутствовать.
int myfunction(int a);
// Определение функции. int b - формальный параметр, имя параметра может не совпадать с указанным при объявлении функции.
int myfunction(int b)
{
return 0;
}
int main()
{
int c=0;
myfunction(c); // Вызов функции. c - фактический параметр.
return 0;
}
Использование параметров
Семантика использования формальных и фактических параметров называется стратегией вычисления . Заданная стратегия вычисления диктует, когда следует вычислять аргументы функции (метода, операции, отношения), и какие значения следует передавать. Существует довольно много разнообразных стратегий вычисления.
Примечание — использование распространённого в сообществе императивного программирования термина « передача параметра » для многих языков программирования является не вполне корректным — например, в случае вызова по необходимости , применяемого в языке Haskell , параметр может быть использован в теле функции, но ни разу не передан за все случаи её вызова, и даже полностью исключён из результирующего машинного кода.
Наиболее часто упоминаемыми стратегиями вычисления являются вызов по значению и вызов по ссылке , однако в действительности использование этих терминов не всегда уместно. Например, в сообществе языка Java говорят « Java использует вызов по значению, где „значением“ является ссылка на объект », в сообществе языка Ruby говорят « Ruby использует вызов по ссылке », однако в действительности оба эти языка используют стратегию вызов по соиспользованию ( англ. call-by-sharing ) . Многие языки, например Си , не имеют механизма вызова по ссылке, но позволяют симулировать его внутри семантики вызова по значению посредством ссылочных типов , в частности, указателей . В последнем случае в сообществах таких языков часто говорят « язык поддерживает две стратегии вычисления », а также о « вызове по указателю » или « вызове по адресу ».
На практике, модель вычисления многих промышленных языков ( Java , C# ) сводится к стратегии « вызов-при-упоминании/передача-по-ссылке ». Некоторые более старые языки, в особенности небезопасные языки, такие как C++ , сочетают несколько разных моделей вызова, включая экзотичные, такие как « вызов-по-ссылке-на- константу ». Исторически вызов по значению и вызов по имени восходят к Алголу-60 , созданному в конце 1950-х годов . Только чистые функциональные языки, такие как Clean и Haskell , используют вызов по необходимости ( англ. call-by-need ), который часто отождествляют (что также не вполне корректно) с ленивыми вычислениями .
Примеры
Передача параметра по ссылке означает что копируется не само значение, а адрес исходной переменной (как в случае передачи параметра по адресу), однако синтаксис используется такой, чтобы программисту не приходилось использовать операцию разыменования и он мог иметь дело непосредственно со значением, хранящимся по этому адресу (как в случае передачи параметра по значению).
Передача по ссылке позволяет избежать копирования всей информации, описывающей состояние объекта (а это может быть существенно больше чем sizeof(int)) и является необходимой для конструктора копирования .
Если функция возвращает значение по ссылке (например, в виде «return *this;»), то её вызов можно использовать слева от оператора присваивания (см. также ).
В случае, если передача по ссылке используется именно как средство увеличения быстродействия, но изменение параметра нежелательно, можно использовать передачу по ссылке константного объекта.
#include <iostream>
using namespace std; // для использования cout
void f(int x)
{
// передача параметра по значению
cout << x;
x = 1;
cout << x;
}
void g(int* x)
{
// передача параметра по адресу
cout << *x;
*x = 2;
cout << *x;
}
void h(int& x)
{
// передача параметра по ссылке
cout << x;
x = 3;
cout << x;
}
void i(const int& x)
{
// передача неизменяемого параметра по ссылке
cout << x;
x = 4; //Ошибка из-за которой код не будет скомпилирован
cout << x;
}
int main()
{
int x = 0;
cout << x;
f(x);
cout<< x << " ";
g(&x);
cout << x << " ";
h(x);
cout << x << " ";
i(x);
cout << x;
return 0;
}
Таким образом можно ожидать, что примерная программа напечатает (если закомментировать ошибочную строку) «0010 022 233 333».
Некоторые языки (или их диалекты) не поддерживают передачу по ссылке, некоторые наоборот — передают параметры исключительно по ссылке, что порождает риск непреднамеренного изменения контекста вызывающей функции.
Язык Fortran подразумевает передачу параметров исключительно по ссылке:
Программа:
PROGRAM PARAMS
IMPLICIT NONE
INTEGER A, B, C
A = 7.0
B = 9.0
C = 0.0
100 FORMAT('A =',I2,', B =',I2,', C =',I3)
WRITE(*, 100) A, B, C
CALL MUL(A, B, C)
WRITE(*, 100) A, B, C
END PROGRAM
SUBROUTINE MUL(A, B, C)
INTEGER A, B, C
C = A * B
END SUBROUTINE
Напечатает:
A = 7, B = 9, C = 0
A = 7, B = 9, C = 63
См. также
Литература
- В.В.Фаронов. 8.2.2. Параметры // 8.2. Описание подпрограммы // Глава 8. Процедуры и функции // .
Ссылки
- (англ.) . Дата обращения: 13 октября 2012. 16 февраля 2020 года.
- . Дата обращения: 13 октября 2012. 28 августа 2012 года.
- Fredrik Lundh. (англ.) . effbot.org . Дата обращения: 29 мая 2014. Архивировано из 23 ноября 2019 года.
- . CS 412/413 Introduction to Compilers . Cornell University (2001). Дата обращения: 29 мая 2014. 23 сентября 2015 года.
- 2020-06-28
- 2