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

Все функции языка С имеет имя и список аргументов (формальных параметров).

Функции могут возвращать значение. Это значение может быть использовано далее в программе. Так как функция может вернуть какое-нибудь значение, то обязательно нужно указать тип данных возвращаемого значения. Если тип не указан, то по умолчанию предполагается, что функция возвращает целое значение (типа int). После имени функции принято ставить круглые скобки (это касается вызова функции её объявления и описания). В этих скобках перечисляются параметры функции, если они есть. Если у функции нет параметров, то при объявлении и при описании функции вместо <список параметров> надо поставить void - пусто.

Основная форма описания (definition) функции имеет вид:

тип <имя функции>(список параметров)
{
тело функции
}

Объявление (прототип) функции имеет вид:

тип <имя функции>(список параметров);

Обратите внимание на то, что при описании функции после заголовка функции
тип <имя функции>(список параметров)
точка с запятой не ставиться, а при объявлении функции точка с запятой ставиться.

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

<имя функции>(параметры);

или

<переменная>=<имя функции>(параметры);

При вызове функции так же ставиться точка с запятой.

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

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

/* Используем свою функцию */

#include <stdio.h>

void main(void) // Точка входа в программу
{
void function1(void); // Объявление функции

function1(); // Вызов функции
}


/* Описание функции */
void function1(void) // Заголовок функции
{ // Начало тела функции

printf("Вызвали функцию\n");

} // Конец тела функции

Результатом работы программы будет строка напечатанная на экране.
Обратите внимание на заголовок в описании функции! После него не ставится точка с запятой.

В теле функции main() мы объявили функцию function1(), затем её вызвали. В теле нашей функции function1() мы вызываем функцию printf(). А где же объявлена функция printf() ? Если вы внимательно посмотрите текст программы, то увидите строку #include <stdio.h>, как говорилось ранее эта строка говорит компилятору, чтобы тот включил в текст программы файл с объявлениями функций стандартного ввода/вывода (standart input/output). Аха! Значит функция printf() объявлена именно там!

Директива препроцессора (preprocessor directive) просто вставляет текстовый файл stdio.h в текст нашей программы. Причем вставляет туда где стоит эта директива. Если вы уберете или закоментируете строку #include <stdio.h>, то программа работать не будет потому что функция printf() не будет объявлена. Компилятор просто выдаст ошибку - Function 'printf' should have a prototype (Функция 'printf' должна иметь прототип).

необходимо обратить внимание на то, что тип возвращаемого значения у нашей функции void (пусто). Это значит, что функция не будет возвращать никакого значения.

Функции возвращающие значение.

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

/* Две наших функции */

#include <stdio.h> // Подключаем файл заголовков функций (их объявлений)

int x; // Объявляем переменную x (глобальная переменная)

void main(void)
{
void function1(void); // Объявляем функцию function1()
int function2(); // function2() будет возвращать значение типа int

x = 10; // Присваиваем переменной x значение 10

printf("До вызова функции function2() x равно %d\n", x);

function1(); // Вызываем функцию function1()
x = function2(); // Вызываем функцию function2()

printf("После вызова функции function2() x равно %d\n", x);
}

/* Описание наших функций */

void function1(void)
{
printf("Сделан вызов первой функции\n");
}

int function2(void)
{
int y; // Объявляем локальную переменную
y = x + 10;

return y; // Возвращаем значение y
}

Теперь давайте посмотрим текст программы. После строки #include <stdio.h> мы объявляем глобальную переменную x. Так как x - глобальная переменная, то она будет видна всем функция нашей программы т.е. этой переменной могут пользоваться все функции.

В теле main() мы объявляем две функции, одна из которых может возвращать значение типа int. Далее мы присваиваем переменной x значение 10, так как x это глобальная переменная, то эта переменная будет видна функции main() т.е. функция main() может использовать эту переменную. После этого присвоения мы выводим значение x на экран.
На экране монитора появится следующая строка - "До вызова функции function2() x равно 10".

Обратите внимание на вызов функции printf() -
printf("До вызова функции function2() x равно %d\n", x);
В строке после сиволов %d стоит символ \n. \n - управляющий символ он означает, что необходимо перейти на новую строку.

