Объявление и определение функций
Язык программирования C, как и многие другие языки, предоставляет возможность создавать программы, которые состоят из большого числа функций и одного
или нескольких файлов исходного кода. До настоящего момента мы работали только с функцией main()
, которая является основной в программе на C,
так как выполнение всегда начинается с нее. Тем не менее, вы можете создавать и другие функции, которые возможно вызвать из main()
или любой
другой функции. На этом уроке мы сосредоточимся на однофайловых программах с более чем одной функцией.
Изучение функций включает в себя понимание различий между локальными и глобальными переменными. В языке C глобальные переменные (они же внешние) объявляются за пределами функций. Они упрощают обмен данными между функциями, но чрезмерное их использование может спутать весь код программы. Локальные переменные называются автоматическими и действуют только внутри той функции, где были объявлены. Параметры функции также выступают в роли локальных переменных.
Структура программы на языке C, состоящей из нескольких функций, может варьироваться. Поскольку выполнение начинается с main()
, этой
функции должны быть известны спецификации (имена, количество и типы параметров, тип возвращаемого значения) всех функций, которые она вызывает.
Это означает, что объявление функций должно произойти перед их вызовом. Однако определение функции может идти как перед, так и после main()
.
Рассмотрим такую программу:
В этом случае функция median()
объявляется в начале программы. Указываются возвращаемый ею тип (float
), а также количество и
типы параметров (int a, int b
). Обратите внимание: при объявлении переменных можно их группировать, например, int a, b;
, но в
случае с параметрами функции каждый параметр должен иметь свой тип: (int a, int b)
.
Затем идет функция main()
, а следом — определение median()
. Имена параметров в объявлении функции не имеют значения (их
можно вообще не указывать, например, float median (int, int);
). При определении функции имена параметров могут отличаться, однако количество
и типы должны совпадать с объявлением.
Функция median()
возвращает результат типа float
. Оператор return
выполняет возврат с результатом выполнения
выражения, следующее за которым выполнение функции прекращается, даже если в теле функции имеется еще код. median()
вычисляет
среднее значение двух целых чисел. В выражении (float) (n1 + n2) / 2
сначала складываются два целых числа, после чего результат превращается
в вещественное число и делится на 2. В противном случае деление было бы целочисленным, и дробная часть обрезалась бы.
В main()
функция median()
заново вызывается трижды. Результат вызова не обязательно сохранять в переменной.
Эту программу можно бы было написать и так:
Хотя это и экономит строку кода, основная логика программы в main()
выносится ниже, что осложняет чтение. Поэтому предпочтительнее первый вариант.
Разработайте функцию, которая возводит в куб переданное ей число. Проверьте ее работу с различными значениями аргументов.
Статические переменные
В языке C имеются так называемые статические переменные, которые могут выступать как глобальными, так и локальными. Их декларация происходит с
использованием ключевого слова static
.
Статические переменные, которые объявлены как внешние, в отличие от обычных глобальных, становятся недоступными из других файлов, если программа состоит из нескольких файлов. Они глобальны только в рамках функций текущего файла. Это помогает сокрытию данных с целью избежания несанкционированных изменений.
Статические переменные, объявленные внутри функции, имеют ту же зону видимости, что и автоматические переменные. Они отличаются тем, что их значения сохраняются между вызовами функций:
Результат:
В этом примере функция hello()
ведет учет своих вызовов.
Передача аргументов по ссылке
В первом примере этого урока аргументы передавались функции по значению. Это значит, что при вызове функции ей фактически передаются
копии значений переменных. Сами переменные не изменяются, так как их изменения в вызываемой функции происходят с копиями. Из этого следует,
что изменения, произведенные над параметрами функции, не воздействуют на переменные из функции median()
, даже если те изменяются.
Однако возможно организовать изменения локальных переменных одной функции через другую функцию, передавая в нее адрес переменной или ее указатель. В действительности это также передача копии значения — конкретно, значения адреса участка памяти. На одну область памяти можно создать множество ссылок и использовать их для изменения значений. Пример:
Функция multi()
не возвращает никакого значения, что указывается ключевым словом void
. Эта функция принимает адрес, который
присваивается локальной переменной-указателю, и целое число. Изменение значения происходит по адресу, который содержится в указателе, и это на самом деле
адрес переменной x
из функции main()
, что позволяет изменить ее значение.
При вызове multi()
из main()
первым параметром обязательно передается адрес, а не само значение. Таким образом, вызов
multi(x, 786)
вызвал бы ошибку, а вот multi(&x, 786)
работает корректно, так как передается адрес переменной x
.
При этом в main()
можно объявить указатель и передавать именно его (например, переменная p
содержит адрес):
Также важно знать, что функция способна возвращать адрес.
Понимание механизма передачи аргументов по ссылке пригодится, когда речь пойдет о массивах и строках. Хотя при работе с простыми типами данных лучше возвращать значение из функции, чем менять локальные переменные одной функции с помощью другой, так как функции должны оставаться максимально независимыми друг от друга.
- Переделайте код первого примера этого урока так, чтобы он использовал указатель; а код примера с функцией
multi()
избавьте от указателей. - Создайте программу, в которой, помимо функции
main()
, будут еще две функции: одна будет вычислять факториал переданного числа, а другая — находить n-й элемент ряда Фибоначчи (где n — параметр функции). Вызовите эти функции с разными аргументами. - Разработайте программу, в которой из функции
main()
будет вызываться другая функция, а затем из нее — еще одна функция.