Передача параметров по значению и по ссылке

Передача параметров по ссылке и по значению

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

• по значению;

• по ссылке.

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

int GetMax(int, int);

принимает два целочисленных аргумента по значению.

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

В C++ передача по ссылке может осуществляться двумя способами:

• используя непосредственно ссылки;

• с помощью указателей.

Синтаксис передачи с использованием ссылок подразумевает применение в качестве аргумента ссылки на тип объекта. Например, функция

double Glue(long& var1, int& var2);

получает две ссылки на переменные типа long и int. При передаче в функцию параметра-ссылки компилятор автоматически передает в функцию адрес переменной, указанной в качестве аргумента. Ставить знак амперсанда перед аргументом в вызове функции не нужно. Например, для предыдущей функции вызов с передачей параметров по ссылке выглядит следующим образом:

Glue(var1, var2);

Пример прототипа функции при передаче параметров через указатель приведен ниже:

void SetNumber(int*, long*);

Кроме того, функции могут возвращать не только значение некоторой переменной, но и указатель или ссылку на него. Например, функции, прототип которых:

*int Count(int); &int Increase();

возвращают указатель и ссылку соответственно на целочисленную переменную типа int. Следует иметь в виду, что возвращение ссылки или указателя из функции может привести к проблемам, если переменная, на которую делается ссылка, вышла из области видимости. Например,

int& func()

{

int x;

return x;

}

В этом случае попытка возвратить ссылку на локальную переменную х приведет к ошибке, которая, к сожалению, выяснится только в ходе выполнения программы.

Эффективность передачи адреса объекта вместо самой переменной ощутима и в скорости работы, особенно, если используются большие объекты, в частности массивы (будут рассмотрены позже).

Если требуется в функцию передать довольно большой объект, однако его модификация не предусматривается, на практике используется передача константного указателя. Данный тип вызова предполагает использование ключевого слова const, например, функция

const int* FName(int* const Number)

принимает и возвращает указатель на константный объект типа int. Любая попытка модифицировать такой объект в пределах тела вызываемой функции вызовет сообщение компилятора об ошибке. Рассмотрим пример, иллюстрирующий использование константных указателей.

#include

int* const call(int* const);

int main()

{

int X = 13; int* pX = &X; call(pX);

return 0;

}

int* const call(int* const x)

{

cout « *x;

//*x++; II нельзя модифицировать объект! return x;

}

Вместо приведенного выше синтаксиса константного указателя в качестве альтернативы при передаче параметров можно использовать константные ссылки, например:

const int& FName (const int& Number)

имеющие тот же смысл, что и константные указатели.

#include

const int& call(const int& x)

{

cout « x;

//x++;

// нельзя модифицировать объект!

return x;

}

int main()

{

int X = 13;

int& rX = X;

call(rX);

return 0;

}

StudFiles.ru

Передача параметров

В стандарте языка Паскаль передача параметров может производиться двумя способами - по значению и по ссылке. Параметры, передаваемые по значению, называют параметрами-значениями, передаваемые по ссылке - параметрами-переменными. Последние отличаются тем, что в заголовке процедуры (функции) перед ними ставится служебное слово var.

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

При втором способе (передача по ссылке) все изменения, происходящие в теле процедуры (функции) с формальными параметрами, приводят к немедленным аналогичным изменениям соответствующих им фактических параметров. Изменения происходят с переменными вызывающего блока, поэтому по ссылке передаются выходные параметры. При вызове соответствующие им фактические параметры могут быть только переменными.

Выбор способа передачи параметров при создании процедуры (функции) происходит в соответствии со сказанным выше: входные параметры нужно передавать по значению, а выходные - по ссылке. Практически это сводится к расстановке в заголовке процедуры (функции) описателя var при всех параметрах, которые обозначают результат работы подпрограммы. Однако, в связи с тем, что функция возвращает только один результат, в ее заголовке использовать параметры-переменные не рекомендуется.  

Локальные и глобальные идентификаторы

Использование процедур и функций в Паскале тесно связано с некоторыми особенностями работы с идентификаторами (именами) в программе. В часности, не все имена всегда доступны для использования. Доступ к идентификатору в конкретный момент времени определяется тем, в каком блоке он описан.

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

Основные правила работы с глобальными и локальными именами можно сформулировать так:

  • Локальные имена доступны (считаются известными, "видимыми") только внутри того блока, где они описаны. Сам этот блок, и все другие, вложенные в него, называют областью видимости для этих локальных имен.

  • Имена, описанные в одном блоке, могут совпадать с именами из других, как содержащих данный блок, так и вложенных в него. Это объясняется тем, что переменные, описанные в разных блоках (даже если они имеют одинаковые имена), хранятся в разных областях оперативной памяти.

Глобальные имена хранятся в области памяти, называемой сегментом данных (статическим сегментом) программы. Они создаются на этапе компиляции и действительны на все время работы программы.

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

