ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 23.06.2021
Просмотров: 1699
Скачиваний: 3

51
11. Функции в Си++
С увеличением объема программы становится невозможно удерживать в памяти
все детали. Чтобы уменьшить сложность программы, ее разбивают на части. В Си++
задача может быть разделена на более простые подзадачи с помощью функций.
Разделение задачи на функции также позволяет избежать избыточности кода, т. к.
функцию записывают один раз, а вызывают многократно. Программу, которая
содержит функции, легче отлаживать.
Часто используемые функции можно помещать в библиотеки. Таким образом,
создаются более простые в отладке и сопровождении программы.
11. 1. Объявление и определение функций
Функция – это именованная последовательность описаний и операторов,
выполняющая законченное действие, например, формирование массива, печать
массива и т. д.
Функция, во-первых, является одним из производных типов СИ++, а ,во-вторых,
минимальным исполняемым модулем программы.
Любая функция должна быть объявлена и определена.
Объявление функции (прототип, заголовок) задает имя функции, тип
возвращаемого значения и список передаваемых параметров.
Определение функции содержит, кроме объявления, тело функции, которое
представляет собой последовательность описаний и операторов.
тип имя_функции([список_формальных_параметров])
{ тело_функции}
Тело_функции – это блок или составной оператор. Внутри функции нельзя
определить другую функцию.
В теле функции должен быть оператор, который возвращает полученное
значение функции в точку вызова. Он может иметь 2 формы:
1)
return выражение;
2)
return;
Первая форма используется для возврата результата, поэтому выражение
должно иметь тот же тип, что и тип функции в определении. Вторая форма
используется, если функция не возвращает значения, т. е. имеет тип void. Программист
может не использовать этот оператор в теле функции явно, компилятор добавит его
автоматически в конец функции перед }.
Тип возвращаемого значения может быть любым, кроме массива и функции, но
может быть указателем на массив или функцию.
Список формальных параметров – это те величины, которые требуется передать
в функцию. Элементы списка разделяются запятыми. Для каждого параметра
указывается тип и имя. В объявлении имена можно не указывать.
Для того, чтобы выполнялись операторы, записанные в теле функции, функцию
необходимо вызвать. При вызове указываются: имя функции и фактические параметры.
Функция
Исх. данные (параметры,
передаваемые в функцию)
Результат (возвращаемое
значение)

52
Фактические параметры заменяют формальные параметры при выполнении операторов
тела функции. Фактические и формальные параметры должны совпадать по количеству
и типу.
Объявление функции должно находиться в тексте раньше вызова функции,
чтобы компилятор мог осуществить проверку правильности вызова. Если функция
имеет тип не void, то ее вызов может быть операндом выражения.
Пример:
Заданы координаты сторон треугольника. Если такой треугольник существует,
то найти его площадь.
1. Математическая модель:
1)
l=sqrt(pow(x1-x2,2)+pow(y1-y2,2));//длина стороны треугольника
2)
p=(a+b+c)/2;
s=sqrt(p*(p-a)*(p-b)*(p-c));//формула Герона
3)
проверка существования треугольника
(a+b>c&&a+c>b&&c+b>a)
2. Алгоритм:
1)
Ввести координаты сторон треугольника (х1,у1),(х2,у2),(х3,у3);
2)
Вычислить длины сторон ab, bc, ca;
3)
Проверить существует ли треугольник с такими сторонами. Если да, то
вычислить площадь и вывести результат.
4)
Если нет, то вывести сообщение.
5)
Если все координаты равны 0, то конец, иначе возврат на п.1.
#include <iostream.h>
#include <math.h>
double line(double x1,double y1,double x2,double y2)
{
//функция возвращает длину отрезка, заданного координатами x1,y1 и x2,y2
return sqrt(pow(x1-x2,2)+pow(y1-y2,2));
}
double square(double a, double b, double c)
{
//функция возвращает площадь треугольника, заданного длинами сторон а,b,c
double s, p=(a+b+c)/2;
return s=sqrt(p*(p-a)*(p-b)*(p-c));//формула Герона
}
bool triangle(double a, double b, double c)
{
//возвращает true, если треугольник существует
if(a+b>c&&a+c>b&&c+b>a) return true;
else return false;
}
void main()
{
double x1=1,y1,x2,y2,x3,y3;
double point1_2,point1_3,point2_3;
do

53
{
cout<<"\nEnter koordinats of triangle:";
cin>>x1>>y1>>x2>>y2>>x3>>y3;
point1_2=line(x1,y1,x2,y2);
point1_3=line(x1,y1,x3,y3);
point2_3=line(x2,y2,x3,y3);
if(triangle(point1_2,point1_3,point2_3)==true)
cout<<"S="<<square(point1_2,point2_3,point1_3)<<"\n";
else cout<<"\nTriagle doesnt exist";
}
while(!(x1==0&&y1==0&&x2==0&&y2==0&&x3==0&&y3==0));
}
11.2.Прототип функции
Для того, чтобы к функции можно было обратиться, в том же файле должно
находиться определение или описание функции (прототип).
double line(double x1,double y1,double x2,double y2);
double square(double a, double b, double c);
bool triangle(double a, double b, double c);
double line(double ,double ,double ,double);
double square(double , double , double );
bool triangle(double , double , double );
Это прототипы функций, описанных выше.
При наличии прототипов вызываемые функции не обязаны размещаться в одном
файле с вызывающей функцией, а могут оформляться в виде отдельных модулей и
храниться в откомпилированном виде в библиотеке объектных модулей. Это относится
и к функциям из стандартных модулей. В этом случае определения библиотечных
функций уже оттранслированные и оформленные в виде объектных модулей, находятся
в библиотеке компилятора, а описания функций необходимо включать в программу
дополнительно. Это делают с помощью препроцессорных команд include< имя файла>.
Имя_файла – определяет заголовочный файл, содержащий прототипы группы
стандартных для данного компилятора функций. Например, почти во всех программах
мы использовали команду #include <iostream.h> для описания объектов потокового
ввода-вывода и соответствующие им операции.
При разработке своих программ, состоящих из большого количества функций, и
, размещенных в разных модулях, прототипы функций и описания внешних объектов
(констант, переменных, массивов) помещают в отдельный файл, который включают в
начало каждого из модулей программы с помощью директивы include”имя_файла”.
11.3.Параметры функции
Основным способом обмена информацией между вызываемой и вызывающей
функциями является механизм параметров. Существует два способа передачи
параметров в функцию: по адресу и по значению.
При передаче по значению выполняются следующие действия:
-
вычисляются значения выражений, стоящие на месте фактических
параметров;
-
в стеке выделяется память под формальные параметры функции;
-
каждому фактическому параметру присваивается значение формального
параметра, при этом проверяются соответствия типов и при необходимости
выполняются их преобразования.

