Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Комплексное пособие Си.pdf
Скачиваний:
57
Добавлен:
12.03.2015
Размер:
1.57 Mб
Скачать

(прототип функции). Прототип функции – это заголовок функции, завершающийся символом ‘;’.

Например,

float f (int n, float m[ ]); - прототип вещественной функции f от целочисленного входного параметра n и вещественного массива m.

Параметры подпрограмм

Параметры предназначены для передачи входных и выходных данных (переменных) подпрограммы.

В заголовке подпрограммы объявляется тип каждого формального параметра. При вызове указываются аргументы вызова – фактические параметры.

При вызове подпрограммы происходит согласование параметров:

- порядок и типы формальных параметров в объявлении и определении подпрограммы должны совпадать с порядком и типами фактических параметров при вызове подпрограммы.

После вызова подпрограммы выполняются ее операторы, где фактические параметры подставляются вместо формальных параметров.

Передача параметров и согласование формальных и фактических параметров может осуществляться

по значению;

по ссылке (по адресу).

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

89

только входные параметры, т.е. можно передать данные от вызывающей программы к подпрограмме.

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

В языке С параметры всегда передаются по значению, т.е. непосредственно можно использовать только входные параметры. Передачу выходных параметров по ссылке можно реализовать с помощью указателей (ссылок, адресов). При передаче параметра по ссылке в вызове функции нужно получить его адрес с помощью операции &, например &x, а в заголовке функции тип параметра должен быть указатель, например int *x.

Упрощенное правило:

Для передачи параметра по ссылке в заголовке и теле подпрограммы перед именем параметра необходимо указывать символ *, а при вызове - символ &.

Массивы всегда передаются по ссылке. Имя массива является адресом его первого элемента, поэтому на параметры – массивы правило не распространяется (т.е. не нужны символы * и &). Размер массива рекомендуется передавать отдельным параметром. В случае со строкой (символьным массивом) размер строки обычно не передают, т.к. конец строки определяется завершающим нуль символом –‘\0’.

Пример заголовка функции с параметром массив:

90

float f (int n, float m[]) - вещественная функция f от целочисленного параметра n (количество элементов массива) и вещественного массива m[].

Пример вызова этой функции:

int

k; float z[100], t;

t =

f (k, z);

Область действия переменных

Каждая переменная до использования должна быть описана. Локальные переменные. Переменные, объявленные в теле функции,

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

Глобальные переменные. Глобальные переменные объявляются до всех функций или между определениями функций. Областью действия глобальной переменной является вся программа.

Глобальные переменные доступны из любой функции программы, где не объявлены локальные переменные с такими же именами. Однако не рекомендуется использовать их для обмена данными между функциями, т.к. это затрудняет отладку программы. Могут возникнуть трудно обнаруживаемые ошибки из-за того, что любая функция может изменить любую глобальную переменную. Рекомендуется, чтобы прототип функции полностью определял ее сопряжение с другими функциями.

Примеры

Задача. Составить программу вычисления c = n! / (m! * (m-n)!)

В вычисляемом выражении требуется трижды вычислять факториал вида k!, где k! = 1*2*...*k при целом k > 0, 0! = 1.

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

Решение Б Пусть вызов подпрограммы p_fakt (k, f) обозначает действие - операцию присваивания f = k!;. Здесь k - исходные данные, а f - результат.

91

Таким образом, подпрограмма p_fakt() имеет входной параметр k и выходной параметр f.

Обозначим факториалы: n!, m! и (n-m)! через f1, f2 и f3, соответственно. Получим программу, приведенную ниже.

Подпрограмма вычисления факториала p_fakt содержит повторение умножений, т. е. имеет циклическую структуру. Текущим множителем служит вспомогательная переменная j, изменяющаяся с шагом +1.

/* Вариант А. Вычисление c=n!/(m!*(m-n)!)

*/

/* с

помощью подпрограммы, не возвращающей значение*/

#include <stdio.h>

 

 

 

 

void

p_fakt (int k, long *f); /* прототип функции */

/*

 

Вычисление c = n! / (m! * (n-m)!)

 

*/

void

main(void)

/* исходные данные и результат */

