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

Учебное пособие_С++2015

.pdf
Скачиваний:
179
Добавлен:
15.03.2016
Размер:
2.8 Mб
Скачать

int c; //локальная переменная if (a>b)

c=a;

else c=b;

return c; // возвращение результата

}

void main()

{int x,y,z; printf("Введите x и y:");

scanf("%d%d",&x,&y); // ввод двух чисел z=maximum(x,y); // обращение к функции maximum

printf("max=%d\n",z);

}

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

#include "stdafx.h" #include "stdlib.h"

#define M 50

void Form_matrix(int A[][M], int m, int n) /*заголовок

функции Form_matrix */

{

int i,j; //локальные переменные

for(i=0;i<m;i++)

for(j=0;j<n;j++) A[i][j]=rand()%100-50;

}

void main()

{int m1,n1,m2,n2; //переменные для задания размерности матриц

int Matr1[M][M],Matr2[M][M]; /*объявление двух матриц размера 50х50 */

printf("Введите размерность Mart1 "); scanf("%d%d",&m1,&n1); // ввод двух чисел

Form_matrix(Matr1,m1,n1); //обращение к функции Form_matrix printf("Введите размерность Mart2 ");

scanf("%d%d",&m2,&n2); // ввод двух чисел

Form_matrix(Matr2,m2,n2); //обращение к функции Form_matrix

}

101

Данный пример демонстрирует использование функции Form_matrix дважды в главной функции. При первом обращении к функции произойдет заполнение матрицы Mart1, а при втором обращении – Matr2, так как их имена указаны в соответствующих обращениях к функции. Функция Form_matrix может заполнить матрицу любого размера, не превышающего 50х50. (Конечно, можно было создать динамические матрицы, но это другая история, и мы говорили о ней в параграфе «Динамическая память»).

В теории о подпрограммах-функциях следует остановиться еще на трех важных вопросах:

обращение к нетипизированной и типизированной функциям;

передача параметров в функцию;

возвращение результатов.

Обращение к функции

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

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

printf("max=%d\n", maximum(x,y));

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

Пример программы с функцией

Вычислить значение: Z = a5 a 5 ,

2a7

где а - заданное вещественное число.

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

P xn x x x ... x,

n раз

где i – номер шага вычисления (умножения); n – число шагов.

102

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

#include "stdafx.h"

 

float ST(float x, int n)

// начало функции ST

{

 

 

int

i;

 

float

P; //локальные переменные i и P

P=1;

 

 

for( i=1; i<= n; i++)

 

P = P*x; //накопление произведения

return

P;

 

}

// конец функции ST

void main()

{

float a,Z;

printf("Введите число а:"); scanf("%f",&a);

Z = (ST(a, 5) + ST(1/a, 5))/(2* ST(a, 7)); printf("Z=%f\n", Z);

}

В процессе выполнения программы после ввода заданного числа а вычисляется значение Z по формуле. В данной формуле обращение к функции ST() осуществляется с помощью трех операндов. При вычислении выражения операнд обращения к функции заменяется значением возвращаемого функцией значения. Далее вычисляется значение Z и выводится на экран.

Предыдущую программу можно скомпоновать так:

#include "stdafx.h"

float ST(float , int ); // прототип функции ST

void main()

{float a,Z;

printf("Введите число а:"); scanf("%f",&a);

Z = (ST(a, 5) + ST(1/a, 5))/(2* ST(a, 7));

printf("Z=%f\n", Z);

}

103

// текст функции ST

float ST(float x, int n)

{

int i; float P; P=1;

for( i=1; i<= n; i++) P = P*x;

return P;

}

Передача параметров в функцию

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

Z = (ST(a, 5) + ST(1/a, 5))/(2* ST(a, 7));

при обращении к функции ST параметры a, 5, 1/a, 7 – фактические данные, с которыми будет работать функция ST в каждом своем вызове.

В заголовке функции ST

float ST(float x, int n)

