Вызов функции

Функции, возвращающие результат по ссылке

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

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

void имя(тип1 имя1, тип2 имя2,…, типN имяN, тип1 & имя1, тип2 & имя2,…, типN & имяN)

 

Здесь void – ключевое слово, означающее пусто;

тип1 имя1, тип2 имя2,…, типN имяN – тип и имя входных данных;

тип1 & имя1, тип2 & имя2,…, типN & имяN – тип и имя выходных данных.

Все данные в скобках образуют список параметров, состоящих из имен абстрактных данных (не имеющих значений).

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

Оператор вызова функций, возвращающих результат по ссылке, имеет следующий вид:

имя_функции (имя1, имя2, . . . , имяN);


Здесь имя_функции – имя вызываемой функции;

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

В С++ принято все переменные типа массив воспринимать по умолчанию как переменные по ссылке. Поэтому перед такими переменными в списке параметров знак & не ставиться.

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

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

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

В качестве примера функции, возвращающей результат по ссылке, может быть функция, определяющая наименьшее и наибольшее число ряда чисел a(N). Блок – схема и текст такой функции приведен ниже.

+ _

+

 

void minmax (float a(N), float & min, float & max)

{

short i;

min = max = a[0];

for (i = 1; i < N; i ++)

if (a[i] < min) min = a[i];

else

{

if (a[i] > max) max = a[i];

}

}

В заголовке приведенной функции знаком & (амперсанд) помечены две переменные min и max, играющие роль выходных. В качестве входной переменной используется массив a(N).

15.3.3. Место расположения функций в программе

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

перед главной функцией,

после главной функции.

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

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

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

Пример программы с использованием функций.

 

В заданной матрице a(M*N), где M = 5, а N = 8, необходимо определить наименьший и наибольший элемент.

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

 

inmatr( ) // Функция ввода матрицы

       
 
 
   

 


// Функция определения наименьшего и наибольшего элемента

minmax ( )

 
 


+ _

+

// Главная функция

main( )

a(M*N)

a(M*N) min, max

// Программа вычислений

# include <iostream.h>

# include <conio.h>

# include <iomanip.h>

# define M 5

# define N 8

float a[M][N]; // Глобальные переменные

short i, j;

void inmatr( ) // Функция ввода матрицы с клавиатуры

{

cout << setw(10)<<””<<”Введите матрицу”<<M<<”на”<<N<<endl;

for (i = 0; i < M; i ++)

for (j = 0; j < N; j ++)

cin >> a[i][j];

}

// Функция определения наименьшего наибольшего элемента

void minmax (float & min, float & max)

{

min = max = a[0][0];

for (i = 0; i < M; i ++)

for (j = 0; j < N; j ++)

if ( a[i][j] < min) min = a[i][j];

else

{

if ( a[i][j] > max) max = a[i][j];

}

}

// Главная функция

void main( )

{

float amin, amax; // Локальные переменные

inmatr( ); // Ввод матрицы

clrscr( ); // Очистка экрана

minmax(amin, amax); // Вызов функции minmax( )

cout << setw(35)<<””<<”Результат вычисления”<< endl;

cout << setw(25)<<””<<”min =”<<setw(7)<<setprecision(4)<<amin

<<setw(15)<<””<<”max=”<<setw(7)<<setprecision(4)<<amax

<< endl;

getch( );

}

В этом примере функции inmatr( ) и minmax( ) располагаются перед главной функцией main( ).

Ниже дается вариант программы этого же вычисления, но с расположением функций inmatr( ) и minmax( ) после главной функции main( ).

// Программа вычислений

# include <iostream.h>

# include <conio.h>

# include <iomanip.h>

# define M 5

# define N 8

float a[M][N]; // Глобальные переменные

short i, j;

void inmatr( ); // Прототип

void minmax (float & min, float & max); // Прототип

// Главная функция

void main( )

{

float amin, amax; // Локальные переменные

inmatr( ); // Ввод матрицы

clrscr( ); // Очистка экрана

minmax(amin, amax); // Вызов функции minmax( )

cout << setw(35)<<””<<”Результат вычисления”<< endl;

cout << setw(25)<<””<<”min =”<<setw(7)<<setprecision(4)<<amin

<<setw(15)<<””<<”max=”<<setw(7)<<setprecision(4)<<amax

<< endl;

getch( );

}

// Функция ввода матрицы с клавиатуры

void inmatr( )

{

cout << setw(10)<<””<<”Введите матрицу”<<M<<”на”<<N<<endl;

for (i = 0; i < M; i ++)

for (j = 0; j < N; j ++)

cin >> a[i][j];

}

// Функция определения наименьшего наибольшего элемента

void minmax (float & min, float & max)

{

min = max = a[0][0];

for (i = 0; i < M; i ++)

for (j = 0; j < N; j ++)

if ( a[i][j] < min) min = a[i][j];

else

{

if ( a[i][j] > max) max = a[i][j];

}

}

В этом варианте программы перед главной функцией main( ) располагаются прототипы функций inmatr( ) и minmax( ), а после главной функции – их тексты.

В приведенных вариантах программы после директив препроцессору размещены операторы описания переменной a[N] и параметров циклов i, j. Эти данные описаны как глобальные. Это объясняется тем, что они используются в нескольких функциях, inmatr( ) и minmax( ). Если бы их описывать как локальные, то пришлось бы их описывать в каждой функции, что менее удобно.