Программирование на C и C++

Онлайн справочник программиста на C и C++

Параметры-ссылки

По умолчанию С и С++ передает аргументы в функцию, используя передачу по значению. Это означает, что функция использует копии аргументов, благодаря чему предотвращается возмож­ность модификации аргументов функции. Если требуется предоставить функции возможность из­менять значения своих переменных-аргументов, то в языке С параметры должны быть объявлены явным образом как указатели. Тогда функция будет обрабатывать значения вызванных перемен­ных, используя оператор *. Например, следующая программа реализует функцию swap(), обме­нивающую между собой значения двух аргументов целого типа:

#include <iostream.h>
void swap(int *a, int *b);
int main ()
{
int x, y;
x = 99;
у = 88;
cout << x << " " << у << "\n";
swap(&x, &y); // обмен значений
cout << x << " " << у << "\n";
return 0;
}
// версия swap(), явно использующая указатели
void swap (int *a, int *b)
{
int t;
t = *a;
*a = *b;
*b = t;
}

При вызове функции swap() перед подставляемыми в нее переменными должен стоять оператор взятия адреса &. Именно так реализуется передача по ссылке в С. Хотя С++ позволяет подобный синтаксис, он поддерживает и более ясный, более прозрачный метод передачи по ссылке, ис­пользуя параметр типа ссылки (reference parameter).

В С++ можно создавать передаваемые по ссылке параметры. Для этого при объявлении функ­ции перед параметром ставится знак амперсанта &. В качестве примера рассмотрим функцию:

void f(int &f)
{
f = rand(); // изменяет переданный аргумент
}

Обратим внимание, что инструкция

f = rand();

не использует оператор *. При объявлении параметра-ссылки компилятор С++ знает, что это неявный указатель, и обрабатывает его соответствующим образом. Всякий раз при вызове функ­ции f() ей автоматически передается адрес аргументов. Например, в следующем фрагменте кода

int val;
f (val); // получает случайное значение
printf("%d", val);

адрес переменной val, а не значение этой переменной, передается функции f(). Благодаря этому функция f() может модифицировать значение переменной val. Обратим внимание, что при вызо­ве функции f() нет необходимости ставить оператор взятия адреса & перед переменной val. Ком­пилятор автоматически передает функции адрес переменной val.

Для того, чтобы проиллюстрировать использование параметров ссылочного типа, мы перепи­шем функцию swap() с использованием ссылок. Обратим внимание, каким образом функция swap() объявляется и вызывается:

#include <iostream.h>
void swap (int &a, int &b); // объявление в виде ссылок
int main()
{
int x, у;
x = 99;
у = 88;
cout << х << " " << у << "\n";
swap(x, у); // обмен значений
cout << х << " " << у << " \n";
return 0;
}
/* swap () определена с использованием передачи по ссылке, а не по значению */
void swap (int &а, int &b)
{
int t;
t = a;
a = b; // установка значения x
b = t; // установка значения у
}

Еще раз отметим, что определив а и b как параметры ссылочного типа, мы не нуждаемся в ис­пользовании оператора взятия адреса & при вызове функции swap(), а также не используем опе­ратор * внутри функции swap(). На применение переменных ссылочного типа имеется ряд огра­ничений:

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