x и n - это формальные параметры, которые примут в себя копии значений фактических параметров.

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

Механизмы замены параметров

В языке С++ существует два механизма передачи параметров в функции:

по значению и по адресу.

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

которые передаются копии

значений фактических параметров. При

 

104

выполнении функции значения в этих ячейках могут измениться, однако соответствующие им фактические параметры останутся без изменения. Фактическим параметром, передаваемым по значению, может быть константа, переменная или выражение, что и продемонстрировано в предыдущем примере при вызове функции ST().

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

Рассмотрим два примера, иллюстрирующих механизмы передачи

параметров:

 

Пример 1

Пример 2

#include "stdafx.h"

#include "stdafx.h"

void Z (int у)

void Z (int *у)

{

{

y=l;

*y=1;

}

}

void main()

void main()

{ int х;

{ int х;

x=0;

х=0;

Z(x);//обращение к функции Z

Z(&x);//обращение к функции Z

printf("x=%d", x);

printf("x=%d", x);

}

}

В примере 1 функция Z() содержит формальный параметр у, который передается по значению, поэтому его изменение в процедуре (у=1;) не влияет на значение фактического параметра х. После выполнения программы на экран будет выведено: х=0.

В примере 2 у функции Z() формальный параметр у – это указатель. В него передается при вызове функции Z() адрес фактического параметра x. Это означает, что функция Z() изменяет значение y в той же ячейки памяти, где находится значение фактического параметра x . На экран будет выведено:

х = 1.

Параметры-массивы в функциях

Массивы, так же как и простые переменные, можно передавать в функции в качестве параметров. Так как имя массива – это адрес, то передача массива происходит всегда по адресу.

105

Рассмотрим, например, функцию, вычисляющую среднее значение элементов массива. Желательно сделать ее так, чтобы в нее можно было передавать массив любого размера. В языке С++ функции не могут самостоятельно определять размер массива, поэтому он (размер) должен быть обязательно одним из параметров.

#include "stdafx.h"

int Sum ( int A[], int N )//заголовок функции

{

int i, sum; //локальные переменные sum = 0;

for ( i = 0; i < N; i ++ ) sum += A[i];

return sum/N; //возвращаемое значение

}

void main()

{

int x[5]={1,2,3,4,5}, y[3]={11,22,33};

printf("\n sr x=%d sr y=%d\n", Sum(x,5),Sum(y,3));

}

Обратите внимание, что указан отдельным параметром. а только как A[] или *A.

в заголовке функции Sum размер N массива Нельзя объявлять массив-параметр как A[N],

Если в функцию передаѐтся двумерный массив, то описание соответствующего параметра функции должно содержать количество столбцов; количество строк - несущественно, поскольку фактически передаѐтся указатель. Например, так: int Х[ ][5], или Х[5][5].

Рассмотрим пример функции, перемножающей матрицы А и В; результат - матрица С. По правилам математики перемножать можно матрицы, размеры которых (mxn) и (nxk) соответственно. Результирующая матрица будет иметь размеры (mxk).

const nmax = 50;

void product(int А[][nmax], int В[][nmax],int С[][nmax], int m, int n, int k)

{

/* m - число строк в матрице А;

n - число строк в матрице В и число столбцов в матрице А; k - число столбцов в матрице В. */

106

for (int i=0; i< m; i++) for (int j=0; j< k; j++)

{

С[i][j]=0;

for (int l=0; l< n; l++) С[i][j] + = А[i][l]*В[l][j];

}

}

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

В приведѐнном примере есть недостаток - здесь заранее фиксируется максимальная размерность матриц. Но использоваться может только часть памяти.

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

Возвращение результатов

Результат работы функции возвращается в точку вызова с помощью оператора

return [выражение];

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

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

Примеры программирования задач с использованием подпрограмм

Задача 1

Даны два вектора: x = {хi}; i =1,8 и y ={yi};i =1,10 .

Вычислить значение: D = yx , где x mx sx ; y my sy ;

