Функции. Функция вызывается при вычислении выражений

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

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

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

Пусть функция sqrt – это функция с одним аргументом – вещественным числом двойной точности,она возвращает результат типа double double sqrt(double x); Рассмотрим функцию sum от трех целых аргументов, которая возвращает целое число int sum(int a, int b, int c);

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

double x = sqrt(3) + 1;sum(k, l, m) / 15;

Если функция не возвращает никакого результата, она должна быть объявлена как void, ее вызов не может быть использован как операнд более сложного выражения, а должен быть записан сам по себе:

func(a,b,c);

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

int sum(int a, int b, int c){ int result; result = a + b + c; return result;}

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

Аргументы a, b и c называются формальными параметрами. Это переменные, которые определены в теле функции, т.е. к ним можно обращаться только внутри фигурных скобок. При написании определения функции программа не знает их значения. При вызове функции вместо них подставляются фактические параметры – значения, с которыми функция вызывается. Выше, в примере вызова функции sum, фактическими параметрами (фактическими аргументами) являлись значения переменных k, l и m.

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

Первое, что мы делаем в теле функции — объявляем внутреннюю переменную result типа целое. Переменные, объявленные в теле функции, также называют локальными. Это связано с тем, что переменная result существует только во время выполнения тела функции sum. После завершения выполнения функции она уничтожается – ее имя становится неизвестным, и память, занимаемая этой переменной, освобождается.

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

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

int k = 2;int l = 3;int m = 5;int s = sum(k, l, m);

Имена функций

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

doublesum(double a, double b, double c){ double result; result = a + b + c; return result;}

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

int x, y, z, ires;double p,q,s, dres;...// вызвать первое определение функции sumires = sum(x,y,z);// вызвать второе определение функции sumdres = sum(p,q,s);

При первом вызове функции sum все фактические аргументы имеют тип int. Поэтому вызывается первая функция. Во втором вызове все аргументы имеют тип double, соответственно, вызывается вторая функция.

Важен не только тип аргументов, но и их количество. Можно определить функцию sum, суммирующую четыре аргумента:

intsum(int x1, int x2, int x3, int x4){ return x1 + x2 + x3 + x4;}

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

int foo(int x);double foo(int x); // ошибка – двукратное определение имени

Рекурсия

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

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

Int fact(int n){ int result = 1; for (int i = 1; i <= n; i++) result = result * i; return result;}

Второй способ:

Int fact(int n){ if (n == 1) // факториал 1 равен 1 return 1; else // факториал числа n равен // факториалу n-1 // умноженному на n return n * fact(n -1);}

Функция fact вызывает сама себя с модифицированными аргументами. Такой способ вычислений называется рекурсией. Рекурсия – это очень мощный метод вычислений. Значительная часть математических функций определяется в рекурсивных терминах. В программировании алгоритмы обработки сложных структур данных также часто бывают рекурсивными. Рассмотрим, например, структуру двоичного дерева. Дерево состоит из узлов и направленных связей. С каждым узлом могут быть связаны один или два узла, называемые сыновьями этого узла. Соответственно, для "сыновей" узел, из которого к ним идут связи, называется "отцом". Узел, у которого нет "отца", называется корнем. У дерева есть только один корень. Узлы, у которых нет "сыновей", называются листьями. Пример дерева приведен на рисунке


В этом дереве узел A – корень дерева, узлы B и C – "сыновья" узла A, узлы D и E – "сыновья" узла B, узел F – "сын" узла C. Узлы D, E и F – листья. Узел B является корнем поддерева, состоящего из трех узлов B, D и E. Обход дерева (прохождение по всем его узлам) можно описать таким образом:

1. Посетить корень дерева.

2. Обойти поддеревья с корнями — "сыновьями" данного узла, если у узла есть "сыновья".

3. Если у узла нет "сыновей" — обход закончен.

Очевидно, что реализация такого алгоритма с помощью рекурсии будет оправдана. Довольно часто рекурсия и итерация взаимозаменяемы (как в примере с факториалом). Выбор между ними может быть обусловлен разными факторами. Чаще рекурсия более наглядна и легче реализуется. Однако, в большинстве случаев итерация более эффективна.


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: