Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Разработка комплексов программ на языке С для решения прикладных задач. Учебное пособие

.pdf
Скачиваний:
0
Добавлен:
12.08.2026
Размер:
828 Кб
Скачать
☆

printf("\n");

}

void main(){ int x = 1245; reverse(x); reverse(4329);

reverse(17328);}

Приведем пример функции, возвращающей минимальное из двух значений:

#include<stdio.h>

double minimum(double a, double b) {return (a < b)? a: b;}

void main()

{

double x = 3.5, y = -4.6, min; min = minimum(x,y); printf("%5.2f\n", min);

min = minimum(x,1.8); printf("%5.2f\n", min); printf("%5.2f\n", minimum(-5.4,x)); printf("%5.2f\n", minimum(6.6,9.2));

}

3.2. Передача аргументов по значению и по ссылке

Передача аргументов по значению

Аргументы могут передаваться по значению (by value) и по ссылке (by reference). При передаче аргументов по значению внешний объект, который передается в качестве аргумента в функцию, не может быть изменен в этой функции. В функцию передается само значение этого объекта. Например:

#include<iostream> void square(int, int); int main()

{

41

int a = 4; int b = 5;

std::cout << "Before square: a = " << a << "\tb=" << b << std::endl;

square(a, b);

std::cout << "After square: a = " << a << "\tb=" << b << std::endl;

return 0;

}

void square(int a, int b)

{

a = a * a; b = b * b;

std::cout << "In square: a = " << a << "\tb=" << b << std::endl;

}

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

Ипри выполнении мы увидим, что изменения аргументов

вфункции square действуют только в рамках этой функции. Вне ее значения переменных a и b остаются неизменными:

Before square: a = 4

b = 5

In square: a = 16

b = 25

After square: a = 4 b = 5

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

Передача параметров по ссылке

При передаче параметров по ссылке передается ссылка на объект, через которую мы можем манипулировать самим объек-

42

тов, а не просто его значением. Так, перепишем предыдущий пример, используя передачу по ссылке:

#include<iostream> void square(int&, int&); int main()

{

int a = 4, b = 5;

std::cout << "Before square: a = " << a << "\tb=" << b << std::endl;

square(a, b);

std::cout << "After square: a = " << a << "\tb=" << b << std::endl;

return 0;

}

void square(int &a, int &b)

{

a = a * a; b = b * b;

std::cout << "In square: a = " << a << "\tb=" << b << std::endl;

}

Теперь параметры a и b передаются по ссылке. Ссылочный параметр связывается непосредственно с объектом, поэтому через ссылку можно менять сам объект.

И если мы скомпилируем и запустим программу, то резуль-

тат будет иным:

 

Before square: a = 4

b = 5

In square: a = 16

b = 25

After square: a = 16

b = 25

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

От передачи аргументов по ссылке следует отличать передачу ссылок в качестве аргументов:

43

#include <iostream> void square(int, int); int main()

{

int a = 4; int b = 5;

int &aRef = a; int &bRef = b;

std::cout << "Before square: a = " << a << "\tb=" << b << std::endl;

square(aRef, bRef);

std::cout << "After square: a = " << a << "\tb=" << b << std::endl;

return 0;

}

void square(int a, int b)

{

a = a * a; b = b * b;

std::cout << "In square: a = " << a << "\tb=" << b << std::endl;

}

Если функция принимает аргументы по значению, то изменение параметров внутри функции также никак не скажется на внешних объектах, даже если при вызове функции в нее пере-

даются ссылки на объекты.

 

Before square: a = 4

b = 5

In square: a = 16

b = 25

After square: a = 4 b = 5

 

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

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

44

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

3.3. Перегрузка функций

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

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

return_type1 FunName(parameters_list_1)

{

//...

}

return_type2 Fun Name (parameters_list_2)

{

//...

}

return_typeN FunName (parameters_list_N)

{

// ...

}

где Fun Name – имя перегруженной функции; parameters_list1, parameters_list2, …, parameters_listN – списки парамет-

ров «перегруженной» функции с именем FunName; return_type1, return_type2, …, return_typeN – типы параметров, которые воз-

вращаются перегруженной функцией FunName. Компилятор различает «перегруженные» функции только по списку полученных параметров, а не по возвращаемому значению.

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

45

количеством параметров;

если количество параметров одинаковое, то по типам параметров.

Пример. Функция Max() есть перегруженная и отличается количеством параметров и типами параметров

//функция Max с двумя параметрами типа int int Max(int a, int b)

{

//...

}

// функция Max с тремя параметрами типа int int Max(int a, int b, int c)

{

//...

}

//функция Max с двумя параметрами типа double int Max(double a, double b)

{

//...

}

3.4. Рекурсия

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