{

int n, m, c;

long f1, f2, f3;

/* n!, m!, (n-m)!

 

*/

printf("\nВведите два исходных целых числа ");

scanf("%d %d", &n, &m);

/* f1 = n!

*/

 

p_fakt (n, &f1);

 

 

p_fakt (m, &f2);

 

/* f2 = m!

*/

 

p_fakt (n-m, &f3);

 

/* f3 = (n-m)! */

 

c = f1 / (f2 * f3);

 

 

 

 

printf ("\n c = %d", c);

 

 

 

}

 

Подпрограмма: f = k!;

*/

 

/*

 

 

void p_fakt (int k, long *f)

 

*/

{

int j;

/* текущий множитель

*f=1;

 

 

 

 

 

for (j=2; j<=k; j++)

 

 

 

 

*f = (*f )* j;

/* здесь не обязателен

*/

return;

}

 

 

 

 

 

*/

/* Вариант Б. Вычисление c=n!/(m!*(m-n)!)

/* с помощью функции,

возвращающей значение

*/

#include <stdio.h>

 

/* прототип функции

long fakt (int k);

 

 

 

*/

 

 

 

 

/*

 

Вычисление c = n! / (m! * (n-m)!)

 

*/

void main(void)

 

/* исходные данные и результат

{

int n, m, c;

 

 

 

*/

 

 

 

 

printf("\nВведите два исходных целых числа "); scanf("%d %d", &n, &m);

c = fakt(n) / (fakt (m) * fakt (n-m)); printf ("\n c = %d", c);

}

Функция k!

*/

/*

long

fakt (int k)

 

92

{ long f;

/* k!

 

*/

/* текущий множитель

*/

int j;

f=1;

 

 

for (j=2; j<=k; j++)

 

 

f = f * j;

/* значение функции

*/

return f;

}

 

 

Пояснения к программе.

1.В программах А, Б вызовы подпрограмм расположены в тексте программы раньше, чем определения этих подпрограмм. Поэтому в начале программы объявлены функции, т.е. записаны их прототипы.

2.В программе Б результат работы подпрограммы fakt передается как значение функции. Поэтому переменная f является не параметром, а

вспомогательной локальной переменной и записывается без звездочки.

3.В программе А вызов функции p_fakt, не обладающей значением, может записываться только как самостоятельный оператор. В программе Б вызов функции fakt, обладающей значением, может являться операндом в выражении.

4.В программе А при выводе результата можно заменить строки:

c = f1 / (f2 * f3); printf ("\n c = %d", c);

строкой:

printf ("\n c = %d", f1/(f2*f3));

Тогда переменная c и ее объявление становятся ненужными. В

программе Б также можно обойтись без переменной с.

 

Задача. Даны две строки длиной до 80 символов.

Определить число

латинских букв в каждой строке.

 

#include <stdio.h>

 

/*------------------------------------------------------------

*/

93

/* Функция определения количества лат. букв в заданной строке */

/*------------------------------------------------------------

KolLatBukv (char s[])

 

*/

int

 

 

{

i,

/* индекс очередного символа строки s */

int

k=0;

/* количество лат. букв */

for ( i = 0; s[i] != '\0';

i++ )

if(s[i]>='a'&&s[i]<='z'||s[i]>='A'&&s[i]<='Z') k++;

return k;

 

 

 

 

}

 

 

 

 

 

/*-----------------

 

 

*/

 

 

/* Главная функция */

 

 

/*-----------------

 

 

*/

 

 

void main()

 

 

 

 

{

 

 

 

 

/* заданные строки */

char s1[81], s2[81];

 

printf ("\nВведите две строки символов\n");

gets (s1);

 

 

 

 

gets (s2);

 

 

 

 

printf ("В

1-й

строке

%d

лат. букв\n", KolLatBukv (s1));

printf ("Во

2-й

строке

%d

лат. букв\n", KolLatBukv (s2));

}

 

 

 

 

 

Пример результата выполнения программы:

Введите

две

строки

символов

AaBbcd

123

Zz

 

t = x + y * z / 10 ;

В 1-й

строке

8

лат. букв

Во 2-й

строке

4

лат. букв

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

#include <stdio.h>

 

/*----------------------------------------------------

Функция определения суммы и количества

*/

/*

*/

/*

положительных элементов заданного массива

*/

/*----------------------------------------------------

 

*/

void

SumPos (float m[], int n, float *s, int

*k)

/* Вх. параметры:

m – указатель на заданный массив, n – число элементов массива. Вых. параметры:

*s – сумма положительных элементов массива,

94