Далее мы вызываем функцию function1(). Эта функция просто выводит строку "Сделан вызов первой функции\n" на экран и так как в строке стоит \n, то будет осуществлен переход на новую строку.

В следующей строке x = function2(); переменная x принимает значение которое вернет функция function2(). Посмотрите на описание функции function2(). В теле этой функции мы объявляем переменную y, а дальше переменной y мы присваиваем значение переменной x + 10. Так как x - глобальная переменная (она видна для функции function2) все будет работать.

Далее идет строка return y; с помощью оператора return мы возвращаем значение переменной y. Запомните, что если функция возвращает значение, то в теле этой функции обязательно должен присутствовать оператор return (он может быть и не один). Ну так вот с помощью оператора return мы возвращаем значение локальной переменной y в вызывающую функцию main().

Теперь посмотрим тело функции main() Следующей строкой после x = function2(); является строка printf("После вызова функции function2() x равно %d\n", x); которая выводи значение измененной переменной x;
На экране появится строка - "После вызова функции function2() x равно 20".
Функции с параметрами.

Функции языка С могут иметь параметры. Эти параметры передаются в функцию и там обрабатываются. Ещё раз покажем основную форму описания функции

тип <имя функции>(список параметров)
{
тело функции
}

В списке параметров для каждого параметра должен быть указан тип.
Пример правильного списка параметров:
function(int x, char a, float z)
Пример неправильного списка параметров:
function(int x, a, float z)

Давайте рассмотрим все это на примере. Пусть у нас будет функция у которой присутствует один параметр x. Функция будет возвращать квадрат значения x.

int square(int x)
{
x = x * x; // Символ * это операция умножения
return x;
}

Теперь давайте рассмотри пример функции, которая будет выводить значение переменной z типа float на экран.

void myout(float z) // Переменная z является формальным параметром.
{
printf("Z=%f", z); // %f - означает, что выводится число с плавающей точкой
}

Формальные и фактические параметры

Формальные параметры - это параметры которые мы объявляем в заголовке функции при описании.

Фактические параметры - это параметры которые мы подставляем при вызове функции.

void myfunc(int x); // Объявление функции
void main(void)
{
int a;
a=5;
myfunc(a); // a- фактический параметр
}

// Описание функции
void myfunc(int x) // x - формальный параметр
{
x = x + 10;
printf("Вывод x = %d",x);
}

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


   EasyEDA:  бесплатный редактор схем

   ✓ Создание схем
   ✓ Возможность симуляции
   ✓ Быстрое создание печатных плат
   ✓ Интуитивно понятный интерфейс

   Нарисуй свою схему прямо сейчас!
   Изготовление печатных плат   https://easyeda.com/order
авторизация
Логин:
Пароль:
Комментарии
Сетевой диммер 220V на микроконтроллере
09.12.2016 - vakulyuk:
Спасибо) Я принцип действия понял, а вот откуда взялась именно цифра 195 не поня...
Сетевой диммер 220V на микроконтроллере
09.12.2016 - exersizze:
pchela5, ну так это в военное, а у нас в мирное время все примерно)) Наше...
Сетевой диммер 220V на микроконтроллере
09.12.2016 - pchela5:
> Полуволна в нашей электросети по времени длится примерно 10 мс

...
Сетевой диммер 220V на микроконтроллере
09.12.2016 - exersizze:
Чтобы понять откуда взялась цифра 195 надо сначала въехать в принцип работы: ког...
Сетевой диммер 220V на микроконтроллере
09.12.2016 - vakulyuk:
А почему минимальный накал при 195? Насколько минимум можно занизить Wt?
Когда не хватает ног. Часть 2. Сдвиговый регистр 74HC595
08.12.2016 - exersizze:
yorx выдалось немного свободного времени, проверил в симуляторе. Проблема...
Логгер температуры 2.0
05.12.2016 - Evgeny6873:
Хотел повторить схему и долго ждал дисплей, два раза заказывал с Китая, пришел. ...
Когда не хватает ног. Часть 2. Сдвиговый регистр 74HC595
01.12.2016 - yorx:
Доброго времени суток, exersizze попробовал Ваш код все равно не работает как на...
Помни об усадке!
30.11.2016 - pchela5:
Автомобильные никакие не лезут?