Обмен данными между функциями.

Автор: Пьянков Денис
ИТП-3-08

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

Для обмена данными между функциями в С++ используются следующие способы:

  • оператор return
  • глобальные переменные
  • аппарат формальных и фактических параметров

С помощью оператора return можно передать в вызывающую функцию единственный результат работы функции.

Использование глобальных переменных

Переменная, объявленная вне функций, называется глобальной. Переменная, объявленная в функции, в том числе и в заголовке функции, называется локальной.

Пример использования глобальной переменной двумя функциями: одна функция изменяет значение этой переменной, другая – выводит значение глобальной переменной на экран:

#include <conio.h>
#include <iostream.h>

int a = 1; //глобальная переменная

void f1(int x) //x – локальная переменная
{
  int y = 10; //локальная переменная
  a = x + y;
  cout « "x = " « x « " a = " « a « endl; //x = 2 a = 12
}

int main( )
{
  int z = 2; //локальная переменная
  //Вывод значения глобальной переменной
  cout « "a = " « a « endl; //a = 1 
  f1(z); //вызов функции      
  cout « "a = " « a; //a = 12
  getch();
}

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

Локальные переменные имеют, как правило, локальную продолжительность жизни: память для них выделяется при входе в блок (составной оператор), а освобождается – при выходе из блока.

Глобальную переменную можно использовать от точки ее объявления до конца файла с текстом программы, за исключениием функций, где переменная переобъявлена. Таким образом, глобальные переменные можно использовать для обмена данными между функциями. Например, одна функция может задавать значение глобальной переменной, другая – изменять это значение, а третья – выводить значение переменной на экран.

Пример программы, которая вводит последовательность из n целых чисел и выводит на экран все простые числа этой последовательности:

#include <conio.h>
#include <iostream.h>

int x; //глобальная переменная
bool simple(); //прототип функции проверки числа: простое?

void main()
{
  int n; //количество чисел
  bool ok = false; //true – простое, false - нет
  cout « "n? ";
  cin » n;
  for (int i = 0; i < n; ++i)
  {
    cout « "x? ";
    cin » x;
    if (simple())
    {
      cout « x « ' '; 
      ok = true;
    }
  }
  if (!ok)
  {
    cout « "No";
  }
  getch();
}

bool simple()
{
  int d = 2; //пробный делитель
  while (d <= sqrt(x) && x % d != 0)
  {
    d++;
  }
  if (d <= sqrt(x) || x == 1) 
  {
    return false;
  }
  return true;
}

Тесты:

  1. n=6, a: 2 13 4 1 121 20          результат: 2 13
  2. n=6, a: 4 15 65 22 24 100      результат: “No”

Недостатки использования глобальных переменных:

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

Использование аппарата формальных и фактических параметров

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

В С++ существуют два способа передачи параметров в функцию:

  • по значению
  • по ссылке

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

Синтаксис формального параметразначения:

тип  имя_параметра

Пример прототипа функции с формальным параметромзначением:

float f(int x);

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

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

Для реализации передачи по ссылке используются два способа:

  • связь через формальный параметр-указатель
  • связь через ссылочный формальный параметр

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

#include <conio.h>
#include <iostream.h>

void sumraz(int a, int b, int *s, int *r) //s сумма a и b, r - разность
{
  *s = a + b;
  *r = a - b;
}

void main()
{
  int x, y, sum, raz;
  cout « "&x, y? quot;; 
  cin » x » y;
  sumraz(x, y, &sum, &raz); //вызов функции
  cout « sum « ' ' « raz;
  getch();
}

При вызове функции sumraz в формальные параметры-указатели s и r передаются адреса переменных sum и raz: &sum и &raz. Функция sumraz с помощью операций разыменования (косвенной адресации) *s и *r изменяет значения, которые находятся по полученным параметрами s и r адресам.

Пример программы вычисления суммы и разности двух целых чисел, в которой используется передача выходных данных функции через параметры-ссылки:

#include <conio.h>
#include <iostream.h>

void sumraz(int a, int b, int &s, int &r) 
{
   s = a + b;
   r = a - b;
}

void main()
{
  int x, y, sum, raz;
  cout « "x, y "; 
  cin » x » y;
  sumraz(x, y, sum, raz); //вызов функции
  cout « sum « ' ' « raz; 
  getch();
}

При использовании ссылочных параметров &s и &r компилятор автоматически трактует имена формальных параметров как адреса аргументов. Все действия с параметром-ссылкой в теле функции происходят в действительности с переменной, которая является аргументом функции. Таким образом, параметр-ссылка автоматизирует механизм связи параметров по ссылке. Синтаксис становится проще и, следовательно, в программе будет меньше ошибок.

Передавать по ссылке можно не только выходные данные функции, но и входные. Например, функция sumraz может быть такой:

void sumraz(int &a, int &b, int &s, int &r) 
{
  s = a + b;
  r = a - b;
}

При использовании способа передачи параметров по ссылке аргументы функции не могут быть выражениями – они могут быть только переменными. Это связано с тем, что значением ссылочной переменной может быть только адрес другой переменной. Например, нельзя для последнего варианта функции использовать ее вызов в виде:

