10.08 Функции
Повторное использование:
Исходного текста — макроопределения: короткий / понятный текст программы заменяется на длинный / непонятный
Кода — подпрограммы: часть программы оформляется отдельно; её можно вызвать из разных мест в программе
Параметризация:
Повторно используемый фрагмент оперирует переменными значениями (например, «решить квадратное уравнение ax² + bx + c = 0»)
Возвращаемое значение:
- Содержательный результат работы подпрограммы должен быть явно доступен после возврата из неё
Вариант: подпрограмма изменяет заданный фрагмент памяти (например, массив), а возвращаемое значение — это код ошибки или иная диагностика.
Кстати, возвращаемое значение main() — зто код ошибки для операционной системы; при этом 0 — это «без ошибок»
Простейшая функция
В Си подпрограммы называются функциями, обычно возвращают значение и не имеют чёткого деления на содержательный результат и диагностику
Пример (мы его уже проходили), когда функция возвращает то ли содержательный результат, то ли диагностику
Почему мы можем использовать и res = scanf(…), и просто scanf(…)?
Сложение двух чисел
- Тип возвращаемого значения
Формальные параметры — локальные переменные
return может встречаться в функции сколько угодно раз
Написать функцию max3() от трёх целочисленных параметров, которая возвращает их максимум
Кстати. ∃ ли в Си возможность выполнить некоторый код не в теле функции
Области видимости
Имена в Си (переменная или функция) становятся видимыми после их описания.
Глобальные переменные — определяются вне функции («после include»)
Статические переменные — определяются в теле функции, существуют постоянно
Локальные переменные — определяются в теле функции, существуют только на период выполнения тела функции
Формальные параметры — локальные переменные, определяются в сигнатуре функции
Классифицировать эти четыре вида как «временные/постоянные» и «видимые/невидимые из других функций»
Пример
Модифицировать функцию сложения так, чтобы можно было узнать, сколько раз её вызывали (с помощью глобальной переменной)
Недостаток простого решения: глобальную переменную можно поменять. Как сделать так, чтобы (как минимум, непосредственно после возврата из функции) в этой глобальной переменной гарантированно лежало количество вызовов add()?
Что выведет эта программа?
Сигнатура
Если функция где-то есть, но к моменту её вызова не описана, необходимо задать её сигнатуру (тип параметров и возвращаемого значения):
Кстати, в include-никах хранятся как раз макросы и сигнатуры, а сами функции — в библиотеках.
С помощью gcc -E найти сигнатуру putchar() (одна строка)
Подсказка: использовать > файл, открыть его в редакторе и поискать
Если вдруг кто знает, что такое grep…
Стек вызовов (введение)
Функции могут вызывать друг друга, при этом изолированные локальные переменные заводятся в каждом вызове
Написать функцию trisquare(x0, y0, x1, y1, x2, y2) вычисления площади треугольника по формуле:
$$ S = \frac{1}{2} | x_0(y_1 - y_2) + x_1(y_2 - y_0) + x_2(y_0 - y_1) | $$
Не забываем про #include <math.h> для fabs()
Написать функцию quadsquare(x0, y0, x1, y1, x2, y2, x3, y3) вычисления площади выпуклого чертырёхугольника
TODO Здесь и далее переформулировать текст из narhoz-chita
http://grep.cs.msu.ru/narhoz-chita.ru/zadachnik/Glava12/index12.htm#z440
Написать функцию get_e(double epsilon) вычисления числа e с заданной точностью по формуле
$$ e = \sum_{n=0}^{\infty} \frac{1}{n!} = 2.71828… $$
Подсказка: не надо писать отдельную функцию факториала! (нажмите «Комментарии» в шапке страницы, чтобы прочитать спойлер)
Функция возвращает значение, когда очередной член ряда < epsilon
Д/З
TODO
http://grep.cs.msu.ru/narhoz-chita.ru/zadachnik/Glava12/index12.htm#z425
http://grep.cs.msu.ru/narhoz-chita.ru/zadachnik/Glava12/index12.htm#z446
Более хитрый ряд (как минимум, с -1ⁿ в числителе, чтобы для сравнения с epsilon нужен был abs())
http://grep.cs.msu.ru/narhoz-chita.ru/zadachnik/Glava12/index12.htm#z445
