Функции в Си

Для чего нужны функции в C?

Функции в Си применяются для выполнения определённых действий в рамках общей программы. Программист сам решает какие именно действия вывести в функции. Особенно удобно применять функции для многократно повторяющихся действий.

Простой пример функции в Cи

Пример функции в Cи:

Это очень простая программа на Си. Она просто выводит строку «Functions in C». В программе имеется единственная функция под названием main. Рассмотрим эту функцию подробно. В заголовке функции, т.е. в строке

int main(void)

int – это тип возвращаемого функцией значения;

main — это имя функции;

(void) — это перечень аргументов функции. Слово void указывает, что у данной функции нет аргументов;

return – это оператор, который завершает выполнение функции и возвращает результат работы функции в точку вызова этой функции;

EXIT_SUCCESS — это значение, равное нулю. Оно определено в файле stdlib.h;

часть функции после заголовка, заключенная в фигурные скобки

{
     puts("Functions in C");
     return EXIT_SUCCESS;
}

называют телом функции.

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

Наверх

Как из одной функции в Cи вызвать другую функцию?

Рассмотрим пример вызова функций в Си:

Запускаем на выполнение и получаем: Function in C

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

Заголовок функции sum:

int sum(int a, int b)

здесь int — это тип возвращаемого функцией значения;

sum — это имя функции;

(int a, int b) — в круглых скобках после имени функции дан перечень её аргументов: первый аргумент int a, второй аргумент int b. Имена аргументов являются формальными, т.е. при вызове функции мы не обязаны отправлять в эту функцию в качестве аргументов значения перемнных с именами a и b. В функции main мы вызываем функцию sum так: sum(d, e);. Но важно, чтоб переданные в функцию аргументы совпадали по типу с объявленными в функции.

В теле функции sum, т.е. внутри фигурных скобок после заголовка функции, мы создаем локальную переменную int c, присваиваем ей значение суммы a плюс b и возвращаем её в качестве результата работы функции опрератором return.

Теперь посмотрим как функция sum вызывается из функции main.

Вот функция main:

Сначала мы создаём две переменных типа int

int d = 1; int e = 2;

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

Далее создаём переменную f:

int f = sum(d, e);

её значением будет результат работы функции sum, т.е. мы вызываем функцию sum, которая возвратит значение типа int, его-то мы и присваиваем переменной f. В качестве аргументов передаём d и f. Но в заголовке функции sum

int sum(int a, int b)

аргументы называются a и b, почему тогда мы передаем d и f? Потому что в заголовке функций пишут формальные аргументы, т.е. НЕ важны названия аргументов, а важны их типы. У функции sum оба аргумента имеют тип int, значит при вызове этой функции надо передать два аргумента типа int с любыми названиями.

Ещё одна тонкость. Функция должна быть объявлена до места её первого вызова. В нашем примере так и было: сначала объявлена функция sum, а уж после мы вызываем её из функции main. Если функция объявляется после места её вызова, то следует использовать прототип функции.

Наверх

Прототип функции в Си

Рассмотрим пример функциив Си:

В этом примере функция sum определена ниже места её вызова в функции main. В таком случае надо использовать прототип функции sum. Прототип у нас объявлен выше функции main:

int sum(int a, int b);

Прототип — это заголовок функции, который завершается точкой с запятой. Прототип — это объявление функции, которая будет ниже определена. Именно так у нас и сделано: мы объявили прототип функции

int sum(int a, int b);

далее в функции main вызываем функцию sum

int f = sum(d, e);

а ниже функции main определяем функцию sum, которая предварительно была объявлена в прототипе:

Наверх

Чем объявление функции в Си отличается от определения функции в Си?

Когда мы пишем прототип функции, например так:

int sum(int a, int b);

то мы объявляем функцию.

А когда мы реализуем функцию, т.е. записываем не только заголовок, но и тело функции, например:

то мы определяем функцию.

Наверх

Оператор return

Оператор return завершает работу функции в C и возвращает результат её работы в точку вызова. Пример:

Эту функцию можно упростить:

здесь оператор return вернёт значение суммы a + b.

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

Если в примере значение аргумента a окажется больше двух, то функция вернет ноль (первый случай) и всё, что ниже комментария «// Первый случай;» выполнятся не будет. Если a будет меньше двух, но b будет меньше нуля, то функция завершит свою работу и всё, что ниже комментария «// Второй случай;» выполнятся не будет.

И только если оба предыдущих условия не выполняются, то выполнение программы дойдёт до последнего оператора return и будет возвращена сумма a + b.

Наверх

Передача аргументов функции по значению

Аргументы можно передавать в функцию C по значению. Пример:

В примере, в функции main, создаём переменную int d = 10. Передаём по значению эту переменную в функцию sum(d). Внутри функции sum значение переменной увеличивается на 5. Но в функции main значение d не изменится, ведь она была передана по значению. Это означает, что было передано значение переменной, а не сама переменная. Об этом говорит и результат работы программы: Function in C

т.е. после возврата из функции sum значеие d не изменилось, тогда как внутри функции sum оно менялось.

Наверх

Передача указателей функции Си

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

В этом варианте программы я перешел от передачи аргумента по значению к передаче указателя на переменную. Рассмотрим подробнее этот момент.

В строке

printf("sum = %d\n", sum(&d));

в функцию sum передается не значение переменной d, равное 10-ти, а адрес этой переменной, вот так:

sum(&d)

Теперь посмотрим на функцию sum:

Аргументом её является указатель на int. Мы знаем, что указатель — это переменная, значением которой является адрес какого-то объекта. Адрес переменной d отправляем в функцию sum:

sum(&d)

Внутри sum указатель int *a разыменовывается. Это позволяет от указателя перейти к самой переменной, на которую и указывает наш указатель. А в нашем случае это переменная d, т.е. выражение

a += 5;

равносильно выражению

d += 5;

Результат: функция sum изменяет значение переменной d: Function in C

На этот раз изменяется значение d после возврата из sum, чего не наблюдалось в предыдущм пункте, когда мы передавали аргумент по значению.

Наверх

C/C++ в Eclipse

Все примеры для этой статьи я сделал в Eclipse. Как работать с C/C++ в Eclipse можно посмотреть здесь. Если вы работаете в другой среде, то примеры и там будут работать.