sumraz(5, 4, sum, raz);

Использовать входные ссылочные параметры целесообразно для больших по размеру данных, например, структур. В этом случае экономится память и время на копирование данных. Однако при использовании ссылочных параметров для входных данных возникает опасность непреднамеренного изменения входных аргументов функции внутри функции – снижается надежность программы. Для того чтобы защитить программу от подобных ошибок, входные ссылочные формальные параметры следует объявлять как константные:

сonst тип &имя_параметра

Заголовок функции sumraz с входными константными ссылочными параметрами:

void sumraz(const int &a, const int &b, int &s, int &r)

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

Передача массивов в функцию

Чтобы передать массив в функцию надо указать его имя в списке аргументов функции при ее вызове, например, для вызова функции сортировки целочисленного массива a из 100 элементов используется синтаксис:

sort(a, 100);

Так как в С++ имя массива – это константный указатель, значением которого является адрес первого элемента массива, то в этом вызове в функцию передается адрес массива. Массив всегда передается в функцию по ссылке (в функцию передается адрес массива-аргумента). Формальный параметр функции для массива должен иметь синтаксис:

тип элементов имя [ ]

или

тип элементов имя [максимальный размер массива]

или

тип элементов *имя

Примеры задания формальных параметров-массивов:

void sort (int a[], int n)
void sort (int a[100], int n)
void sort (int *a, int n)

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

Пример программы вычисления суммы максимальных элементов двух целочисленных массивов из 20 и 15 элементов. В программе алгоритм поиска максимального элемента целочисленного массива из n элементов оформлен в виде функции.

#include <conio.h>
#include <iostream.h>

int max (int a[ ], int n); //поиск максимального элемента массива

void main()
{
  int b[20], c[15];
  int i; //номер элемента
  for (i = 0; i < 20; ++i)
  {
    cin » b[i];
  }
  for (i = 0; i < 15; ++i)
  {
    cin » c[i];
  }
  cout « " sum = " « max(b,20) + max(c,15);
  getch();
}

int max (int a[ ], int n)
{
  int amax; //значение максимального элемента
  amax = a[0];
  for (int i = 1; i < n; ++i)
  {
    if(a[i] > amax) amax = a[i];
  }
  return amax;
}

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

#include <conio.h>
#include <iostream.h>

//Функция удаления из строки s символов c
void del(char s[ ], char c);

int main( )
{
  char s[80]; //текст
  char c; //удаляемый символ
  cout « "s? "; 
  cin.getline(s,80);
  cout « "c? "; 
  cin » c;
  del(s,c);
  if (s[0] == '\0')
  {
    cout « "s is empty"; //строка стала пустой
  }
  else
  {
    cout « s;
  }
  getch();
}

void del(char s[], char c)
{
  int i = 0; //номер сравниваемого символа строки
  int j = 0; //позиция символа, не совпадающего с символом с
  while(s[i] != '\0') //цикл по всем символам строки
  {
    if (s[i] != с)
    {
      s[j] = s[i]; 
      j++;
    }
  i++;
  }
  s[j]='\0';  //завершение строки 0-символом
}

Тесты:

  1. s: Ааа рaрр еaaеее, c: a      результат: А ррр ееее
  2. s: ааaaaaa, c: a                    результат: строка пуста

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

Синтаксис формального параметра двумерного массива:

тип элементов имя [][максимальное количество столбцов]

или

тип элементов  имя [максимальное количество строк] [макси-мальное количество столбцов]

Пример программы удаления из матрицы целых чисел строки с заданным номером, в которой алгоритм удаления строки оформлен в виде функции:

#include <conio.h>
#include <iostream.h>
#include <iomanip.h>

//Функция удаления из матрицы a из n строк и m столбцов
// строки c номером k
void del(int a[ ][50], int &n, int m, int k);

void main( )
{
  int a[100][50]; //матрица
  int n, m; //количества строк и столбцов
  int k; //номер удаляемой строки
  cout « "n, m? "; 
  cin » n » m;
  cout « "a? ";
  for (int i = 0; i < n; i++)
  {
    for (int j = 0; j < m; ++j)
    {
      cin » a[i][j];
    }
  }
  cout « "k? ";
  cin » k;
  del(a, n, m, k); //вызов функции
  if (n == 0) cout « "a is empty";
  else //Вывод матрицы в виде прямоугольника
  {
    for (int i = 0; i < n; i++)
    { 
      for (int j = 0; j < m; j++)
      {
        cout « setw(7) « a[i][j];
      }
    }
    cout « endl;
  }
  getch();
}

void del(int a[][50], int &n, int m, int k)
{
  for (int i = k; i < n-1; i++)
  {
    for (int j = 0; j < m; j++)
    {
      a[i][j] = a[i+1][j];
    }
  }
  n--;
}

В программе для форматирования вывода матрицы используется манипулятор вывода setw(7). Манипулятор определяет ширину поля вывода для любого значения a[i][j] в 7 позиций, что позволяет выровнять столбцы значений матрицы на экране. Манипулятор вывода setw доступен программе при наличии в ней директивы:

#include <iomanip.h>
        
Предыдущая страница         Следующая страница
Сайт создан в системе uCoz