Автор: Пьянков Денис ИТП-3-08 |
|
Программа на С++ может состоять из нескольких функций, которые при выполнении программы вызывают друг друга и обмениваются данными: вызываемая функция получает входные данные от вызывающей функции и обрабатывает их. По окончании работы функция передает в вызывающую функцию результаты расчета. Вызывающая функция может использовать полученные данные в своих расчетах, а может передавать их в другую функцию. Для обмена данными между функциями в С++ используются следующие способы:
С помощью оператора 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; } Тесты:
Недостатки использования глобальных переменных:
Использование аппарата формальных и фактических параметровФормальные параметры – это переменные, которые объявляются в заголовке функции при ее определении. Список формальных параметров определяет: количество данных, которое должна получить или вернуть функция, типы этих данных и порядок следования данных. Фактические параметры (аргументы) функции указываются в круглых скобках при вызове функции после ее имени. Они задают конкретные данные, которые передаются в вызываемую функцию, или переменные, в которые вызываемая функция передает результаты своей работы. В С++ существуют два способа передачи параметров в функцию:
При передаче параметров по значению в формальные параметры функции копируются значения фактических параметров. Функция работает с копиями фактических параметров, не изменяя сами фактические параметры. Поэтому такой способ передачи параметров используется только для получения функцией входных данных и не может быть использован для получения от функции результатов. Синтаксис формального параметразначения: тип имя_параметра Пример прототипа функции с формальным параметромзначением: 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-символом } Тесты:
Если формальный параметр является многомерным массивом, то в таком формальном параметре необходимо указывать максимальные размеры по всем измерениям, кроме первого. Синтаксис формального параметра двумерного массива: тип элементов имя [][максимальное количество столбцов] или тип элементов имя [максимальное количество строк] [макси-мальное количество столбцов] Пример программы удаления из матрицы целых чисел строки с заданным номером, в которой алгоритм удаления строки оформлен в виде функции: #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> |