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

Практикум по основам программирования. Массивы. Строки. Подпрограммы. Учебное пособие

.pdf
Скачиваний:
0
Добавлен:
07.09.2026
Размер:
2 Мб
Скачать
2) подпрограмма должна решать самостоятельную задачу по прин-
ципу одна подпрограмма – одна функция. Например, ввод линейного массива, вычисление произведения матриц, поиск наибольшего эле­мента в одномерном массиве и т. д.
3) подпрограмма должна возвращать управление в ту часть про-
граммы, которая ее вызвала;
4) подпрограмма может вызывать другую подпрограмму, в том
числе и саму себя, в последнем случае имеем дело с рекурсивной под­программой;
5) подпрограмма должна настраиваться на входные данные вызы-
вающей части и возвращать в вызывающую часть результат своих вы­числений;
6) размер подпрограммы желательно ограничивать одной-двумя
страницами исходного текста.
Каждой подпрограмме дается имя, которое используется для акти-
вации действий, описанных в подпрограмме (вызова подпрограммы) в тех местах программы, где необходимо их выполнить. В точке вызова подпрограммы управление передается ее первой команде. Выполнение подпрограммы завершается действиями по возвращению управления в точку вызова – т. е. команде, непосредственно следующей за точкой вызова, называемой точкой возврата.
Таким образом, в структурированной программе между программ-
ными единицами устанавливается отношение вызываемая­вызывающая.
Синтаксически подпрограмма состоит из: – определения подпрограммы, – обращения к подпрограмме.
Определение подпрограммы: <определение подпрограммы> ::= <заголовок подпрограммы>
<тело подпрограммы>
Тело подпрограммы является описанием того частичного алгорит-
ма, который объявляется подпрограммой.
Заголовок подпрограммы задает ее имя и определяет ее входные и
выходные данные.
Обращение к подпрограмме служит для ее активации.
51
Большинство языков программирования допускает подпрограммы
двух видов – подпрограммы-процедуры и подпрограммы-функции (или просто процедуры и функции). В отличие от процедуры функция реализует функциональную зависимость, у которой обязательно дол­жен быть хотя бы один результат. Кроме того, результат функции мо­жет быть, как правило, простого типа.
Функции языка C
Программа на языке C это совокупность подпрограмм – функций (в
дальнейшем просто функций), среди которых выделяется одна обяза­тельная (главная) с именем main. Остальные функции вводятся в структуру программы для улучшения ее структурированности. Их вы­полнение инициируется прямо или косвенно вызовами из функции
main.
В простом случае определение функции на языке C:
<Определение функции> ::= <заголовок функции> <блок> <заголовок функции> <составной оператор>
Таким образом, тело функции задается блоком (блок – это после-
довательность спецификаций переменных и операторов, заключенная в фигурные скобки) или составным оператором.
<Заголовок функции> :: = < тип результата функции> <имя функции> ( [ <cписок формаль-
ных параметров> ] )
| void <имя функции> ( [ <cписок формальных параметров> ] )
В заголовке функции задается тип ее результата, если функция
имеет возвращаемый результат (будем называть его основной резуль­тат), иначе тип void. Функция с типом void является подпрограммой­процедурой. Список формальных параметров, если он не опущен, со­держит перечисленные через запятую спецификации формальных па­раметров. В теле функции, если она возвращает результат, обязательно должен быть хотя бы один оператор возврата в точку вызова:
52
return <выражение>; Выражение определяет возвращаемый (основной) результат, его
тип описан в заголовке функции. Если функция не возвращает никако­го значения (т.е. имеет тип void), оператор возврата может опускаться.
Обращение к функции, возвращающей основной результат, это
первичное выражение вида:
<имя функции>(<список фактических параметров>)
или <имя функции> ( ) , если у функции нет формальных параметров. Вызов такой функции является операндом какого-либо выражения.
Синтаксически обращение к функции, не возвращающей результат,
задается также, но в этом случае обращение – это оператор вызова:
<имя функции>(<список фактических параметров>); или <имя функции> ( ); Одним из важных моментов при организации подпрограмм являет-
ся задание данных, над которыми будут выполняться действия подпро­граммы. Данные в подпрограмму можно передавать двумя способами:
1) используя для этого глобальные объекты, 2) используя формальные параметры.
Функции без параметров
Если используется только первый способ, то в определении под-
программы (ее теле) непосредственно используются данные опреде­ленные вне тела функции. Такие подпрограммы не имеют параметров.
Пример определения функции без параметров (задача нахожде-
ния наибольшего значения среди двух чисел):
int MAX1( ) { return a > b ? a : b; }
Функция MAX1 может выполнять действия только над переменны-
ми a и b (входные данные функции). Переменные a и b должны быть определены вне функций и называются внешними или глобальными
53
переменными. Тело функции MAX1– составной оператор. Обращение к функции MAX1 – операнд выражения, например: x = MAX1 ( ); Пере­менной x будет присвоено значение функции MAX1, т. е. наибольшее из значений a и b.
В таких подпрограммах жестко зафиксированы объекты, над кото-
рыми выполняются действия подпрограммы. Если необходимо приме­нить эту подпрограмму для других объектов требуется изменение са­мих глобальных объектов (их имен) в теле подпрограммы.
Функции с параметрами
Чтобы сделать подпрограмму более гибкой и обеспечить ее общ-
ность, данные в подпрограмму передаются через список формальных параметров. Формальные параметры задают не какие-то конкретные данные программы, а лишь условно определяют объекты подпрограм­мы. Это позволяет применять подпрограммы к различным объектам программы, конкретизируя при каждом обращении ее данные в списке фактических параметров. Все объекты подпрограммы можно разде­лить на входные данные, промежуточные и выходные. В список фор­мальных параметров необходимо вводить только те объекты, которые изменяются при вызове подпрограммы, т. е. входные и выходные дан­ные.
Формальные параметры в C задаются в списке формальных пара-
метров перечислением через запятую спецификаций отдельных пара­метров. Спецификация каждого параметра имеет вид:
<спецификация типа> <имя параметра> Список фактических параметров задается перечислением через за-
пятую фактических данных, над которыми функция должна выполнять действия при данном вызове. При обращении к функции между спи­ском формальных и списком фактических параметров устанавливается соответствие: по взаимному расположению параметров в списках (первому формальному параметру соответствует первый фактический параметр и т. д.), количеству, типу (как при присваивании) и способу связывания.
Связь между формальными и фактическими параметрами может
устанавливаться двумя способами:
54
– связь по значению – значение фактического параметра присваи-
вается формальному. Действия в подпрограмме выполняются над формальной переменной, получившей значение фактического пара­метра;
– связь по адресу – фактический параметр заменяет в теле подпро-
граммы формальный, и подпрограмма получает доступ к фактическо­му параметру. Если говорить более точно, то формальному параметру присваивается адрес (ссылка) фактического параметра. Значение тако­го формального параметра при его использовании в операциях рас­сматривается как адрес того объекта, над которым надо выполнить эту операцию. Такой способ используется как для передачи входных дан­ных, так, и, прежде всего, для выходных данных (результатов).
В C связь между формальными и фактическими параметрами уста-
навливается по значению. Фактический параметр в этом случае – вы­ражение того же типа, что и соответствующий ему формальный. В мо­мент вызова функции вычисляется значение фактического параметра и присваивается формальному параметру. Такой способ позволяет пере­дать в подпрограмму значения входных данных. Изменение формаль­ного параметра, получившего значение фактического, не приводит к изменению фактического параметра.
Пример определения функции с входными параметрами (задача
нахождения наибольшего значения среди двух чисел):
int MAX2(int a, int b) { return a > b ? a : b; }
Функция MAX2 выполняет действия над формальными перемен-
ными a и b (входные данные функции). Переменные a и b получают значения фактических параметров при обращении к MAX2 (т. е. связь между параметрами устанавливается по значению). Результат функции возвращается в точку вызова при выполнении оператора return. Обра­щение к функции MAX2 – операнд выражения, например: x = MAX2 (n
55
+ 1, m*m ); Переменной x будет присвоено значение функции MAX2, т. е. наибольшее из значений выражений n + 1 и m * m.
Если через список формальных параметров должен передаваться
результат функции, то формальный параметр должен быть типа указа­тель, а соответствующий ему фактический параметр – это выражение, значение которого есть адрес переменной результата.
Пример определения функции (процедуры) с входными и выход-
ным параметрами (задача нахождения наибольшего значения среди
двух чисел):
void MAX3(int a, int b, int *c) { *c = a > b ? a : b ; }
Функция MAX3 выполняет действия над формальными перемен-
ными a, b и с. Переменные a, b и c получают значения фактических па­раметров при обращении к MAX3 (т. е. связь между параметрами уста­навливается по значению). Результат функции передается через фор­мальный параметр типа указатель – с. Фактический параметр, соответ­ствующий с – это адрес переменной, которой надо присвоить резуль­тат. При выполнении оператора присваивания, в левой части которого стоит выражение *c (здесь * – это операция разыменования указателя), происходит обращение к области памяти (к переменной), адрес кото­рой является значением с. И туда помещается вычисленное значение правой части оператора присваивания. Обращение к функции MAX3 – оператор вызова функции, например:
MAX3(n + 1, m * m, &y);
(здесь & – это операция получения адреса переменной). Перемен-
ная y получает значение наибольшего из выражений n + 1 и m*m.
Пример определения функции с двумя результатами (задача на-
хождения наибольшего и наименьшего значений среди трех целых чи­сел):
56
int MAXMIN(int x, int y, int z, int *max) { int min;
if (x > y) if (x > z) { *max = x; if (y < z) min = y; else min = z; } else { *max = z; min = y; } else if (y > z) { *max = y; if (x < z) min = x; else min = z; } else { *max = z; min = x; } return min;
}
Один результат – это наименьшее значение из трех величин x, y, z,
он возвращается как основной результат функции. Второй результат – наибольшее из x, y, z, для его возврата используется формальный па­раметр max. Вызов подпрограммы: int r = MAXMIN(a, b, c, &x);
57
Вариант 1:
Вариант 2:
void sqrarray (float a[ ], int n) { for (int i = 0; i < n; i++)
a[i] *=a[i]; }
void sqrarray (float *a, int n) {
for (int i = 0; i < n; i++) a[i] *= a[i];
}
Вариант 3:
Вариант 4:
void SquareArray (float *a, int n) { for (i = 0; i < n; i++) *(a + i) *= *(a+ i); }
void sqrarray (float *a, int n) { for (i = 0; i < n; i++) *a *= *a++; }
Функции с параметрами типа массив
Параметром функции может быть величина сложного типа, напри-
мер массив. В этом случае в функцию передается адрес массива.
Пример определения процедуры с параметром типа массив (за-
дача возведения в квадрат элементов массива):
Все четыре варианта равнозначны, но в первом варианте формаль-
ный параметр a задан более наглядно, он имеет тип массив. Во 2-4 ва­риантах используется то, что имя массива является указателем на на­чало массива, поэтому формальный параметр задан как параметр типа указатель. В 4-м варианте изменение параметра a (a++) приводит к вычислению указателя (адреса) на очередной элемент массива. Вызов подпрограммы sqrarray:
1) const int n = 20; float x [n]; sqrarray (x, n); Все 20 элементов массива x будут возведены в квадрат.
2) const int n = 20; float x [n]; sqrarray (x, n / 2); Первые 10 элементов x будут возведены в квадрат.
58
3) const int n = 20; float x [n]; sqrarray (&x[10], 10); Последние 10 элементов x будут возведены в квадрат.
Пример определения процедуры с параметром типа двумерный
массив (задача поиска строки квадратной матрицы с наибольшей сум-
мой элементов):
const int N =25; void matr(int a[ ][N], int n, int b[ ]) { int i, j, k, s, max; for ( s = 0, i = 0; i < n; i++ ) s += a[0][i]; max = s; k = 0; for ( i = 0; i < n; i++ ) { s = 0; for ( j = 0; j < n; j++ ) s += a[i][j]; if (s > max) { max = s; k = i; } } for ( i = 0; i < n; i++ ) b[i] = a[k][i]; }
Вызов процедуры: main ( ) { int d [N][N], c[N], m; . . . matr (d, m, c); // Поиск строки среди всех строк матрицы
59
matr (d[2], m-2, c); // Поиск строки среди строк матрицы с // номерами от 2 до m - 1 matr (&d[m/2][0], m/2, c); // поиск строки среди строк матрицы с // номерами от m/2 до m-1 }
Пример программы с функциями, параметры которых типа
массив (задача вычисления произведения матриц Z
n×n2
= X
n×n1∙Ynn2
#include <stdio.h> #include <conio.h>
const int n = 15; const int n1= 10; const int n2 = 20;
void MULT(float a[ ][n1], float b[ ][n2], float c[ ][n2], int n, int m, int p) { int i, j, k ; float s; for ( i = 0; i < n; i++ ) for ( j = 0; j < p; j++ ) { for ( s = k = 0; k < m; k++ ) s += a[i][k] * b[k][j]; c[i][j] = s; } }
void input(float a[ ][m], int n, int m) { int i, j; for ( i = 0; i < n; i++ ) for ( j = 0; j < m; j++ ) scanf("%f ", &a[i][j]); }
)
60
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]