Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лекция7-8_модульность.doc.doc
Скачиваний:
14
Добавлен:
12.02.2015
Размер:
81.92 Кб
Скачать
    1. Особенности написания и использования функций в языке с

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

Любая программа на языке С состоит из функций. Любая функция должна быть объявлена и определена. Объявление функции (прототип, заголовок, сигнатура) задает ее имя, тип возвращаемого значения и список передаваемых параметров.Определение функциисодержит кроме объявления,тело функции, представляющее собой последовательность операторов. Объявление функции должно находится в тексте программы раньше ее вызова, а определение может находиться как до (в этом случае не делается отдельного объявления), так и после ее вызова. В языке С описание функции не может быть находится в теле какой-либо другой функции, то есть не может быть локальным. Однако, в других языках программирования, например, вPascal, функции могут быть вложенными.

Таким образом, схема описания функций в программе на языке Cпредставляется следующими двумя способами:

1.

объявление функции f1

….

объявление функции fn

определение главной функции main

определение функции f1

…..

определение функции fn

Причем любая из функций fiможет быть вызвана любой функциейfjи функциейmain

2.

определение функции f1

…..

определение функции fn

определение главной функции main

Причем любая из функций fiможет быть вызвана функциейfj, гдеj>=iи функциейmain

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

Синтаксис определения функции в языке С:

[класс памяти] тип имя_функции ([список параметров]) [throw (исключения)]

{тело функции}

Класс памяти функции задает область действия функции. Для задания класса памяти допустимы только спецификаторы extern и static. Staticуказывает на то, что область действия функции с момента объявления и до конца файла, где она объявлена, extern - на то, что область действия функции во всех модулях, где она объявлена. По умолчанию –static.

Тип функции может быть любым кроме массива и функции (но может быть указателем на массив или функцию), может быть void.

Список параметров определяет величины, которые требуется передать в функцию при ее вызове. Элементы списка параметров разделяются запятыми. Для каждого параметра указывается тип и имя (в объявлении имя не обязательно). Параметры, перечисляемые в заголовке функции, называютсяформальными, а параметры, записанные в операторе вызова функции, называютсяфактическими. В объявлении и определении одной функции типы и порядок следования параметров должны совпадать.

Например,

voidvivod(int); // объявление функции

void vivod (int a) {printf(“%40d”,a;)} // определение функции

vivod (50); //вызов функции

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

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

Функция возвращает значение с помощью оператора

return выражение; или return;.

Выражение в операторе returnдолжно иметь тот же тип что и тип функции. Если функция имеет тип void, то этот оператор можно опустить.

Пример, int sum(int a, int b) {return a+b;}

В функции может быть несколько операторов return, если предусматривается несколько ветвей.

Например, функция, вычисляющая xв степениy.

float pow (int, int);

void main ()

{

printf("%f", pow(2, -2));

getch();

}

float pow (int x, int y)

{

if (!y) return 1;

if (y>0)

{

int p=1;

for (int i=1; i<=y; i++) p*=x;

return p;

}

float p=1;

for (int i=1; i<=(-y); i++) p/=x;

return p;

}

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

Например, функция вычисляющая сумму элементов массива

intSum(int*mas,intn)

{

intsumm=0;

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

summ+=mas[i];

return summ;

}

void main()

{

const int n=3;

int r[n];

randomize();

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

{

r[i]=random(6);

printf(" %d",r[i]);

}

printf("\nSum = %d, Sum(r, n));

getch();

}

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

Рассмотрим подробно механизм работы функций.

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

  2. В стеке выделяется память под формальные параметры функции в соответствии с их типом.

  3. Каждому формальному параметру присваивается значение соответствующего фактического параметра (т.е функции всегда работает с копиями фактических параметров).

  4. В стеке также сохраняется адрес команды, вызвавший функцию. (Именно его и извлекает из стека оператор return. Если в функции, тип которой неvoid, операторreturnотсутствует, то возврат в место вызова не произойдет. В этом случае будут выполняться все команды из памяти подряд, что потенциально приводит к аварийному завершению программы.)

  5. Управление передается на первый оператор тела функции

  6. Оператор returnизвлекает из стека сохраненный адрес и передает на него управление вместе с возвращаемым функцией значением.

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

bool F (int r, int w);

F(178, 65); синтаксически и семантически верно

F(65, 178); синтаксически верно, но семантически не верно

int*a=NULL;F(a, 178); - синтаксически не верно

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

int f (int a) {a++; return a;};

void main ()

{

int n=10;

printf("%d%d%d", n, f(n), n);//10 11 10

}

Перечислим некоторые особенности функций в С.

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

Например,

int sum (int a=1, int b=2)

{return a+b;}

sum();//3

sum(10)//12

sum(10,5)//15

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

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

тип имя (список параметров, …);

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

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

# include“имя файла”

включают в начало каждого из модулей программы.