Скачать презентацию Языки программирования Функции в языке С часть 2 Скачать презентацию Языки программирования Функции в языке С часть 2

Лекция 8 - Функции в языке С++ (часть 2).ppt

  • Количество слайдов: 25

Языки программирования Функции в языке С++ (часть 2) Полежаев Петр Николаевич Языки программирования Функции в языке С++ (часть 2) Полежаев Петр Николаевич

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

Пример прямой рекурсии (I) Вычисление факториала целого неотрицательного числа n может быть описано рекурсивно Пример прямой рекурсии (I) Вычисление факториала целого неотрицательного числа n может быть описано рекурсивно с помощью формул: 0! = 1 n! = n * (n-1)!, n >=1 Функция, осуществляющая вычисление факториала числа n: int fact(int n) { if (n == 0) //Условие окончания рекурсивного спуска return 1; return n * fact(n-1); //Рекурсивный вызов }

Пример дерева вызова рекурсивной функции fact для первоначального n=3 fact(3) fact(2) fact(1) fact(0) Пример дерева вызова рекурсивной функции fact для первоначального n=3 fact(3) fact(2) fact(1) fact(0)

Некоторые понятия рекурсии Рекурсивный спуск –вызов рекурсивной функции. Действие, совершаемое на рекурсивном спуске – Некоторые понятия рекурсии Рекурсивный спуск –вызов рекурсивной функции. Действие, совершаемое на рекурсивном спуске – операторы, выполняемые до осуществления очередного рекурсивного вызова функции. Условие окончания рекурсивного спуска – условие, выполнение которого ведет к началу рекурсивного возврата. Рекурсивный возврат –возврат из вложенного вызова рекурсивной функции. Действие, совершаемое на рекурсивном возврате – операторы, выполняемые после осуществления очередного рекурсивного вызова функции.

Пример действий, совершаемых на рекурсивном спуске и возврате int fact(int n) { if (n Пример действий, совершаемых на рекурсивном спуске и возврате int fact(int n) { if (n == 0) //Условие окончания рекурсивного спуска return 1; return n * fact(n-1); //Рекурсивный вызов } На рекурсивном спуске выполняется вычисление выражения n – 1 На рекурсивном возврате выполняется умножение n * результат вызова функции fact(n – 1)

Пример прямой рекурсии (II) Вычисление n-го члена последовательности Фибоначчи осуществляется с помощью следующей рекуррентной Пример прямой рекурсии (II) Вычисление n-го члена последовательности Фибоначчи осуществляется с помощью следующей рекуррентной формулы: F 1 = F 2 = 1 Fn=Fn-1+Fn-2, n >=3 Функция, вычисляющая n-й член последовательности Фибоначчи: int fib(int n) { //Условие окончания рекурсивного спуска if (n == 1 || n == 2) return 1; return fib(n - 1) + fib(n - 2); //Рекурсивные вызовы }

Пример дерева вызова рекурсивной функции fib для n=5 fib(5) fib(4) fib(3) fib(2) fib(1) Каждый Пример дерева вызова рекурсивной функции fib для n=5 fib(5) fib(4) fib(3) fib(2) fib(1) Каждый вызов функции приводит к помещению в стековую память параметров функции, точки возврата, размещению локальных переменных. Каждый возврат из функции приводит к освобождению стековой памяти, занимаемой данным вызовом функции.

Назначение рекурсий • Компактная реализация алгоритмов, описываемых рекурсивно, например, алгоритма нахождения НОД (наибольшего общего Назначение рекурсий • Компактная реализация алгоритмов, описываемых рекурсивно, например, алгоритма нахождения НОД (наибольшего общего делителя) двух целых чисел • Вычисления членов рекуррентных последовательностей, например, последовательности Фибоначчи • Обработка структур данных рекурсивной природы, например, деревьев

Достоинства и недостатки рекурсии Достоинство рекурсии – компактная, легко читаемая запись алгоритма Недостатки рекурсии Достоинства и недостатки рекурсии Достоинство рекурсии – компактная, легко читаемая запись алгоритма Недостатки рекурсии – трата времени и памяти на повторные вызовы функции и передачу ей копий параметров, а также опасность переполнения стека Любую рекурсивную функцию можно реализовать без рекурсии с помощью циклов и стека

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

Пример использования параметров со значениями по умолчанию int f 1(int a, int b = Пример использования параметров со значениями по умолчанию int f 1(int a, int b = 2) { return a + b; } double f 2(double a, double b = 9. 0, double c = 10. 0) { return a * b * c; } int main() { cout << f 1(5) << endl; cout << f 1(3, 7) << endl; cout << f 2(5. 0, 2. 0) << endl; cout << f 2(1. 0, 2. 0, 3. 0) << endl; return 0; }

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

Пример перегрузки функций //Объявления перегруженной функции вычисления максимума int max(int a, int b); int Пример перегрузки функций //Объявления перегруженной функции вычисления максимума int max(int a, int b); int max(int a, int b, int c); double max(double a, double b, double c); int main() { double d = 1. 5; int i = 77; cout << "max(20, 10) = " << max(20, 10) << endl; cout << "max(-9. 6, 5. 4) = " << max(-9. 6, 5. 4) << endl; cout << "max(7, " << i << ", 3) = " << max(7, i, 3) << endl; cout << "max(" << d << ", 20. 6, 77. 7) = " << max(d, 20. 6, 77. 7) << endl; return 0; }. . //Определения функций

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

Пример неоднозначности преобразовании типа int f(float x) // (1) { return x * x; Пример неоднозначности преобразовании типа int f(float x) // (1) { return x * x; } double f(double x) // (2) { return x + 1; } int main() { f(2); //Непонятно использовать функцию (1) или (2) return 0; } Схожая неоднозначность возникает, например, при попытке вызова стандартной функции вычисления арккосинуса acos, объявленной в заголовочном файле math. h

Пример неоднозначности при использовании параметровссылок int f(int x, int y) // (1) { return Пример неоднозначности при использовании параметровссылок int f(int x, int y) // (1) { return x + y; } int f(int x, int& y) // (2) { return y = x + 1; } int main() { int a = 3; f(2, a); //Непонятно использовать функцию (1) или (2) return 0; }

Пример неоднозначности при использовании параметров со значениями по умолчанию int f(int x, int y Пример неоднозначности при использовании параметров со значениями по умолчанию int f(int x, int y = 1) // (1) { return x + y; } int f(int x) // (2) { return x * x; } int main() { f(2); //Непонятно использовать функцию (1) или (2) return 0; }

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

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

Формат записи шаблонов функции template <class Type 1, class Type, …, class Type. N> Формат записи шаблонов функции template заголовок_функции { //тело функции } Пример template T sum(T a, T b) { return a + b; }

Пример шаблона функции нахождения максимального элемента массива template <class T> T max(T mas[], int Пример шаблона функции нахождения максимального элемента массива template T max(T mas[], int size) { T max_value = mas[0]; for (int i = 0; i < size; i++) if (mas[i] > max_value) max_value = mas[i]; return max_value; } int main() { int a[] = {5, 6, 7, 3, 1}; double b[] = {-2. 1, 33. 223, 9. 1, 199. 1}; int a_size = sizeof(a) / sizeof(a[0]); int b_size = sizeof(b) / sizeof(b[0]); cout << max(a, a_size) << endl; cout << max(b, b_size) << endl; return 0; }

Функция main() – функция, получающая управления после запуска программы. Форматы записи: //без параметров int Функция main() – функция, получающая управления после запуска программы. Форматы записи: //без параметров int main() { /* … */ } //с двумя параметрами int main(int argc, char* argv []) { /* … */ } где argc – количество передаваемых параметров; argv – массив строк-параметров, передаваемых в программу из командной строки. Параметр argv[0] всегда совпадает с именем программы

Пример программы, печатающей все передаваемый ей параметры #include <iostream> using namespace std; int main(int Пример программы, печатающей все передаваемый ей параметры #include using namespace std; int main(int argc, char* argv []) { cout << "Parameters : " << endl; for (int i = 0; i < argc; i++) { cout << i << " is " << argv[i] << endl; } return 0; }

Вопросы? • Q&A Вопросы? • Q&A