Все о функциях в языке Си

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

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

Объявление функции

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

Пример объявления функции с возвратом и без:

int Func_1(){ // функция которая возвращает литерал типа int

// операторы

return int; // оператор возврата некого значения int

}

 

void Func_2(){ // функция, которая ничего не возвращает, но выполняет определенные действия

// операторы

}

Пояснение:

  1. int — может быть любой тип данных, который ставится перед именем функции и говорит о том, какое значение функция возвращает.
  2. void  — ставится перед именем функции и говорит о том, что функция ничего не возвращает.
  3. Func_1, Func_2 — произвольное имя функции, по которому она вызывается. Также это ссылка на область памяти, где находится блок операторов функции.
  4. () — скобки служат для параметров (аргументов), функции бывают с параметрами и без. Также скобки используют для вызова функции.
  5. { // операторы } — блок операторов, который выполняется при вызове функции.
  6. return — оператор, указывающий на возврат определенного результата функции.

Пример использования функции с возвратом:

int func(){

int x = 5;

int y = 5;

return x+y;

}

 

func(); // так выглядит вызов функции — сложение выполнилось, вернулась сумма

printf(func()); // Выведет 10

 

int a = func(); // сохраним в переменную результат вызова функции

printf(a); // выведет 10 как значение переменной, в которую был сохранен результат выполнения функции

Пример использования функции без возврата:

void write_message(){

printf(«Hello World! «);

printf(«Hello everyone! «);

printf(«I glad to see you all!»);

}

 

write_message();

// Вывод: Hello World! Hello everyone! I glad to see you all!

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

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

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

printf(«Hello World! «);

printf(«Hello everyone! «);

printf(«I glad to see you all!»);

 

printf(«Hello World! «);

printf(«Hello everyone! «);

printf(«I glad to see you all!»);

 

printf(«Hello World! «);

printf(«Hello everyone! «);

printf(«I glad to see you all!»);

Здесь мы повторили одни и те-же действия несколько раз. Ведь мало кто захочет, постоянно повторять написание этих операторов в нужном участке кода.

Теперь запишем предыдущий пример в виде функции:

void write_message(){

printf(«Hello World! «);

printf(«Hello everyone! «);

printf(«I glad to see you all!»);

}

 

write_message();

write_message();

write_message();

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

Здесь при вызове функции, write_message является ссылкой на инициализацию функции, которую мы осуществили выше вызова. Оператор () осуществляет выполнение блока команд инициализированной функции. Каждый раз как мы вызываем функцию, выполняются команды в описанном блоке.

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

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

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

int/void func(int x, int y){ операторы, return}

В скобках определены две переменные int x и int y. В инициализации функции описывается как будут использоваться эти параметры. При вызове функции параметры получают любое значение в соответствии со своим типом.

Пример:

int func(int x, int y){ // Объявили функцию с параметрам — имена параметров могут быть произвольными

int z = x+y; // используем имена параметров в теле функции —  в нашем случае будет произведено сложение значений в параметре

return z;

}

 

func(5, 5); // параметр x = 5, параметр y = 5, функция сложила значения этих параметров и вернула 10

func(34, 112); // в следующем вызове можно установить новые значения параметров. Возвращенный результат равен 146

func(10, 5); // 15

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

Пример со строкой без возврата:

void fun_str(String a, String c){

String h = a + c + » Yes, That is right!»;

printf(h);

}

 

fun_str(«I am», «smartest man.»); // Вывод: I am smartest man. Yes, That is right!

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

Локальные и глобальные переменные

Локальные переменные обладают областью видимости только внутри функции. Глобальные переменные объявляются и инициализируется вне функции, но в пределах главной функции Main. Если глобальные переменные передать в функцию в качестве аргументов, то их изменение будет проведено только в рамках функции. Значения глобальных переменных останутся не измененными.

Пример:

int a = 50;  // a и b — глобальные переменные

int b = 100;

 

int func(int x, int y, int c){

x +=20;  // изменяем локальные переменные

y+=20;

z = x + y + c;

return z;

}

 

func(a, b, 30); //  результат будет равен 210 — в качестве параметров вставили глобальные переменные

 

printf(a);  // 50 — глобальная а осталась неизмененная

printf(b); // 100 — глобальная b осталась с прежним значением

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

Функции могут быть выполнены и объявлены в теле другой функции

Вложенные функции можно объявить и вызвать в теле другой функции.

Пример:

void fun(int x){

void f(){  // объявление вложенной функции

printf(x);

}

 

if(x>5) f(); // если условие верно, то вызов внутренней функции

else printf(«Wrong value»); // иначе — вывод сообщения

}

 

fun(6); // Wrong value

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

Рекурсивные функции

Рекурсия — функция, которая вызывает самому себя. Это функциональный вид цикла, только осуществляемый за счет функции.

Пример:

int recursion(int a)

{

if (a == 1)

{

return 1;

}

else

{

return n * recursion(n — 1);

}

}

 

recursion(6) // вернет 720

Что здесь произошло:

Мы установили параметр а = 6. Если a равно 1, то выход из функции. В ином случае: возврат (значение параметра умножить на вызов функции, где параметр -1).

Ключевое значение здесь играет n * recursion(n-1): 6 * выполнить инструкции еще раз с параметром 6 — 1. Здесь n перемножается по цепочке: 6*5*4*3*2 = 720. Когда n = 1, то последнее умножение прерывается и возвращается результат из предыдущего звена. В нашем случае, функция recursion повторила свое выполнение 4 раза, на 5-м процесс прервался.

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

Но, рекурсивная функция экономичнее — она позволяет устанавливать любые параметры, а ее вызов занимает всего одну строку. Это достаточно удобно, нежели писать несколько циклов. Тем не менее, если необходимо выполнить цепочку расчетов лишь один раз, то рекомендуется все-таки использовать циклы, ведь они удобнее для этих целей. Ошибка в рекурсии может заставить программиста искать ее причину и решение долгое время, когда в цикле данный процесс обычно протекает быстрее ввиду более красивого синтаксиса.

Подводя итоги

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

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

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

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

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *