Создание и использование функций

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

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

 

Основные теоретические сведения

 

Создание и использование функций

Принципы программирования на языке Си основаны на понятии функции. Уже были рассмотрены некоторые функции: printf( ), scanf( ), getchar( ), putchar( ). Эти функции являются системными, однако мы создали и несколько собственных функций под общим именем main( ). Выполнение программы всегда начинается с команд, содержащихся в функции main( ), затем последняя вызывает другие функции. Рассмотрим вопрос, как создавать свои собственные функции и делать их доступными для функции main( ), а также для других функций.

 

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

 

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

 

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

 

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

 

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

тип-результата имя-функции (формальные аргументы)

{

тело функции

}

 

Пример:

float f(float x){

float y;

y=x*x;

return y;

}

или

float f(float x){

return x*x;

}

 

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

 

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

return e;

 

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

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

int f(int a){

if (a>5) return a;

else return 0;

}

 

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

Например:

void f(int a){

for (int i=0;i<a;i++)printf("Hello world");

}

 

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

return;

 

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

int abs(int x)

{

if(x < 0) return(-x);

else return(x);

printf("Работа завершена!\n");

}

 

Наличие оператора return препятствует тому, чтобы оператор печати когда-нибудь выполнился в программе.

 

Вызов функций

Вызов функции производится следующим образом:

f(b);

или таким

int t = f(b);

 

В первом случае результат передается системе и не сохраняется в переменной.

 

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

 

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

 

Параметры функции.

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

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

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

print_num(int i, int j)

{

printf("значение i=%d значение j=%d", i,j);

}

 

Обращение в программе к данной функции будет таковым:

 

print_num(6,19);

либо таковым:

int k = print_num(6,19);

 

Обратите внимание, аргументы функции при ее объявлении нельзя записать так: print_num(int i, j)

 

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

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

Пример:

#include <stdio.h>

/* Функция суммирует значения своих параметров */

long summa(int m,...) /*m - число параметров*/

{

int *p=&m; /*настроили указатель на параметр m*/

long t=0;

for(;m>=0;m--) t+=*(++p);

return t;

}

void main()

{

printf("\n summa(2,6,4)=%d",summa(2,6,4));

printf("\n summa(6,1,2,3,4,5,6)=%d", summa(6,1,2,3,4,5,6));

 

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

• по значению

• по указателю

В языке Си++ добавляется еще один способ передачи параметров – по ссылке.

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

 

int a = 5;

int f(int a){

a+=3;

return a;

}

int k = f(a);

 

В данном случае в результате a= 5, k= 8.

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

int *a;

int = 5;

void f(int *a){

(*a)+=3;

}

f(&a);

int k = *a;

 

В данном случае в результате a= 8, k= 8. Обратите внимание, что в функцию необходимо передать адрес переменной (&)

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

int a = 5;

void f(int &a){

a+=3;

}

f(a);

int k = a;

 

Обратите внимание, что в данном случае не нужно писать значек «*». Результат, по прежнему, a= 8, k= 8