\documentclass[a5paper,twoside]{article} \include{formatting} \title{Очередное введение в\\язык программирования C} \begin{document} \maketitle \thispagestyle{empty} \newpage \tableofcontents \newpage % 01 intro \include{sections/01-intro} % 02 basics \include{sections/02-basics} % 03 io \include{sections/03-io} % 04 variables \include{sections/04-variables} % 05 conditions \include{sections/05-conditions} % 06 cycles \include{sections/06-cycles} \section{Функции} Функция - это такая обособленная часть кода, которую можно выполнять любое количество раз. У функций обязательно в таком порядке должны быть описаны: тип возвращаемого значения, название, аргументы и так называемое тело, то есть собственно исполняемый код. Рассмотрим более детально функцию \code{int main (int argc, char *argv[])}: \code{int} - это \textit{тип возвращаемого значения}, то есть на том месте, откуда будет вызвана эта функция, в результате её работы по выполнении оператора \code{return;}, появится некое целое число. Возвращаемые значения могут быть любых типов. В случае же когда функция не должна возвращать результат своей работы, или никакого возвращаемого результата не предполагается, указывается ключевое слово \code{void} (англ. - пустота). То есть на месте вызова функции в результате её выполнения ничего не появится. Оператор \code{return;} обязателен для не-void функций, а в \code{void} функциях может присутствовать или нет, но никогда не содержит возвращаемого значения. \code{main} - это \textit{название функции}. Функция именно с таким названием, написанным с маленькой буквы, всегда является точкой входа в программу (\hyperref[text:main]{\ref{text:main}}). Операционная система ищет именно эту функцию, когда получает команду на выполнение программы. \frm{Названия функций в рамках одной программы не должны повторяться и не должны начинаться с цифр или спецсимволов, также, как и названия переменных (\hyperref[text:naming]{\ref{text:naming}}) никаких других ограничений на название функций не накладывается.} Конструкция в круглых скобках \code{(int argc, char *argv[])} - это \textit{аргументы функции}. Аргументы функции - это такие переменные, которые создаются при вызове функции и существуют только внутри неё. С их помощью можно передать в функцию какие-то параметры и исходные данные для работы. Аргументы пишутся в круглых скобках сразу после названия функции. В случае если функция не принимает аргументов необходимо поставить после названия пустые круглые скобки. Весь код, содержащийся в фигурных скобках после аргументов функции называется \textit{телом функции}. Это те операторы и команды, которые будут последовательно выполнены при вызове функции. В теле функции мы можем \textbf{вызывать} другие функции, но никогда не можем создавать в теле функции другие функции. Никаких других ограничений на написание тела функции язык не накладывает. \begin{verbatim} ТипВозвращаемогоЗначения Имя (СписокАргументов) { ТелоФункции return ВозвращаемоеЗначение; } \end{verbatim} % \begin{lstlisting}[language=C,style=CCodeStyle] % void somefunction() { // <-- это функция % // полезные действия % } % int main (int argc, const char* argv[]) { % // больше полезных действий % somefunction(); // <-- это вызов функции % return 0; % } % \end{lstlisting} Функции принято разделять на проверяющие, считающие и выводящие, и каждая из вышеописанных функций не должна нести дополнительной нагрузки. То есть, функция не должна знать откуда в программе появились её аргументы, и где будет использован результат её работы. Для примера опишем функцию суммирующую два числа. в качестве аргументов она будет принимать целые числа и возвращать целочисленный результат. Обратите внимание что функция не знает откуда взялись эти числа, мы можем их считать с консоли, можем задать в виде констант или получить в результате работы какой то другой функции. Внутри функции main мы вызываем нашу функцию sum суммирующую два числа и передаем в качестве аргументов эти числа. % int sum(int x, int y) { % int result = x + y; % return result; % } % int main (int argc, const char* argv[]) { % sum(50, 60); % return 0; % } % Обратите внимание, что в качестве аргументов мы можем передавать константные значения, а также переменные. Значения переменных мы можем получить например из консоли, либо в результате выполнения какой-нибудь другой функции. % int main (int argc, const char* argv[]) { % int a; % scanf(“%d, &a”); % sum(50, a); % return 0; % } % Как уже было сказано - аргументы - это переменные, которые хранят в себе некоторые параметры вызова функции. Аргументы позволяют использовать одни и те же функции с разными исходными данными. Приглядимся повнимательнее к хорошо знакомой нам функции printf(). Строка, которую мы пишем в круглых скобках в двойных кавычках это и есть аргумент функции. То есть мы знаем, что функция умеет выводить на экран строки. Как именно - нам нет дела, а какие именно строки - мы указываем в качестве аргумента. % Функция printf() примечательна еще и тем, что она может принимать в себя нефиксированное количество аргументов. Описание работы таких функций, а также их написание выходит далеко за пределы основ языка, нам важно помнить что мы можем это использовать. В аргументе функции printf() мы можем написать заполнитель соответствующего типа и вызвать нашу функцию sum. % printf(“HelloWorld!”); % printf(“%d”, sum(50, a)); % Теперь мы без проблем можем оформить уже существующие у нас программы в виде функций. Например, оформим в виде функций программу проверки простоты числа. % Для этого опишем функцию которая возвращает целое число, назовем ее isPrime, в качестве аргумента она принимает целое число, назовем его number. Найдем из предыдущих занятий программу определения простоты числа и скопируем в тело функции. % Внесем небольшие правки, уберем вывод т.к. это проверяющая функция, вывод оставим для основной части. И допишем если делителей 2 то число простое, возвращаем 1. Если же делителей больше – число не простое, возвращаем 0. % Такой вывод можно записать и другим способом, return (d == 2) – это выражение в случае истины вернет 1 в случае лжи 0. % Можно воспользоваться тернарным оператором, т.е. написать % return (d == 2) ? 1 : 0 – если условие в скобках истинно вернется 1, ложно – 0.; % Выйти из функции мы можем на любом этапе ее выполнения, например если делителей уже 3, то мы можем вернуть 0. % int isPrime(int number){ % int d = 0, i = 1; % while(i <= number){ % if(number % i++ ==0) % d++; % else % continue; % if (d == 3) break; % } % //if (d == 2) return 1; % //else return 0; % return (d == 2) % //return (d == 2) ? 1 : 0; % } % if (d == 3) return 0; % Немного подправим вывод, внесем в него вызов функции isPrime и объявим переменную int num, которую будем передавать в качестве аргумента в функцию isPrime. % Запустим нашу программу и убедимся что все работает – число 71 действительно является простым. % Теперь мы можем написать программы любой сложности, содержащие функции isPrime. sum. О том, что мы работаем с консолью, в нашем случае должна знать только функция main, поэтому ввод значений и вывод на экран мы оставим в ней, а подсчёты значений положим в функции. % int main (int argc, const char* argv[]) { % int a; % scanf(“%d, &a”); % printf(“%d”, sum(50, a)); % int num = 71; % printf(“Введенное число %d %s является простым \n”, number, isPrime(num) ? “” : “не”); % return 0; % } % Пришло время поговорить про прототипы. % Зачастую возникают ситуации, когда функция не описана до точки входа в программу, или вовсе лежит в другом файле. В этом случае мы должны сообщить компилятору, что такую функцию придётся дополнительно поискать. Для этого необходимо указать всю информацию о функции, кроме её тела. Такой оператор называется прототип функции. % Опишем прототип функции isPrime, описав сигнатуру этой функции. % int isPrime(int number); % И пара слов о заголовочных файлах. Заголовочные файлы это мощный инструмент модульной разработки. Мы уже неоднократно видели подключение заголовочного файла stdio.h, давайте посмотрим, что же скрывает и как именно работает эта строка. Обнаружив данный файл на диске мы видим, что в нём содержатся другие подключения библиотек, директивы препроцессора (о которых более подробно мы будем говорить на следующих занятиях) и прототипы функций (например, так часто используемой нами % printf()). (Где-то вот здесь… на 259 строке) % // Здесь показ содержимого stdio.h \end{document}