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

8. Функции

Как только программа приобретает большие размеры, работать с ней становится всё труднее. Для

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

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

С помощью подпрограмм программу можно структурировать, разделяя её текст на блоки (модули), каждый из которых выполняет какую-то одну вполне законченную задачу. Полученные блоки, в свою очередь, также можно разделить на меньшие блоки. Такое деление проводят многократно до тех пор, пока получающиеся части всё ещё остаются самостоятельными задачами.

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

Функция это подпрограмма специального вида, которая выполняет следующие действия:

получает параметры;

выполняет инструкции, согласно заложенному алгоритму;

может возвращать результат в вызывающую программу.

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

Далее мы будем говорить только о функциях, так как в отличие от других языков программирования в

Снет деления на подпрограммы и функции, здесь вся программа строится только из функций.

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

Подводя итоги сказанного можно отметить, что использование функций дает много положительного:

Функции позволяют избежать дублирования кода в одной программе. Кроме того, несколько программ могут совместно использовать код функции.

Программы легче читаются, так как детали "скрыты" внутри функций.

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

8.1.Общие понятия

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

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

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

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

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

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

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

Данные из функции в вызывающую программу передаются при помощи оператора return, который чаще всего завершает тело функции.

PDF created with FinePrint pdfFactory Pro trial version http://www.fineprint.com

8.2. Определение функции

Определение функции состоит из заголовка и тела и имеет следующий формат:

тип имя_функции (тип имя_параметра_1, тип имя_параметра_2, ...) {тело функции};

Тип функции определяет тип значения, которое возвращает функция.

Если тип не указан, то предполагается, что функция возвращает целое значение, типа int.

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

Возвращаемое значение передается в точку вызова во внешнюю, по отношении к функции, программу.

В языке С функция может возвращать только одно значение.

Следует подчеркнуть, что функция возвращает значение, только если ее выполнение заканчивается оператором return, содержащим некоторое выражение. Если оператор return не содержит выражения или выполнение функции завершается без выполнения оператора return (в этом случае функция завершается после выполнения последнего оператора), то возвращаемое значение функции не определено. Когда функция объявлена как возвращающая некоторое значение, а в её теле отсутствует оператор return, поведение программы после выхода из функции может быть непредсказуемым.

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

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

Пример: Функция находит максимальное значение из двух целых чисел a и b и возвращает его в точку

вызова.

 

 

 

 

// Определение функции max

int max(int a, int b)

//a,b – формальные параметры

{

int r;

// тело функции

 

if (a>=b) r=a;

 

 

else r=b;

 

}

return (r);

// Возврат результата

 

 

void main()

 

{

int x=4,y=10,big;

//Вызов функции max, x,y – фактические параметры big=max(x,y);

printf ("big=%d\n",big); // big=10

}

Функция max() имеет два формальных параметра типа int (a и b) и возвращаемое значение типа int. При вызове функции ей передаются фактические параметры(x и y), в теле функции определена локальная переменная r для хранения и возврата результата. После выполнения функции результат находится справа от знака присваивания в выражении big=max(x,y), на месте выражения max(x,y), поэтому говорят, что

результат передается в точку вызова.

8.3. Прототип функции

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

перед функцией main();

после функции main();

в другом модуле (файле) программы.

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

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

Если вызов функции предшествует её определению, то перед вызовом необходимо поместить

объявление функции, которое чаще называют её прототипом. Это связано с тем, что компилятору

PDF created with FinePrint pdfFactory Pro trial version http://www.fineprint.com

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

Прототип функции обладает следующими свойствами:

Прототип имеет такой же вид, что и заголовок определения функции.

Тело функции отсутствует.

Имена формальных параметров могут быть опущены (типы параметров опускать нельзя).

Приведем пример решения предыдущей задачи с использованием прототипа функции max().

В теле функции вместо оператора if будем использовать оператор ? , что позволит записать алгоритм

короче.

 

 

 

 

int max(int a, int b);

//

Прототип функции max

void main()

 

 

{ int x=4,y=10,big;

 

 

big=max(x,y);

//

Вызов функции printf ("big=%d\n",big);

}

 

 

int max(int a, int b)

//

Определение функции max

{ return (a>=b)? a: b;

 

 

}

 

 

Прототип функции max() может быть задан двумя способами: int max (int a, int b);

или

int max (int , int );