#include<iostream> int factorial(int); int main()

{

int n = 5;

int result = factorial(n);

std::cout << "Factorial of " << n << " is equal to " << result << std::endl;

return 0;

46

}

int factorial(int n)

{

if(n>1)

return n * factorial(n-1); return 1;

}

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

Рекурсивная функция обязательно должна иметь некоторый базовый вариант, который использует оператор return и к которому сходится выполнение остальных вызовов этой функции. В случае с факториалом базовый вариант представлен ситуацией, при которой n = 1. В этом случае сработает инструкция return 1;.

Пример. При вызове factorial(5) получится следующая цепь вызовов:

5 * factorial(4)

5 * 4 * factorial(3)

5 * 4 * 3 * factorial(2)

5 * 4 * 3 * 2 * factorial(1)

5 * 4 * 3 * 2 * 1

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

ляется по формуле: f(n)=f(n-1) + f(n-2), причем f(0)=0, а f(1)=1.

Значения f(0)=0 и f(1)=1, таким образом, определяют базовые варианты для данной функции:

#include <iostream> int fibonachi(int); int main()

{

int n;

47

for(int i = 0; i < 10; i++)

{

n = fibonachi(i); std::cout << n << "\t";

}

std::cout << std::endl; return 0;

}

int fibonachi(int n)

{

if (n == 0) return 0; if (n == 1) return 1;

return fibonachi(n – 1) + fibonachi(n – 2);

}

Результат работы программы – вывод 10 чисел из последовательности Фибоначчи на консоль:

0, 1, 1, 2, 3, 5, 8, 13, 21, 34

3.5. Математические функции

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

abs(int x) возвращает модуль целого числа x.

acos(double x) возвращает арккосинус числа x в 1 радианах.

asin(double x) возвращает арксинус числа x в1 радианах.

atan(double x) возвращает арктангенс числа x в 1 радианах.

atof(char *s, double x) преобразует строку s в вещественное число x.

cos(double x) возвращает косинус числа x (x задано в радианах).

48

ceil(double x) округляет число x в большую сторону. exp(double x) возвращает экспоненту числа x. fabs(double x) возвращает модуль вещественного числа x.

sin(double

x)

возвращает

синус

числа

x

(x

задано

в радианах).

 

 

 

 

 

 

 

sqrt(double x) возвращает квадрат числа x.

 

 

 

tan(double

x)

возвращает

тангенс

числа

x

(x

задано

в радианах).

 

 

 

 

 

 

 

floor(double x) округляет число x в меньшую сторону.

fmod(double x, double y) возвращает остаток от деления чис-ла x на число y.

hipot(double x, double y) возвращает квадрат суммы числа x и числа y.

log(double x) возвращает натуральный логарифм числа x. log10(double x) возвращает десятичный логарифм числа x. modf(double x,double& y) возвращает дробную часть числа

x, по адресу y записывается целая часть исходного числа x. pow(double x, double y) возвращает x в степени y.

Контрольные вопросы

1.Как выглядит обобщенное определение функции на языке С? Опишите механизм вызова функций.

2.Что такое формальный параметр функции, фактический параметр функции, прототип функции, сигнатура функции, описание функции?

3.Для чего дается описание функции в программе? Как оно выглядит?

4.Какова роль умалчиваемых значений параметров функции? Какие ограничения на использование умалчиваемых значений налагает синтаксис языка?

5.Что такое передача параметров в функцию по значению? По адресу? По ссылке?

6.Как передавать в функцию одномерные массивы? Двумерные массивы?

49

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

8.Как определяются и для чего используются указатели на функции?

9.Результат какого типа возвращает функция, описанная следующим образом: char My_F(int x, char m);?

10.Перечислите параметры функции, описанной следующим образом:

int EQV(float x, int y, char c);

11.Опишите действие оператора return. В каком случае оператор return можно не использовать в функции?

12.Каким образом можно вернуть управление в вызывающую функцию?

13.Перечислите переменные, локальные для функции min: int min(int *x, int n){

int min1=x[0]; for(int i=1;i<n;i++)

if (x[i]<min1)min1 = x[i]; return min1;

}

14.Функция func1 записана следующим образом:

void func1(int z){ for(int i=0;i<z+1;i++){ prinf("%d \n",i*z);

}

Что будет выведено на экран при вызове func1(5);?

15.Напишите функцию, принимающую значение 0 или 1, если точка с заданными координатами x и y принадлежит или не принадлежит окружности с заданным центром и радиусом. Параметры функции: координаты точки; координаты центра окружности; радиус.

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

17.Запишите функцию, выводящую на экран последова-

тельность n целых чисел xi = n + i – z, i = 0, 1,…, n. Параметры функции n, z.

50

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