54
Пример:
double square(double a, double b, double c)
{
//функция возвращает площадь треугольника, заданного длинами сторон а,b,c
double s, p=(a+b+c)/2;
return s=sqrt(p*(p-a)*(p-b)*(p-c));//формула Герона
}
1) double s1=square(2.5,2,1);
2) double a=2.5,b=2,c=1;
double s2=square(a,b,c);
3) double x1=1,y1=1,x2=3,y2=2,x3=3,y3=1;
double s3=square(sqrt(pow(x1-x2,2)+pow(y1-y2,2)),//расстояние между 1и2
sqrt(pow(x1-x3,2)+pow(y1-y3,2)), //расстояние между 1 и 3
sqrt(pow(x3-x2,2)+pow(y3-y2,2)));//расстояние между 2 и3
Стек
A 2
.5
B 2
C 1
S
P
P и S – локальные переменные.
Т. о. в стек заносятся копии фактических параметров и операторы функции
работают с этими копиями. Доступа к самим фактическим параметрам у функции нет,
следовательно нет возможности их изменить.
При передаче по адресу в стек заносятся копии адресов параметров,
следовательно, у функции появляется доступ к ячейке памяти, в которой находится
фактический параметр и она может его изменить.
Пример.
void Change(int a,int b)//передача по значению
{int r=a;a=b;b=r;}
int x=1,y=5;
Change(x,y);
A 1
5
B 5
1
r
1
cout<<”x=”<<x<<”y=”<<y;
выведется: x=1y=5
void Change(int *a,int *b)//передача по адресу
{int r=*a;*a=*b;*b=r;}
int x=1,y=5;
Change(&x,&y);
A &
x
5
B &
y
1
r
1
cout<<”x=”<<x<<”y=”<<y;

55
выведется: x=5y=1
Для передачи по адресу также могут использоваться ссылки. При передаче по
ссылке в функцию передается адрес указанного при вызове параметра, а внутри
функции все обращения к параметру неявно разыменовываются.
void Change(int &a,int &b)
{int r=a;a=b;b=r;}
int x=1,y=5;
Change(x,y);
A &
x
5
B &
y
1
r
1
cout<<”x=”<<x<<”y=”<<y;
выведется: x=5y=1
Использование ссылок вместо указателей улучшает читаемость программы, т. к.
не надо применять операцию разыменовывания. Использование ссылок вместо
передачи по значению также более эффективно, т .к. не требует копирования
параметров. Если требуется запретить изменение параметра внутри функции,
используется модификатор const. Рекомендуется ставить const перед всеми
параметрами, изменение которых в функции не предусмотрено (по заголовку будет
понятно, какие параметры в ней будут изменяться, а какие нет).
11.4. Локальные и глобальные переменные
Переменные, которые используются внутри данной функции, называются
локальными. Память для них выделяется в стеке, поэтому после окончания работы
функции они удаляются из памяти. Нельзя возвращать указатель на локальную
переменную, т. к. память, выделенная такой переменной будет освобождаться.
int*f()
{
int a;
. . . .
return&a;// НЕВЕРНО
}
Глобальные переменные – это переменные, описанные вне функций. Они видны
во всех функциях, где нет локальных переменных с такими именами.
Пример:
int a,b;//глобальные переменные
void change()
{
int r;//локальная переменная
r=a;a=b;b=r;
}
void main()
{
cin>>a,b;
change();
cout<<”a=”<<a<<”b=”<<b;
}