Для чего нужны функции в C?
Функции в Си применяются для выполнения определённых действий в рамках общей программы. Программист сам решает какие именно действия вывести в функции. Особенно удобно применять функции для многократно повторяющихся действий.
Простой пример функции в Cи
Пример функции в Cи:
Это очень простая программа на Си. Она просто выводит строку «Functions in C». В программе имеется единственная функция под названием main. Рассмотрим эту функцию подробно. В заголовке функции, т.е. в строке
int – это тип возвращаемого функцией значения;
main — это имя функции;
(void) — это перечень аргументов функции. Слово void указывает, что у данной функции нет аргументов;
return – это оператор, который завершает выполнение функции и возвращает результат работы функции в точку вызова этой функции;
EXIT_SUCCESS — это значение, равное нулю. Оно определено в файле stdlib.h;
часть функции после заголовка, заключенная в фигурные скобки
puts(«Functions in C»);
return EXIT_SUCCESS;
}
называют телом функции.
Итак, когда мы работаем с функцией надо указать имя функции, у нас это main, тип возвращаемого функцией значения, у нас это int, дать перечень аргументов в круглых скобках после имени функции, у нас нет аргументов, поэтому пишем void, в теле функции выполнить какие-то действия (ради них и создавалась функция) и вернуть результат работы функции оператором return. Вот основное, что нужно знать про функции в C.
Как из одной функции в Cи вызвать другую функцию?
Рассмотрим пример вызова функций в Си:
Запускаем на выполнение и получаем:
В этом примере создана функция sum, которая складывает два целых числа и возвращает результат. Разберём подробно устройство этой функции.
Заголовок функции sum:
здесь 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
их мы передадим в функцию sum в качестве значений аргументов.
Далее создаём переменную f:
её значением будет результат работы функции sum, т.е. мы вызываем функцию sum, которая возвратит значение типа int, его-то мы и присваиваем переменной f. В качестве аргументов передаём d и f. Но в заголовке функции sum
аргументы называются a и b, почему тогда мы передаем d и f? Потому что в заголовке функций пишут формальные аргументы, т.е. НЕ важны названия аргументов, а важны их типы. У функции sum оба аргумента имеют тип int, значит при вызове этой функции надо передать два аргумента типа int с любыми названиями.
Ещё одна тонкость. Функция должна быть объявлена до места её первого вызова. В нашем примере так и было: сначала объявлена функция sum, а уж после мы вызываем её из функции main. Если функция объявляется после места её вызова, то следует использовать прототип функции.
Прототип функции в Си
Рассмотрим пример функциив Си:
В этом примере функция sum определена ниже места её вызова в функции main. В таком случае надо использовать прототип функции sum. Прототип у нас объявлен выше функции main:
Прототип — это заголовок функции, который завершается точкой с запятой. Прототип — это объявление функции, которая будет ниже определена. Именно так у нас и сделано: мы объявили прототип функции
далее в функции main вызываем функцию sum
а ниже функции main определяем функцию sum, которая предварительно была объявлена в прототипе:
Чем объявление функции в Си отличается от определения функции в Си?
Когда мы пишем прототип функции, например так:
то мы объявляем функцию.
А когда мы реализуем функцию, т.е. записываем не только заголовок, но и тело функции, например:
то мы определяем функцию.
Оператор return
Оператор return завершает работу функции в C и возвращает результат её работы в точку вызова. Пример:
Эту функцию можно упростить:
здесь оператор return вернёт значение суммы a + b.
Операторов return в одной функции может быть несколько. Пример:
Если в примере значение аргумента a окажется больше двух, то функция вернет ноль (первый случай) и всё, что ниже комментария «// Первый случай;» выполнятся не будет. Если a будет меньше двух, но b будет меньше нуля, то функция завершит свою работу и всё, что ниже комментария «// Второй случай;» выполнятся не будет.
И только если оба предыдущих условия не выполняются, то выполнение программы дойдёт до последнего оператора return и будет возвращена сумма a + b.
Передача аргументов функции по значению
Аргументы можно передавать в функцию C по значению. Пример:
В примере, в функции main, создаём переменную int d = 10. Передаём по значению эту переменную в функцию sum(d). Внутри функции sum значение переменной увеличивается на 5. Но в функции main значение d не изменится, ведь она была передана по значению. Это означает, что было передано значение переменной, а не сама переменная. Об этом говорит и результат работы программы:
т.е. после возврата из функции sum значеие d не изменилось, тогда как внутри функции sum оно менялось.
Передача указателей функции Си
Если в качестве аргумента функции передавать вместо значения переменной указатель на эту переменную, то значение этой переменной может меняться. Для примера берём программу из предыдущего раздела, несколько изменив её:
В этом варианте программы я перешел от передачи аргумента по значению к передаче указателя на переменную. Рассмотрим подробнее этот момент.
В строке
в функцию sum передается не значение переменной d, равное 10-ти, а адрес этой переменной, вот так:
Теперь посмотрим на функцию sum:
Аргументом её является указатель на int. Мы знаем, что указатель — это переменная, значением которой является адрес какого-то объекта. Адрес переменной d отправляем в функцию sum:
Внутри sum указатель int *a разыменовывается. Это позволяет от указателя перейти к самой переменной, на которую и указывает наш указатель. А в нашем случае это переменная d, т.е. выражение
равносильно выражению
Результат: функция sum изменяет значение переменной d:
На этот раз изменяется значение d после возврата из sum, чего не наблюдалось в предыдущм пункте, когда мы передавали аргумент по значению.
C/C++ в Eclipse
Все примеры для этой статьи я сделал в Eclipse. Как работать с C/C++ в Eclipse можно посмотреть здесь. Если вы работаете в другой среде, то примеры и там будут работать.