Общие сведения
В языке C++ программа состоит из функций. Функции - относительно самостоятельные фрагменты программы, спроектированные для решения конкретных задач и снабженные именем [2]. С одной из них, главной, мы уже знакомы. Функции аналогичны программам в миниатюре и имеют общее название подпрограммы. Главное отличие простой функции от главной в том, что с главной функции начинается выполнение программы, а все остальные функции вызываются либо главной, либо из других функций. Применение подпрограмм дает возможность сэкономить память за счет размещения многократно повторяющихся частей программ в функции, а также возможность конструировать программу как, набор отдельных подпрограмм, что, в свою очередь, позволяет работать группе программистов над сложной задачей. Даже в том случае, если некоторая задача решается в одной программе и одним программистом, лучше оформить ее решение в виде подпрограмм, поскольку функции повышают уровень модульности, облегчает чтение, внесение изменений и коррекцию ошибок в программе. Пусть необходимо написать программу, которая выполняет следующие действия:
вводит массив чисел;
определяет среднее арифметическое чисел;
определяет местоположение максимального элемента;
заменяет максимальный элемент массива средним арифметиче-
ским;
выводит обработанный массив.
Операторную часть такой программы можно записать следующим образом:
{..............
vvodmas(mas);
s
87
max=maxmas(mas);
zamena(mas);
vivod(mas);
…………..
}
Как видно из приведенного фрагмента, программа разделена по смыслу на пять подпрограмм, которые еще следует написать. В программе на языке C++ описание функций может располагаться либо до функции main, либо после функции main. Никакая функция не может быть описана внутри другой функции. Кроме того, функции могут быть описаны в отдельном файле и подключены к программе с помощью директивы препроцессора include. Каждая функция описывается один раз, а вызываться на выполнение может многократно. В языке C++ описание должно обязательно предшествовать вызову функции. Если функция описана после функции, из которой она вызывается, то до вызова функции должен быть помещен прототип функции.
Прототип функции - это заголовок функции, завершающийся точкой с запятой (функция должна быть декларирована). Структура подпрограммы почти полностью повторяет структуру главной функции, что как раз подчеркивает структурированность языка. В функциях могут быть описаны собственные константы, типы, переменные. В этом случае они называются локальными. Их область действия распространяется только на те функции, в которых они описаны. Переменные, описанные вне функций, в том числе и вне главной функции, называются глобальными. Их область действия распространяется на все функции, расположенные в том же файле после описания. Имена локализованных переменных могут совпадать с ранее объявленными глобальными именами. В этом случае считается, что локальное имя "закрывает" глобальное и делает его недоступным, т. е. одноименные локальные и глобальные переменные - это разные переменные. Память под глобальные переменные отводится до, начала выполнения программы и освобождается в момент завершения программы. Доступ к ним возможен из любой функции. Память под локальные переменные выделяется в момент вызова подпрограммы и освобождается после завершения её выполнения. Доступ к ним возможен только из той подпрограммы, в которой они описаны.
В общем случае структуру подпрограммы можно представить следующим образом:
заголовок функции
тело функции
Общая форма записи заголовка функции:
<тип> <имя> (<список формальных параметров>)
З
88
<тип> - тип возвращаемого функцией результата;
<список формальных параметров> - включает в себя параметры,
необходимые для нормального интерфейса, т. е. позволяет передавать данные в подпрограмму и из подпрограммы. Список формальных параметров необязателен и может отсутствовать (круглые скобки опускать нельзя). Если он есть, то может включать в себя параметры, передаваемые по значению, указателю и ссылке. Например:
void sum(float a, float b, float *s)
void sk(int *a, int c, float d)
float f (float x, float &y)
int ab(int a)
void par(void)
Таким образом, в списке формальных параметров перечисляются имена формальных параметров и их тип. Список формальных параметров расширяет раздел описаний фикции, и формальные параметры наряду с локальными переменными используются в выражениях. Тело функции, в том числе и функции main, заключается в фигурные скобки и может содержать описания и операторы.
Вызов функции производится при помощи оператора вызова функций:
<имя>(<список фактических параметров>);
Он записывается в том месте программы, где по логике решения задачи требуется выполнение операторов, определенных в теле функции. После выполнения операторов тела функции управление передается оператору, следующему за оператором вызова.
Следует заметить, что таким образом вызываются функции типа void, т.е. функции, не возвращающие никакого значения. Функции же, возвращающие значения типа int, float и т. д., вызываются упоминанием имени в выражении аналогично стандартным функциям sin, cos и другим. Поэтому в теле таких функции обязательно должен присутствовать оператор возврата return. После ключевого слова return записывается выражение, значение которого вставится вместо имени функции в точке вызова. Функция не может возвращать массив или функцию. В качестве результата, возвращаемого функцией, могут быть значения только простого и ссылочного типа.
Пусть имеется следующее описание функции:
int max (int a, int b)
{
if(a>b) return a;
else return b;
}
Функция max может использоваться в выражении
с=mах(5,3);
m=max(c-d,c+d)+2*max(c*d,c%d);
л
89
printf(''max=%d'', max(c*d, c*d);
В данном примере функция возвращает значение целого типа, фактические параметры - тоже целого типа. Параметры передаются по значению. При первом обращении к функции max формальный параметр а заменяется фактическим параметром, которому соответствует целое число 5, а формальный параметр b - числом 3. Возвращает же функция число 5, и это число присваивается переменной с. При втором и третьем обращениях в качестве фактических параметров передаются выражения. Они сначала вычисляются, и уже значения выражений подставляются в качестве формальны параметров. В четвертом случае функция max вызывается из функции printf.
К списку параметров предъявляются следующие требования:
количество формальных параметров должно быть равно количеству фактических параметров;
порядок следования фактических и формальных параметров дожжен быть один и тот же;
тип каждого фактического должен совпадать с типом соответствующего формального параметра.
Рассмотрим пример использования функции. Даны вещественные числа a,b и с. Необходимо вычислить значения х и у по формулам:
//Пример рr27
#include<stdio.h>
#include<stdlib.h>
#include <conio.h>
float f(float af, float bf, float cf)
{
return (af+bf)/cf;
}
void main()
{
float a,b,c,x,y;
printf("\n Введите a,b,c");
scanf(" %f%f%f ", &a, &b, &c);
x=f(a,b,c*c+10);
y=f(c,a,b*b+ 5);
printf(''\nx=%5.2f y=%5.2f\n'',x,y);
}
Д
90
Для этой же задачи составим программу с использованием параметров, передаваемых по указателю (рr28). // Пример рr28
#include <stdio.h>
#include <conio.h>
void f(float af, float bf, float cf, float *yf)
{
*yf=(af+bf)/cf;
}
void main()
{
float a,b,c,x,y;
printf("\n Введите a,b,c");
scanf(" %f%f%f ",&a,&b,&c);
f(a,b,c*c+10,&x);
f(c,a,b*b+5,&y);
printf("\nx=%5.2f y=%5.2f\n",x,y);
getch();
}
В
91
Третий способ передачи параметров - это передача параметров по ссылке. В языке С этого способа передачи параметров не было. Понятие ссылка появилось только в C++. Ссылочные переменные описываются следующим образом [8]:
<тип> &<имя>=<инициализирующее выражение>
<тип> - любой тип C++;
<имя> - идентификатор переменной ссылочного типа;
<инициализирующее выражение> - выражение, определяющее местоположение в памяти. Например:
int y=16;
int &х=у;
printf("x=%d\n",x);
у=12;
printf("x=%d\n",x);
Результат работы:
x=16
x=12
Ссылочная переменная x определяет местоположение переменной у в памяти в инициализирующем выражении int &x=y. Переменная х обрабатывается как "нормальная" переменная типа int. При обращении к такой переменной нет необходимости в операции снятия ссылки, Когда переменной у присваивается значение 12, то переменная x принимает это новое значение, поскольку она определяет местоположение переменной у в, памяти. Если в этот пример добавить строку х=10, то при этом, значение переменной у станет равным 10. Поскольку х - это ссылка на переменную у, то любое изменение переменной х приведет, к изменению переменной у. Ссылочная переменная при объявлении должна быть инициализирована. Объявление int &x; недопустимо, поскольку неизвестно на что указывает переменная х. Теперь рассмотрим, как же передается параметр по ссылке на примере той же задачи, что и в предыдущей программе рr28. // Пример рr29
#include <stdio.h>
#include <conio.h>
void f(float af, float bf, float cf, float &yf)
{
yf=(af+bf)/cf;
}
void main()
{
float a,b,c,x,y;
printf("\n Введите a,b,c");
scanf(" %f%f%f ", &a, &b, &c);
f(a,b,c*c+10,&x);
92
printf("\nx=%5.2f y=%5.2f\n",x,y);
getch();
}
Здесь используется ссылочный параметр yf. Для формального параметра float &yf инициализирующего выражения не требуется. Инициализирующее выражение подставляется при вызове функции. В частности, при вызове функции f(a,b,c*c+10,x) инициализирующее выражение принимает вид float &yf=x. При вызове функции f(a,b,c*c+10,y) инициализирующее выражение принимает вид float &yf=y. В примере рr29 версия функции более "натуральна", нежели версия в примере рr28, так как нет необходимости в операции разыменовывания.
Рассмотрим
еще один пример использование функции.
Инженеру часто приходится решать
алгебраические или трансцендентные
уравнения, что может представлять
самостоятельную задачу или являться
составной частью более сложных задач.
В обоих случаях практическая ценность
численного метода в значительной мере
определяется быстротой и эффективностью
получения решения. В данном примере
решаем трансцендентное уравнение
(нелинейное уравнение, содержащее
тригонометрические функций или другие
специальные функции, например Ig
х или
).
Методы решения таких уравнений делятся
на прямые и итерационные. Первые позволяют
найти решение непосредственно с помощью
формул и всегда обеспечивают получение
точного результата.
В
итерационных
методах задается процедура решения в
виде многократного применения некоторого
алгоритма. Полученное решение всегда
является приближенным, хотя может быть
сколько угодно близким к точному.
Итерационные методы наиболее удобны
для реализации на компьютере. Пусть
необходимо найти корень уравнения
f(х)=0
на интервале [а,b]
с
точностью е.
При
этом функция f(x)
на этом интервале непрерывна и
монотонна, f(x)=x-sin(x)/cos(x),
a<b,
e>0.
Графическая схема алгоритма представлена
на рис. 25, программа - в рrЗ0.
// Пример pr30
#include <stdio.h>
#include <conio.h>
#include <math.h>
float f(float xf)
{
return xf-sin(fx)-0.25;
}
void main()
{
float a,b,e,x,x1,x2;
printf("\n Введите a,b,e");
93
Рис. 25
if(f(a)*f(b)>0) printf("\nKopней нет\n");
else
{ x1=a;
x2=b;
while(fabs(x2-x1)>e)
{ x=(x1+x2)/2;
if(f(x1)*f(x)>0)
x1=x;
else x2=x;
}
printf("Корень уравнения = %f\nf(x) в этой точке = %f ",x1,f(x1));
}
getch();
}
С
94
В языке C++ функции можно размещать в отдельном файле. В этом случае файл, из которого функция вызывается должен содержать директиву препроцессора #include "имя_файла.срр".
Контрольные вопросы
1. Для чего предназначены функции?
2. Как описываются ссылочные переменные?
3. Как происходит передача параметров в функцию по значению?
4. Как происходит передача параметров в функцию по указателю?
5. Как происходит передача параметров в функцию по ссылке?
6. Какие требования предъявляются к списку формальных параметров?
7. Какого типа значения может возвращать функция?
8. Для чего предназначен оператор return?
9. Какие значения будут напечатаны в результате работы следующей программы: #include<stdio.h>
int а=1,b=2, с=3;
int f(int a, int &b, int *c)
{
a+=2; b++; *c=*c+1;
return a+b;
}
void main()
{
c=f(a+1,b,&c);
printf("\na=%5d b=%5d c=%5d\n",a,b,c);
int y=f(c+5,a,&b);
printf("\na=%5d y=%5d b=%5d c=%5d\n",a,y,b,c);
}
95
Варианты заданий
Табл. 6
96
Окончание табл.6
97
ЛАБОРАТОРНАЯ РАБОТА №8
СТРУКТУРЫ
Цель работы:
Приобретение навыков обработки таблиц, ведомостей, документации.
Порядок выполнения работы:
В соответствии с поставленной задачей необходимо разработать графическую схему алгоритма, составить программу и отладить ее в среде С++, подготовить отчет, ответить на контрольные вопросы и защитить лабораторную работу перед преподавателем.
