Лабораторная работа №.7 Функции
Синтаксис
Важным принципом структурного программирования является принцип модульности. В модульной программе отдельные части, предназначенные для решения частных задач, организованы в функции. Вы уже использовали стандартные функции вывода на экран, чтения с клавиатуры, и так далее. При такой организации, один и тот же фрагмент программы можно использовать несколько раз, не повторяя его текст. Еще одним преимуществом модульного программирования является легкость отладки, чтения и тестирования программы. Приведем пример задачи, которая требует использования модульного подхода к программированию: сформировать три целочисленных массива, элементами которых являются случайные числа – A[5], B[10], C[25]. Длякаждого массива найти сумму минимального и максимального элементов. Для решения этой задачи можно написать четыре функции – функцию создания массива, функцию печати массива, функции поиска минимального и максимального элементов. В основной функции main эти четыре функции будут использоваться для каждого из заданных массивов.
Синтаксически любая функция языка Си описывается следующим образом:
< тип возвращаемого результата> имя функции (<список формальных аргументов>)
{
тело функции
}
Объявление и вызов функций
В языке Си объявить функцию можно несколькими способами. Первый способ – написать функцию до функции main(). Например, напишем функцию поиска минимального числа из трех заданных чисел.
#include <cstdlib>
#include <iostream>
using namespace std;
int min(int a1, int a2, int a3)
// Тип возвращаемого результата – целый, формальные аргументы – три
// целых числа a1,a2,a3.
{
int m = a1;
if (m>a2) m = a2;
if (m>a3) m = a3;
return m; // возвращение результата с помощью оператора return }
int main(int argc, char *argv[])
{
system("chcp 1251");
int x,y,z;
printf("Введите значение x - ");
scanf("%d",&x);
printf("Введите значение y - ");
scanf("%d",&y);
printf("Введите значение z - ");
scanf("%d",&z);
int k = min(x,y,z); // вызов функции с реальными аргументами x,y,z.
// переменной k присваивается возвращаемое значение
printf("\n Минимальное значение - %d \n",k);
system("PAUSE");
return EXIT_SUCCESS;
}
Итак, функцию можно описать до основной функции main(), передать результат в main() помогает оператор return <возвращаемое значение>. Оператор return кроме этого передает управление в вызывающую функцию. Таким образом, оператор может служить и для окончания работы функции. При вызове функции формальные аргументы заменяются реальными аргументами.
Механизм работы модульной программы может быть описан следующим образом:
- при компиляции программы, имеющей пользовательские функции, для каждой функции создается отдельный исполняемый код;
- при вызове функции выполнение программы прерывается, все данные программы сохраняются в стеке, начинает выполняться код тела функции, при этом происходит замена формальных аргументов на реальные, с которыми была вызвана функция;
- при достижении оператора return или закрывающей фигурной скобки функции управление передается в точку вызова вызывающей функции, при этом из стека возвращаются все сохраненные параметры.
Тело функции может быть описано и после тела вызывающей функции, или даже в другом файле, но в этом случае необходимо использовать прототипы функции. Прототипом функции называется указание типа возвращаемого результата, имени функции и списка типов формальных аргументов. Например, для функции min прототип будет выглядеть следующим образом:
int min(int,int,int);
При этом само тело функции может располагаться как после функции main(), так и в другом файле. Использование прототипов связано с принципом обязательного первоначального описания объектов, используемых в программе, то есть, как и любую переменную, функцию необходимо описать перед ее использованием.
Использование прототипов позволяет объединять функции в библиотеки. Для каждой библиотеки может быть написан заголовочный файл с расширением h, в котором будут перечислены прототипы всех функций библиотеки. Тела функций при этом могут храниться в отдельном файле с расширением c (cpp). Заголовочный файл подключается к файлу, содержащему вызывающую функцию с помощью директивы include, выполняется многофайловая компиляция программы (создание проекта). Например, следующий пример описывает небольшую библиотеку простейших арифметических функций.
Файл ariphm.h
int NOD(int,int); // функция нахождения наибольшего общего делителя //для двух целых чисел
float min(float,float);// функция нахождения минимального
//из двух вещественных чисел
float max(float,float);// функция нахождения максимального
// из двух вещественных чисел
Файл ariphm.cpp
// поиск минимального числа
// аргументы функции два вещественных числа х и y
// функция возвращает результат вещественного типа.
float min (float x, float y)
{
if (x>y) return y;
else return x;
}
// поиск максимального числа
// аргументы функции два вещественных числа х и y
// функция возвращает результат вещественного типа.
float max (float x, float y)
{
if (x>y) return x;
else return y;
}
// поиск наибольшего общего делителя
// аргументы функции два целых числа х и y
// функция возвращает результат целого типа.
int NOD(int x, int y) // поиск
{
int z = max(x,y);
int l = min(x,y);
int k = l;
while(z%l!=0)
{
k = z%l;
z = max(k,y);
l = min(k,y);
}
return k;
}
Файл Demo_A.cpp – демонстрация вызова ранее описанных функций.
#include "ariphm.h" // подключение собственного заголовочного файла.
#include <cstdlib>
#include <iostream>
using namespace std;
int main(int argc, char *argv[])
{
system("chcp 1251");printf("Введите два числа: ");
int m,n;
scanf("%d",&m);
scanf("%d",&n);
// Вызов функции NOD. Формальные аргументы x,y заменены
//фактическими m и n.
printf("Наибольший общий делитель: %d \n",NOD(n,m));
// Вызов функции min. Формальные аргументы x,y заменены
//фактическими m и n. Результат работы функции явно
// преобразован к типу int.
printf("Минимальное число: %d \n",(int)min(n,m));
// Вызов функции min. Формальные аргументы x,y заменены
//фактическими m и n. Результат работы функции явно
// преобразован к типу int.
printf("Максимальное число: %d \n",(int)max(n,m));
system("PAUSE");
return EXIT_SUCCESS;
}
Для того, чтобы данный пример выполнился необходимо использовать многофайловую компиляцию. В проект включаются файлы Demo_A.cpp и ariphm.cpp. Все файлы должны находиться в одной папке. Добавление файлов в проект – меню Project - Add to Project.
Локальные переменные
Переменные, описанные в теле функции, называются локальными переменными. Такие переменные видимы только внутри функции и создаются только при вызове функции. При достижении конца функции эти переменные уничтожаются, память, выделенная под хранение таких переменных, освобождается.
#include <stdio.h>
#include <conio.h>
int x = 1;
void func1 (){
int m = 12;
printf("\n x = %d \n", x);
printf("\n m = %d \n", m);}
int main(int argc, char *argv[])
{
int m = 2;
printf("\n x = %d \n", x);
printf("\n m = %d \n", m);
func1();
printf("\n m = %d \n", m);
system("PAUSE");
return EXIT_SUCCESS;
}
Переменная , по отношению к переменным
, объявленным в функциях main() и func() называется глобальной переменной. Зона ее видимости – весь файл, содержащий программу, Время существования – время работы функции main().
Переменная m описанная в функции func() видна только внутри операторных скобок, ограничивающих тело функции.
Переменная m, описанная в функции main() видна только внутри операторных скобок, ограничивающих тело функции.
Результат работы программы будет следующим:
x = 1 // Выводится значение глобальной переменной x.
m = 2 // Выводится значение переменной m, описанной в
//функции main()
// При вызове функции func() значение переменной m = 2
//сохраняется в стеке. Описывается новая
// переменная m, инициализируется значением
//12. На экран выводится значение переменной х, которая
//остается доступной и в функции.
x = 1
// Выводится значение m.
m = 12
// При завершении работы функции func(), переменная m
//перестает существовать. Из стека возвращается
// значение переменной m, описанной в функции main().
m = 2.
Попробуйте изменить значение переменной x в функции func() и попытайтесь объяснить полученный результат.
Выход из функций
Выйти из функции (вернуться в вызывающую функцию, закончить выполнение функции) можно несколькими способами
При достижении закрывающей операторной скобки:
void PRINT(int x)
{
printf(“Значение %d ->”,x);
}
Функция PRINT(int x) закончит свое выполнение по достижению закрывающей скобки.
При достижении оператора return:
float func(float x)
{
x=x*180/3.14;
return sin(x);
}
Функция func(float x) заканчивает свою работу при выполнении оператора return и передает в вызывающую функцию значение синуса заданного значения x.
void my_function(int x, int y){
if (y==0) {printf(“деление на 0”);return;}
float d = ((float)x)/y;
printf(“x/y = %f”);
}
Функция закончит работу, если параметр y равен 0.