Имя, описанное в блоке, "закрывает" совпадающие с ним имена из блоков, содержащие данный. Это означает, что если в двух блоках, один из которых содержится внутри другого, есть переменные с одинаковыми именами, то после входа во вложенный блок работа будет идти с локальной для данного блока переменной. Пременная с тем же имнем, описанная в объемлющем блоке, становится временно недоступной и это продолжается до момента выхода из вложенного блока.

Рекомендуется все имена, которые имеют в подпрограммах чисто внутреннее, вспомогательное назначение, делать локальными. Это предохраняет от изменений глобальные объекты с такими же именами.

StudFiles.ru

Параметр (программирование)

У этого термина существуют и другие значения, см. Параметр (значения).

Пара́метр в программировании — принятый функцией аргумент. Термин «аргумент» подразумевает, что конкретно и какой конкретной функции было передано, а параметр — в каком качестве функция применила это принятое. То есть вызывающий код передает аргумент в параметр, который определен в члене спецификации функции.

Формальные и фактические параметры

Важно различать:

  • формальный параметр — аргумент, указываемый при объявлении или определении функции.[1][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)[3][4]. Многие языки, например Си, не имеют механизма вызова по ссылке, но позволяют симулировать его внутри семантики вызова по значению посредством ссылочных типов, в частности, указателей. В последнем случае в сообществах таких языков часто говорят «язык поддерживает две стратегии вычисления», а также о «вызове по указателю» или «вызове по адресу».

На практике, модель вычисления многих промышленных языков (Java, C#) сводится к стратегии «вызов-при-упоминании/передача-по-ссылке». Некоторые более старые языки, в особенности небезопасные языки, такие как C++, сочетают несколько разных моделей вызова, включая экзотичные, такие как «вызов-по-ссылке-на-константу». Исторически вызов по значению и вызов по имени восходят к Алголу-60, созданному в конце 1950-х годов. Только чистые функциональные языки, такие как Clean и Haskell, используют вызов по необходимости (англ. call-by-need), который часто отождествляют (что также не вполне корректно) с ленивыми вычислениями.

Примеры

Передача параметра по ссылке означает что копируется не само значение, а адрес исходной переменной (как в случае передачи параметра по адресу), однако синтаксис используется такой, чтобы программисту не приходилось использовать операцию разыменования и он мог иметь дело непосредственно со значением, хранящимся по этому адресу (как в случае передачи параметра по значению).

Передача по ссылке позволяет избежать копирования всей информации, описывающей состояние объекта (а это может быть существенно больше чем sizeof(int)) и является необходимой для конструктора копирования.

Если функция возвращает значение по ссылке (например, в виде «return *this;»), то её вызов можно использовать слева от оператора присваивания (смотри также L-выражение).

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

Пример на языке С++: #include using namespace std; // для использования cout void f(int x) { // передача параметра по значению cout

Таким образом можно ожидать, что примерная программа напечатает (если закомментировать ошибочную строку) «0010 022 233 333».

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

Язык Fortran подразумевает передачу параметров исключительно по ссылке:

Пример на языке 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. Процедуры и функции // Иллюстрированный самоучитель по Турбо Паскалю.

Ссылки

  1. The GNU C Programming - Actual parameters and formal parameters (англ.).
  2. Определение и вызов функций.
  3. Fredrik Lundh. Call By Object ( (англ.)). effbot.org.
  4. Iota Language Definition. CS 412/413 Introduction to Compilers. Cornell University (2001).

ru.wikipedia.org

Способы передачи параметров функциям

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

В С++ передача параметров осуществляется тремя способами:

· по копии (или по значению);

· по адресу (или через указатель);

· по ссылке.

Это определяется видом объявления параметра в заголовке функции.

Рассмотрим все три способа передачи на примере функции обмена Change(). Ей передаются два параметра, и она должна поменять местами их значения.

1. Передача по копии (по значению):

void Change( int X, int Y ) // определение функции{ int temp; temp = X; X = Y; Y = temp;}//--------------------------------------------------------------------void main( ){ int A = 10, B = 20; Change( A, B ); // вызов функции printf ( “\n A = %d B = %d”, A, B); // A = 10 B = 20 (замена не состоялась) getch ();}

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

Опишем работу программы. В области видимости функции main() существуют две локальные переменные A и B, которые проинициализированы значениями 10 и 20. В момент вызова функции Change() в стеке создаются параметры X и Y, которые получают копии значений аргументов A и B, а также переменная temp. Затем с помощью этой переменной происходит перестановка значений параметров X и Y (прежние значения выделены красным цветом). Однако по окончании работы функции Change() переменные X, Y и temp уничтожаются, поскольку являются локальными переменными, а значения аргументов A и B остаются неизменными.

Таким образом, функция Change() не решает поставленной перед ней задачи. Тем не менее, данный пример иллюстрирует особенность использования параметров-копий: никакие изменения значения параметра внутри функции не отражаются на значении переменной-аргумента, так как параметр является локальной переменной. Это способ передачи параметров в C++ используется по умолчанию.

2. Передача по адресу (через указатель):

void Change( int *X, int *Y ) // определение функции{ int temp; temp = *X; *X = *Y; *Y = temp;}//--------------------------------------------------------------------void main( ){ int A = 10, B = 20; Change( &A, &B ); // вызов функции printf ( “\n A = %d B = %d”, A, B); // A = 20 B = 10 (замена состоялась) getch ();}

Способ передачи параметров по адресу используется для того, чтобы через указатели обеспечить непосредственный доступ к значениям аргументов. В момент вызова функции Change() в стеке создаются параметры-указатели X и Y, которые получают копии адресов аргументов A и B. Теперь параметры X и Y указывают на аргументы A и B. Несмотря на то, что функции Change() не известны имена аргументов A и B, ей известны их адреса, поэтому она имеет доступ к их значениям. С помощью переменной temp происходит перестановка значений аргументов A и B (прежние значения выделены красным цветом). По окончании работы функции Change() переменные X, Y и temp уничтожаются, поскольку являются локальными переменными, но аргументы A и B остаются с новыми значениями. Таким образом, функция выполнила поставленную задачу.

3. Передача по ссылке:

void Change( int &X, int &Y ) // определение функции{ int temp; temp = X; X = Y; Y = temp;}//--------------------------------------------------------------------void main( ){ int A = 10, B = 20; Change( A, B ); // вызов функции printf ( “\n A = %d B = %d”, A, B); // A = 20 B = 10 (замена состоялась) getch ();}

Этот способ передачи параметров появился в C++ для того, чтобы упростить работу с указателями. При передаче по ссылке объявление параметра представляет собой объявление ссылки без инициализации: Тип &ИмяПараметра. Параметр-ссылка локальна в функции: ни в заголовке, ни в ее теле не должно быть объявлено других параметров и переменных с таким же именем. Инициализация параметра-ссылки выполняется во время вызова функции.

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

В момент вызова функции Change() у аргументов A и B появляются вторые имена X и Y. Поэтому функция Change фактически напрямую работает с исходными переменными A и B и изменяет их.

Использование параметров-ссылок вместо передачи по значению или по адресу более эффективно, поскольку:

1) не требуется памяти для копирования аргументов в локальные переменные;

