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) вычисления площади выпуклого чертырёхугольника
Ввести последовательность целых чисел, признак конца ввода — EOF. Найти и вывести длину максимальной подпоследовательности, состоящей из степеней пятерки. Распознавание, является ли число степенью пятерки, оформить в виде функции.
Написать функцию get_e(double epsilon) вычисления числа e с заданной точностью по формуле
$$ e = \sum_{n=0}^{\infty} \frac{1}{n!} = 2.71828… $$
Подсказка: не надо писать отдельную функцию факториала! (нажмите «Комментарии» в шапке страницы, чтобы прочитать спойлер)
Функция возвращает значение, когда очередной член ряда < epsilon
Д/З
TODO
Во всех задачах считать ввод корректным.
1. Ввести вещественные числа s, t. Рассчитать и вывести значение формулы g(1.2, s) + g(t, s) - g(2*s-1, s*t), где g(a,b)=(a2 + b2)/(a2 + 2*a*b + 3*b2 + 4). Вычисление g(a,b) оформить в виде функции.
3.0 4.0 0.324605
2. Ввести положительное целое n. Выяснить, имеются ли среди чисел n, n+1, ..., 2*n близнецы, т.е. простые числа, разность между которыми равна двум. Если близнецы есть, программа выводит "YES" и наименьшую пару близнецов (формат "YES %d %d"), иначе выводит "NO". Проверку простоты числа оформить в виде функции.
14 YES 17 19
3. Ввести вещественное eps. Рассчитать значение $$\pi$$ при помощи формулы суммы ряда Лейбница (см. ниже). Расчет прекратить, когда очередное слагаемое суммы ряда Лейбница попадает в eps-окрестность нуля; само это слагаемое в сумме учесть. Вывести рассчитанное значение с 16 знаками после запятой (формат "%.16f"). Расчет $$\pi$$ оформить в виде функции get_pi(double epsilon).
$$ \sum_{n=0}^{\infty} \frac{(-1)^n}{2 n+1}=1-\frac{1}{3}+\frac{1}{5}-\frac{1}{7}+\frac{1}{9}-...=\frac{\pi}{4} $$
0.00005 3.1416926435905346
4. Ввести четное число n>2. Проверить для этого числа гипотезу Гольдбаха. Эта гипотеза заключается в том, что каждое четное n, большее двух, представляется в виде суммы двух простых чисел. Если такие два числа существуют, программа выводит "YES" и пару таких чисел (формат "YES %d %d"), иначе выводит "ACHTUNG! GOLDBACH CONJECTURE DISPROVED.". Если пар несколько, выводить ту, в которой разность между числами наибольшая. Проверку простоты числа оформить в виде функции.