Как видно, во втором случае опущены имена параметров функции, что не помешает транслятору проверить правильность её вызова.

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

Операторов return в функции может быть несколько, и тогда они фиксируют несколько точек выхода. Пример: Найти максимальное значение из двух целых чисел a и b, отразить его на экране и вернуть в

точку вызова.

 

 

int max(int , int);

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

void main()

 

{int x=4,y=10,big; big=max(x,y);

}

int max(int a, int b)

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

{if (a > b)

{printf("max = %d\n", a); return a;

}

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

}

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

8.4. Переменные в функции

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

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

принадлежащие определению функции.

Время жизни переменной, определенной в функции от входа до выхода из функции (так как переменная создается при входе в функцию и уничтожается при выходе из неё, то в определениях разных функций переменным можно давать одинаковые имена).

Пример:

#include <stdio.h>

// определение функции father_age()

PDF created with FinePrint pdfFactory Pro trial version http://www.fineprint.com

int father_age()

{int age; // локальная переменная функции printf("\nВведите возраст Вашего отца: ");

scanf (“%d”,&age); return (age);

}

// определение функции your_age() int your_age()

{int age; //локальная переменная функции printf("\nВведите Ваш возраст: ");

scanf (“%d”,&age); return (age);

}

void main()

{//локальные переменные функции main() int f_a, y_a, del;

f_a

= father_age(); // вызовы функций

y_a

= your_age();

del = f_a – y_a;

printf (“\n Ваш отец старше Вас на%d лет\n”, del);

}

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

void main()

{

printf (“\n Ваш отец старше Вас на%d лет\n”,\ father_age()-your_age());

}

Статические переменные могут быть использованы в теле функции. Напомним, что статические

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

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

Пример: Использование статических переменных в определении функции. #include <stdio.h>

// определение функции plus1() void plus1()

{static int x=0;//инструкция выполняется один раз

int y=0;

// выполняется при каждом вызове

x=x+1;

 

y=y+1;

 

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

}

 

void main()

 

{plus1();

 

plus1();

// переменной y уже нет (будет ошибка!)

y++;

plus1();

// переменная х существует, но не видна здесь (будет ошибка!)

x++;

}

 

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

Переменная y создается каждый раз заново при вызове функции plus1(), при этом местоположение её может быть различно, при выходе из функции она уничтожается, и поэтому её значение не сохраняется между вызовами функции.

Врезультате работы программы, на экране будет напечатано :

При 1-ом вызове

х=1, y=1

При 2-ом вызове

х=2, y=1

При 3-ем вызове

х=3, y=1

PDF created with FinePrint pdfFactory Pro trial version http://www.fineprint.com

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

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

Пример: Использование внешних (глобальных) переменных.

Переменная x доступна как в функции main(), так и во всех других функциях программы.

//внешнее (глобальное) объявление переменной int x=3;

// определение функции «увелечение

void plus1()

 

{ int p=10;

// локальная переменная

x=x+1;

 

p=p+1;

 

printf("Плюс 1: x=%d\tp=%d\n",x,p);

}

// определение функции «уменьшение x» void minus1()

{ int m; // локальная переменная x=x-1;

m=m+1;

printf("Минус 1: x=%d\tm=%d\n",x,m);

}

// вызывающая программа void main()

{printf("начало: x=%d\n",x); x--;

p++;

// ошибка доступа!

m++;

// ошибка доступа!

plus1();

 

minus1();

 

minus1();

printf("конец x=%d \n", x);

}

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

Обратите внимание, что локальную переменную p инициировали прямо при создании и работа с ней не вызовет никаких проблем, переменную же m оставили без инициализации и это приведет к получению непредсказуемого результата при выполнении инструкции m=m+1 и печати m. Инициализация локальных переменных - это не просто "правило хорошего тона", а совершенно обязательная вещь.

Если внешняя переменная (в примере - x) не инициализируется явно, то по соглашениям языка С, в ней будет записан нуль (записывается автоматически при трансляции программы). Это возможно сделать, так как внешние переменные создаются один раз на все время работы программы.

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

….

 

int s;

// глобальная переменная

int free()

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

{ int k;

// локальная переменная

return k;

 

}

 

……

 

int main()

 

{

 

printf("%d\n", s); printf("%d\n", free()); return 0;

PDF created with FinePrint pdfFactory Pro trial version http://www.fineprint.com

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]