Функции, возвращающие результат по ссылке
В тех случаях, когда результат работы функции представляется не одним, а несколькими значениями, возврат их с помощью оператора 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(). Если бы их описывать как локальные, то пришлось бы их описывать в каждой функции, что менее удобно.