Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
C_lect.doc
Скачиваний:
18
Добавлен:
12.11.2018
Размер:
856.06 Кб
Скачать

7.6. Рекурсивные функции

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

#include <stdio.h>

int fact(int a) // Рекурсивная функция для вычисления факториала

{

if (a<0) return 0;

if (a==0) return 1;

return a*fact(a-1); // Вызов функции внутри себя

}

void main()

{

printf("fact(5)=%d", fact(5)); // Печатается fact(5)=120

}

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

7.7. Подставляемые (inline) функции

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

Подставляемые функции появились в языке Си++, в исходном языке Си их не было.

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

  • функция слишком велика;

  • функция рекурсивная;

  • обращение к функции идет до ее определения;

  • функция вызывается более 1 раза в одном выражении;

  • функция имеет цикл, переключатель или оператор goto.

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

#include <stdio.h>

#include <math.h>

inline double getVect(double x, double y)

// Функция считает длину вектора, заданного точкой x, y

{

return sqrt(x*x+y*y);

}

void main()

{

printf("%f", getVect(3., 4.));

7.8. Указатели на функции

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

Формат определения указателя на функцию:

<тип_возвращаемого_значения> (* <имя_указателя>) (<спецификация_формальных_параметров>);

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

Ниже представлен пример использования указателей на функции. В программе вводятся с клавиатуры два вещественных значения, знак операции (+, -, *, /), между значениями выполняется введенная операция, результат выводится на печать. В зависимости от введенного знака операции указатель на функцию в программе настраивается на одну из функций.

#include <stdio.h>

double summa(double x, double y) // Функция вычисляет сумму параметров

{

return x+y;

}

double mult(double x, double y) // Функция вычисляет произведение параметров

{

return x*y;

}

double div(double x, double y) // Функция вычисляет результат деления параметров

{

return x/y;

}

double razn(double x, double y) // Функция вычисляет разность параметров

{

return x-y;

}

void main()

{

double x, y, Rez; // Два исходных параметра и результат операции

char Ch; // Символ определяет знак выполняемой операции

double (*pFun)(double, double); // Указатель на функцию

printf("x="); scanf("%lf", &x); // Ввод x

printf("y="); scanf("%lf", &y); // Ввод y

printf("Ch="); fflush(stdin); // Сброс буфера ввода

scanf("%c", &Ch); // Ввод знака операции с клавиатуры

switch(Ch) // В зависимости от знака операции настраиваем указатель

// на одну из функций

{

case '+': pFun=summa; break;

case '-': pFun=razn; break;

case '*': pFun=mult; break;

case '/': pFun=div; break;

default: printf("Error!"); return;

}

Rez=(*pFun)(x, y); // Вызов функции через указатель

printf("Rez=%f", Rez);

}

7.9. Перегрузка функций (Си++)

Перегрузка функций – это использование одного имени для разных функций. При этом функции должны отличать своей сигнатурой (количеством параметров или их типами).

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

#include <stdio.h>

int summa(int a, int b) // Функция считает сумму 2-х параметров типа int

{

return a+b;

}

int summa(int a, int b, int c) // Функция считает сумму 3-х параметров типа int

{

return a+b+c;

}

double summa(double x, double y) // Функция считает сумму 2-х параметров типа double

{

return x+y;

}

void main()

{

int s1, s2;

double s3;

s1=summa(2, 3); // Вызывается первая функция

s2=summa(5, 5, 1); // Вызывается вторая функция

s3=summa(1., 2., 1.5); // Вызывается третья функция

printf("s1=%d s2=%d s3=%f", s1, s2, s3);

}

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]