Oslash; Передача параметров по ссылке

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

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

 

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

 

Вызов по ссылке можно осуществить двумя способами: с помощью ссылочных параметров и с помощью указателей. Ссылочный параметр — это ПСЕВДОНИМ соответствующего аргумента. Чтобы показать, что параметр функции передан по ссылке, после типа параметра в прототипе функции ставится символ амперсанда "&"; такое же обозначение используется в списке типов параметров в заголовке функции. В вызове такой функции реально в функцию передается не сама переменная, а ее адрес, полученный операцией адресации "&". Тогда упоминание в теле вызываемой функции переменной по имени ее параметра в действительности является обращением к исходной переменной в вызывающей функции, и эта исходная переменная может быть изменена.

Альтернативной формой передачи параметра по ссылке является использование указателей. Тогда адрес переменной передается в функцию не операцией адресации "&", а операцией косвенной адресации "*". В списке параметров подобной функции перед именем переменной указывается символ "*", свидетельствуя о том, что передается не сама переменная, а указатель на нее.

 

// Типичная Ошибка!!

void GetArray(int *a) { a=new int[10]; cout<<"Enter array"<<endl; for(int i=0; i<10; i++) cin>>a[i]; }   void main() {   int* a; //передается указатель, а он – не определен) GetArray(a); PutArray(a); }  

 

 

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

void GetArray(int* &a) // ссылка на указатель!!

{

a=new int[10];

cout<<"Enter array"<<endl;

for(int i=0; i<10; i++)

cin>>a[i];

}

 

 

При передаче параметра по ссылке аргументом может быть ТОЛЬКО ПЕРЕМЕННАЯ (простая или структурированная). В этом случае в подпрограмму передается не значение переменной, а ее адрес. Для того, чтобы по нему могло быть занесено новое значение передаваемой в качестве параметра переменной, следует воспользоваться операцией, например, получения адреса — “&”. При этом изменяется работа с данным аргументом в самой подпрограмме : необходимо параметр описать как указатель и использовать, при доступе к нему, операции работы с указателями, что, естественно, немного усложняет текст.

 

void swap (int *a, int *b) { int t; t=*a; *a=*b; *b=t; } void main ( ) { . . . swap (&x,&y); . . . } swap объявлена как функция с двумя аргументами типа указателей на int. При вызове функции swar (&x,&y) адрес x запоминается в a и адрес y запоминается в b. Теперь для одной и той же ячейки существует два имени - синонимы. Ссылки *a и *b в функции swap действуют точно так же, как x и y в main. Присваивание внутри функции swap изменяет содержимое x и y. Компилятор проведет проверку типов аргументов при вызове swap в соответствии с forward-объявлении swap. Типы фактических аргументов соответствуют списку типов аргументов и списку формальных параметров.  

 

Задача:Требуется в заданном массиве из целых чисел поменять местами 2-ой и 6-ой элементы. Требование: в главной программе должны быть только вызовы подпрограмм.

 

Решение

Создадим следующие процедуры:

o void GetMem(int * &x, int n); — для того, чтобы отвести память под массив х из n элементов;

o void DoRandom(int *a, int n); — для того, чтобы задать значения элементов массива а из n элементов с помощью датчика случайных чисел;

o void PrintX(int *x, int n); — для того, чтобы напечатать массив х из n элементов;

o void Change(int*a, int*b); — для того, чтобы поменять местами значения элементов, расположенные по адресам a и b.;

 

/* функция меняет местами значения элементов по адресам а и в */

void Change(int*a, int*b)

{

int z = *a;

*a = *b;

*b = z;

}

/* функция выделяет память под массив */

void GetMem(int * &x, int n)

{

x = new int [n];

}

 

/* функция создает массив ДСЧ */

void DoRandom(int *a, int n)

{

for (int i=0; i<n; i++)

a[i] = random(100);

}

 

/* функция печатает массив */

void PrintX(int *x, int n)

{

cout<< " Array: "<<endl;

for (int i=0; i<n; i++)

cout<<x[i]<<" ";

cout<<endl;

}

 

/* Головная программа */

void main()

{

int* x; // объявить указатель на массив х

GetMem(x,10); // отвести память под массив х

DoRandom(x,10); // задать элементы массива

PrintX(x,10); // напечатать массив

Change(&x[2],&x[6]); // поменять местами значения элементов

PrintX(x,10); // напечатать измененный массив

 

}