тх, ту - максимальные компоненты векторов x и y sx, sy - средние значения компонент векторов x и y

соответственно; соответственно.

107

Решение:

#include "stdafx.h" #include <math.h>

float Mod_Otk(float *a, int n) /* типизированная функция для нахождения максимального компонента и среднего значения в любом массиве */

{

float maxi, sa, Da; //описание локальных переменных int i;

maxi =-10000; sa=0;

for (i =0;i<n;i++)

{

if (a[i]>maxi) maxi= a[i]; sa += a[i];

}

sa = sa/n;

Da= fabs(maxi - sa); return Da;

}

void main()

{ float X[10],Y[10]; int i;

float Dx, Dy, D; printf("Bведитe массив X:\n"); for (i =0;i<8;i++)

scanf("%f",&X[i]); printf("Bведитe массив Y:\n"); for (i =0;i<10;i++)

scanf("%f",&Y[i]);

Dx = Mod_Otk(X, 8);//вызов функции Mod_Otk для массива X Dy = Mod_Otk(Y,10);//вызов функции Mod_Otk для массива Y

D = Dx/Dy; printf("D=%f\n",D);

}

Задача 2

Даны две матрицы: А = {a i j }5x6 и В = {b i j}4x7.

Вычислить разность: С = КА - KB, где КА и KB - количество положительных элементов в матрицах А и В соответственно.

108

#include "stdafx.h"

int CP(float D[7][7], int m, int n) /*типизированная функция

для подсчета

количества положительных элементов в любой матрице */

{ int

i, j, KD;

KD=0;// инициализация счетчика for (i=0;i<m;i++)

for (j=0;j<n;j++)

if (D[i][j]>0) KD ++; /*добавление в счетчик единицы, если элемент матрицы окажется >0 */

return KD; // возвращение результата в точку вызова

}

int main()

 

{

 

float

A[7][7], B[7][7];

int i,j, C;

printf("Введите матрицу А\n"); for (i=0;i<5;i++)

for (j=0;j<6;j++) scanf("%f",&A[i][j]);

printf("Введите матрицу B\n"); for (i=0;i<4;i++)

for (j=0;j<7;j++) scanf("%f",&B[i][j]);

C= CP(A, 5,6)- CP(B, 4, 7); //вызовы функции СР printf("C=%d\n", C);

return 0;

}

Задача 3

На плоскости декартовыми координатами заданы 10 точек:

{x1,y1},{x2,y2}, ...,{х1 0 1 0 }.

Вывести полярные координаты точки, имеющей наибольший полярный радиус. Вычисление полярных координат одной точки оформить подпрограммой. Расчетные формулы для вычисления полярных координат следующие:

a2 b2 ; arctg ba ; , где а и b -декартовы координаты точки.

109

Решение:

#include "stdafx.h" #include<math.h>

void PK(float a, float b, float *ro, float *fi)

/* безтиповая функция для расчета полярных координат точки */

{

*ro = sqrt(a*a + b*b); *fi = atan(b/a);

}

int main()

{

float X[10], Y[10]; // масcивы для декартовых координат точек float R[10], F[10]; // масcивы для полярных координат точек

int i, N; float maxR;

printf("Введите абсциссы 10 точек\n"); for (i=0;i<10;i++) scanf("%f",&X[i]); printf(" Введите ординаты 10 точек\n"); for (i=0;i<10;i++) scanf("%f",&Y[i]); maxR = 0;

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

{

PK(X[i],Y[i],&R[i],&F[i]);

if (R[i]>maxR) // поиск максимального радиуса

{

maxR =R[i];

N=i; /*запоминаем номер точки, радиус которой больше, чем у предыдущих */

}

}

printf("romax=%f fimax=%f\n", R[N],F[N]);/* вывод полярных координат точки с номером N */

return 0;

}

Задача 4

Для заданных квадратных матриц: A = {a i j}3x3 и В = {bi j}4х4 вычислить симметричные им матрицы по правилу:

110