Шаг 46.
Передача в функцию и возврат из нее нескольких значений

    Здесь мы рассмотрим вопросы передачи нескольких значений в функцию и из нее.

    Начнем с классического примера. Предположим, что мы хотим, чтобы переменные x и y одного типа обменялись своими значениями с помощью функции, которую мы назовем interchange(). Чтобы было ясно, какая переменная принадлежит функции main(), а какая - функции interchange(), мы будем использовать переменные x и y в первой из них, и u и v - во второй.

#include <iostream.h>
void interchange (int u,int v)
{
      int temp=u;
      u = v; v = temp;
}
/* ------------- */
void main ()
{
      int x=5,y=10;
      /* --------------------------------------- */
      cout << "Вначале  x = " << x << " и  y = " << y << endl;
      interchange (x,y);
      cout << "Теперь  x = " << x << " и  y = " << y << endl;
}
Текст этой программы можно взять здесь.

    Результат работы программы:

   Вначале  x = 5  и  y = 10.
   Теперь   x = 5  и  y = 10.
Переменные не обменялись своими значениями!

    Поместим в функцию interchange() промежуточную печать, чтобы попытаться понять причину ошибки:

void interchange (int u,int v)
{
      cout << "Вначале u=" << u << " и v=" << v << endl;
      int temp=u;
      u = v; v = temp;
      cout << "Теперь u=" << u << " и v=" << v << endl;
}
Текст этой программы можно взять здесь.

    Результат работы программы:

   Вначале x=5 и y=10.
   Вначале u=5 и v=10.
   Теперь  u=10 и x=5.
   Теперь  x=5 и y=10.

    Отсюда видно, что функция interchange() действительно осуществляет обмен значениями между переменными u и v. Проблема состоит в передаче результатов обратно в функцию main()!

    Мы могли бы, конечно, воспользоваться оператором return u, но с его помощью в вызывающую программу можно передать только одно значение.

    Возникает вопрос: как быть, если необходимо вернуть несколько значений? Этого можно достичь несколькими способами, "классическим" среди которых является использование переменных ссылочного типа.

    Внесем изменения в пример:

#include <iostream.h>
void interchange (int *u,int *v)
{
      int p;
      p = *u; *u = *v; *v = p;
}
/* ------------- */
void main ()
{

      int x = 1, y = 3;
      cout << "Имели...     x= " << x << " y = " << y << endl;
      //Обращение к функции (передаются адреса переменных).
      interchange (&x,&y);
      cout << "Получили...  x= " << x << " y = " << y << endl;
}
Текст этой программы можно взять здесь.

    Результат работы программы:

   Имели...    x = 1  y = 3
   Получили... x = 3  y = 1

    Комментарии к примеру. При вызове функции interchange() с аргументами &x,&y вместо передачи значений x и y мы передаем их адреса. Естественно, что формальные аргументы u и v, имеющиеся в определении функции interchange() должны быть описаны как указатели.

    Поскольку x и y - переменные целого типа, то u и v должны быть указателями на переменные целого типа.

    Оператор описания int p; используется с целью резервирования памяти. Мы хотим поместить значение переменной x в переменную p, поэтому пишем: p = *u;. Вспомните, что значение переменной u - это &x, поэтому переменная u ссылается на x. Это означает, что операция *u дает значение x, которое как раз нам и требуется. Аналогично, оператор *u=*v; соответствует оператору x=y;. Попытайтесь самостоятельно описать назначение оператора *v=p;.

    Подведем итоги. Нам требовалась функция, которая могла бы поменять местами значения переменных x и y. Используя указатели и операцию *, функция смогла извлечь величины, помещенные в соответствующие ячейки памяти, и поменять их местами.

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

    Если мы используем форму обращения function1(x), то происходит передача значения переменной x. Эта форма обращения требует, чтобы определение функции включало в себя формальный аргумент того же типа, что и x: function1 (int num).

    Если мы используем форму обращения function2(&x) то происходит передача адреса переменной x. А эта форма обращения требует, чтобы определение функции включало в себя формальный аргумент, являющийся указателем на объект соответствующего типа: function2(int *x).

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


    Замечание. Вторая форма вызова уже применялась нами при обращении к функции scanf(). Когда мы хотим поместить некоторое значение в переменную num, мы пишем scanf ("%d",&num). Данная функция "читает" значение переменной num, а затем помещает это значение по адресу переменной num.


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


Предыдущий шаг Содержание Следующий шаг