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

Параметры функции и глобальные переменные

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

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

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

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

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

· передача значения параметра (передача по значению);

· передача адреса ячейки памяти, связанной с параметром (в С++ такой способ можно реализовать двумя способами – через указатели или ссылки).

Передача по значению используется только для передачи входных параметров (исходных данных) в функцию. По умолчанию параметры передаются именно по значению – в примере 1.12 с функцией sqr единственный параметр передаётся по значению.

Обратите внимание — функции передается лишь значение параметра, которое помещается в локальную переменную, специально созданную для этой цели. Таким образом, в функции используется копия параметра. В теле функции эта копия может изменяться, но сам параметр останется без изменения.

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

Адрес параметра передаётся в функцию в том случае, если по логике работы функции этот параметр должен получить или изменить своё значение в теле функции. Адрес можно передать двумя способами – через указатель (используя операцию *) или через ссылку (операция &). Первый способ достался в наследство от языка С, в С++ при реализации функций рекомендуется использовать ссылки.

В этом случае, в отличие от передачи параметра по значению, функция работает непосредственно с ячейкой памяти, в которой размещён параметр, никакой копии не создаётся.

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

// Пример 1.16 – функция меняет местами значения двух переменных

#include <iostream>

using namespace std;

void change(int &x, int &y){

int k=x; x=y; y=k;

}

int main() { // демонстрация работы change

int a,b;

cout<< "a,b=?"; cin>>a>>b; // ввели два числа

if (a>b) change(a,b); // a всегда будет <=b

cout<<a<<' '<<b<<endl;

system("pause"); return 0;

}

Для полноты картины представим ту же самую функцию, но её параметры передадим, используя указатели:

void change(int *x, int *y){

int k=*x; *x=*y; *y=k;

}

Обращение к такой функции также выглядит немного сложнее, поскольку x и y теперь указатели:

сhange(&a, &b);

Тем не менее, и такой вариант работает.

Передача массивов в функцию

Обратим внимание, что массивы всегда передаются по адресу – ведь имя массива − это адрес массива в памяти. Передача массивов по значению невозможна, очевидно, потому, что создавать копию массива в функции неэффективно.

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

int func(int a[10]){тело функции}

Для массивов переменного размера сам размер также передаётся как параметр, например:

int func(int a[], int n) {тело функции} // n – размер массива

Рекомендуемый способ основан на связи массивов и указателей, например:

int func(int *a, int n){тело функции}//имя массива – указатель на него

При передаче двумерного массива также возможны варианты, например:

int func(int a[10][20]){тело функции}

int func(int a[10][], int n){тело функции}// int a[][] – нельзя!!

Для динамически формируемого двумерного массива в виде массива указателей на массив указателей (см. главу 2) можно использовать такой вариант:

int func(int **a, int n, int m) {тело функции}

Пример передачи массива в функции будет рассмотрен далее (пример 1.15).

Параметры-константы

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

Обычно const используют для параметров, передаваемых по указателю или ссылке. В этом случае использование const — хороший способ передачи исходных данных в функцию (как альтернатива передаче по значению), т. к. при этом не требуется дополнительных затрат памяти для хранения копий параметров. Рекомендуется использовать этот способ для передачи параметров, которые занимают много места в памяти, например, для параметров типа string (например, const string &s), типов на основе vector (например, const vector<int> &x) или других сложных типов.

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

Наши рекомендации