2) не требуется времени на их создание и уничтожение.

Поэтому программы с параметрами-ссылками работают быстрее и используют меньше памяти. Это имеет значение при передаче структур данных большого объема.

Передача параметра по ссылке также используется, если функция должна возвратить не один результат, а несколько.

Если требуется запретить изменение параметра, передаваемого по адресу или по ссылке, то используется модификатор const, например:

int Func( int a, const double &b);

СОВЕТ Рекомендуется указывать const перед всеми параметрами, изменение которых в функции не предусмотрено. Это облегчает отладку. Кроме того, на место параметра типа const& может передаваться константа.

Параметры, передаваемые в функцию, могут быть любого типа (например, вещественного, структурой, перечислением, объединением, указателем), кроме массива или функции, которые передаются с помощью указателей.

studopedia.ru

В чем отличии передачи парметров по ссылке от передачи параметров по значению?

Антон комаров

Передача параметра по значению
Передача параметра по значению означает что вызывающая функция копирует в память, доступную вызываемой, (обычно стек) непосредственное значение. Изменение копии переменной, соответственно, оригинал не затрагивает.

Передача параметра по ссылке
Передача параметра по ссылке означает что копируется не само значение, а адрес исходной переменной (как в случае передачи параметра по адресу) , однако синтаксис используется такой, чтобы программисту не приходилось использовать операцию разыменования и он мог иметь дело непосредственно со значением, хранящимся по этому адресу (как в случае передачи параметра по значению) .
Передача по ссылке позволяет избежать копирования всей информации, описывающей состояние объекта (а это может быть существенно больше чем sizeof(int)) и является необходимой для конструктора копирования.
Если функция возвращает значение по ссылке (например, в виде «return *this;»), то её вызов можно использовать слева от оператора присваивания (смотри также L-выражение) .
В случае если передача по ссылке используется именно как средство увеличения быстродействия, но изменение параметра нежелательно, можно использовать передачу по ссылке константного объекта.
Таким образом можно ожидать, что примерная программа напечатает (если закоментировать ошибочную строку) «0010 022 233 333».
Некоторые языки (или их диалекты) не поддерживают передачу по ссылке, некоторые наоборот - передают параметры исключительно по ссылке, что порождает риск непреднамеренного изменения контекста вызывающей функции.

Nnn7

Если в двух словах, то передача параметра по значению передает лишь информацию о значении функции. Внутри функции используется это значение для операций и все, там же умирает.
Передача по ссылке (адресу) запускает схожий процесс, за тем исключением что передаваемый параметр изменяется так же и вне функции. Т. е. если его изменит функция внутри себя, то он изменится и вне функции, т. к. используется адрес этого параметра.

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