- Определять и вызывать функцию с типом результата, именем и параметрами
- Объяснять, зачем нужен прототип функции
- Понимать, что параметры передаются по значению (как копии)
- Писать простую рекурсивную функцию с базовым случаем
Две функции ты уже хорошо знаешь: main, с которой начинается любая программа, и printf, которая выводит текст. Большие программы состоят из сотен маленьких функций: одна считает баллы, другая печатает таблицу, третья читает файл. Каждая функция выполняет одну задачу, пишется один раз и вызывается сколько угодно раз. А найденную ошибку достаточно исправить в одном месте.
Как устроена функция
- Тип результата — тип значения, которое возвращает функция (
int,double…). Для функции, которая ничего не возвращает, пишутvoid. - Имя — название, которое говорит, что делает функция, например
maxилиprint_line. - Параметры — входные значения в скобках вместе с их типами:
(int a, int b). Если параметров нет, пишут(void). - Тело — код между фигурными скобками.
returnвозвращает результат в место вызова и сразу завершает функцию.
Компилятор C читает файл сверху вниз. Если main вызывает функцию раньше, чем она определена, компилятор должен знать о ней заранее. Для этого в начале файла пишут прототип — заголовок функции с ; в конце.
Объявление, которое сообщает имя функции, тип результата и типы параметров, но не содержит тела. Например: int max(int a, int b);. Заголовочные файлы вроде stdio.h состоят в основном из прототипов.
#include <stdio.h>
int max(int a, int b);
double average(int a, int b, int c);
int main(void) {
printf("Max: %d\n", max(12, 31));
printf("Average: %.2f\n", average(5, 4, 4));
return 0;
}
int max(int a, int b) {
if (a > b) {
return a;
}
return b;
}
double average(int a, int b, int c) {
return (a + b + c) / 3.0;
}Max: 31 Average: 4.33
main может стоять в начале файла. Деление на 3.0 даёт дробный результат: 13 / 3 ≈ 4,33.Функции void и передача по значению
Некоторые функции ничего не возвращают, а просто выполняют работу, например рисуют линию на экране. Их тип результата — void. Программа ниже показывает и очень важное правило: в C аргументы передаются по значению. Функция получает не саму переменную, а её копию, поэтому изменение параметра не влияет на переменную вызывающей стороны.
#include <stdio.h>
void print_line(int n) {
for (int i = 0; i < n; i++) {
printf("-");
}
printf("\n");
}
void try_to_change(int x) {
x = 100;
printf("Inside: x = %d\n", x);
}
int main(void) {
int x = 5;
print_line(12);
try_to_change(x);
printf("Outside: x = %d\n", x);
print_line(12);
return 0;
}------------ Inside: x = 100 Outside: x = 5 ------------
x внутри функции — копия: она стала равна 100, а x в main осталась равной 5.Не каждую функцию нужно писать самому. В заголовке math.h стандартной библиотеки есть готовые математические функции: sqrt (квадратный корень), pow (степень), fabs (модуль) и другие. Они принимают и возвращают double. В Linux при компиляции такой программы может понадобиться добавить в конце -lm.
#include <stdio.h>
#include <math.h>
int main(void) {
printf("%.2f\n", sqrt(16.0));
printf("%.0f\n", pow(2, 10));
printf("%.1f\n", fabs(-7.5));
return 0;
}4.00 1024 7.5
Рекурсия: функция, вызывающая саму себя
Функция может вызывать и саму себя — это называется рекурсией. У рекурсивной функции две части: базовый случай, который решает задачу сразу, и рекурсивный шаг, который немного уменьшает задачу и снова вызывает функцию. Классический пример — факториал: n! = n · (n − 1)!, а базовый случай — 1! = 1.
#include <stdio.h>
long long factorial(int n) {
if (n <= 1) {
return 1;
}
return n * factorial(n - 1);
}
int main(void) {
for (int i = 1; i <= 5; i++) {
printf("%d! = %lld\n", i, factorial(i));
}
printf("20! = %lld\n", factorial(20));
return 0;
}1! = 1 2! = 2 3! = 6 4! = 24 5! = 120 20! = 2432902008176640000
long long (%lld) — 20! уже не помещается в int.Проследи вызов factorial(4) шаг за шагом.
Показать решениеСкрыть решение
factorial(3) = 3 · factorial(2)
factorial(2) = 2 · factorial(1)
factorial(1) = 1 — базовый случай, вызовы прекращаются.
Теперь результаты возвращаются обратно: 2 · 1 = 2, 3 · 2 = 6, 4 · 6 = 24.
Главное
- У функции есть тип результата, имя, параметры и тело;
returnвозвращает результат. - Если функция вызывается до своего определения, в начале файла нужен её прототип.
- Функция, которая ничего не возвращает, имеет тип
void. - В C аргументы передаются по значению: функция работает с копией.
- У рекурсивной функции обязательно должен быть базовый случай, иначе стек переполнится.
Проверь себя
Вопросов: 10. Каждый правильный ответ приносит XP.