diff --git a/build/main.pdf b/build/main.pdf index bd9cdbd..18c5313 100644 Binary files a/build/main.pdf and b/build/main.pdf differ diff --git a/main.tex b/main.tex index 65bb486..0edded2 100644 --- a/main.tex +++ b/main.tex @@ -24,9 +24,11 @@ \section{Функции} \subsection{Понятие функции, параметры и аргументы} -Функция - это такая обособленная часть кода, которую можно выполнять любое количество раз. У функций обязательно в таком порядке должны быть описаны: тип возвращаемого значения, название, параметры и так называемое тело, т есть собственно исполняемый код. Рассмотрим более детально функцию \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{вызывать} другие функции, но \textbf{никогда не можем создавать в теле функции другие функции}. Никаких других ограничений на написание тела функции язык не накладывает. +Функция - это такая обособленная часть кода, которую можно выполнять любое количество раз. У функций обязательно в таком порядке должны быть описаны: тип возвращаемого значения, название, параметры и так называемое тело, т есть собственно исполняемый код. Рассмотрим более детально функцию \code{int main (int argc, char *argv[])}: \code{int} - это \textit{тип возвращаемого значения}, то есть на том месте, откуда будет вызвана эта функция, в результате её работы по выполнении оператора \code{return;}, появится некое целое число. Возвращаемые значения могут быть любых типов. В случае же когда функция не должна возвращать результат своей работы, или никакого возвращаемого результата не предполагается, указывается ключевое слово \code{void} (англ. - пустота). То есть на месте вызова функции, в результате её выполнения, не появится никакого значения (обычно, таким значением бывает rvalue). Оператор \code{return;} обязателен для не-void функций, а в \code{void} функциях может присутствовать или нет, но никогда не содержит возвращаемого значения. \code{main} - это \textit{название функции}. Функция именно с таким названием, написанным с маленькой буквы, всегда является точкой входа в программу (\hyperref[text:main]{\ref{text:main}}). Операционная система ищет именно эту функцию, когда получает команду на выполнение программы. +\frm{Названия функций в рамках одной программы не должны повторяться и не должны начинаться с цифр или спецсимволов, также, как и названия переменных (см стр. \hyperref[text:naming]{\pageref{text:naming}}) никаких других ограничений на название функций не накладывается.} +Конструкция в круглых скобках \code{(int argc, char *argv[])} - это \textit{параметры функции}. Параметры функции - это такие переменные, которые создаются при вызове функции и существуют только внутри неё. С их помощью можно передать в функцию какие-то аргументы и исходные данные для работы. Параметры пишутся в круглых скобках сразу после названия функции. В случае если функция не принимает параметров необходимо поставить после названия пустые круглые скобки (\code{()}). Весь код, содержащийся в фигурных скобках после параметров функции называется \textit{телом функции}. Это те операторы и команды, которые будут последовательно выполнены при вызове функции. В теле функции мы можем \textbf{вызывать} другие функции, но \textbf{никогда не можем объявлять, описывать или создавать в теле функции другие функции}. Никаких других ограничений на написание тела функции язык не накладывает. Таким образом, общий вид функции имеет следующий вид: + +\begin{figure}[h!] \begin{verbatim} ТипВозвращаемогоЗначения Имя (СписокАргументов) { @@ -34,29 +36,35 @@ return ВозвращаемоеЗначение; } \end{verbatim} -Далее приведём небольшой пример, который призван продемонстрировать, как выглядит простейшее \textit{объявление} и \textit{описпание} функций (function declaration and definition). -\begin{lstlisting}[language=C,style=CCodeStyle] -void somefunction() { // <-- this is a function - printf("some function\n"); - // some useful things -} - -int anotherFunction() { - printf("another function\n"); - // more useful things happened - return 10; -} +\end{figure} +Далее приведём небольшой пример, который призван продемонстрировать, как выглядит простейшее \textit{объявление} и \textit{описпание} функций (function declaration and definition), а также их вызов из функции \code{int main (int argc, char *argv[])}. -int main (int argc, const char* argv[]) { - printf("main function\n"); - // more useful things - somefunction(); // <-- this is invocation - int x = anotherFunction(); - printf("x = %d\n", 10); - return 0; -} -\end{lstlisting} -Так, на тринадцатой строке кода выше мы видим, что \textbf{вернувшееся} из функции, объявленной на пятой строке целое число \code{10} будет присвоено переменной \code{x}. +\begin{figure}[h!] + \begin{lstlisting}[language=C,style=CCodeStyle] + void somefunction() { // <-- this is a function + printf("some function\n"); + // some useful things + } + + int anotherFunction() { + printf("another function\n"); + // more useful things happened + return 10; + } + + int main (int argc, const char* argv[]) { + printf("main function\n"); + // more useful things + somefunction(); // <-- this is invocation + int x = anotherFunction(); + printf("x = %d\n", 10); + return 0; + } + \end{lstlisting} +\end{figure} +Так, на шестнадцатой строке кода выше мы видим, что \textbf{вернувшееся} из функции, объявленной на шестой строке целое число \code{10} будет присвоено переменной \code{x} и выведено в терминал семнадцатой строкой. + +\begin{figure}[h!] \begin{verbatim} $ ./program main function @@ -65,29 +73,36 @@ another function x = 10 $ \end{verbatim} +\end{figure} Функции принято разделять на проверяющие, считающие и выводящие, и каждая из вышеописанных функций не должна нести дополнительной нагрузки. То есть, функция не должна знать откуда в программе появились её параметры, и где будет использован результат её работы. То есть сам язык таких ограничений не накладывает, но такой подход к написанию функций делает их значительно более гибкими и даёт им возможность быть переиспользованными. Без применения такого подхода было бы невозможно писать абстрактные библиотеки и фреймворки. \frm{\textbf{Параметры функции} - это те переменные, которые указываются в круглых скобках при определении или описании функции. Параметры функции существуют как локальные переменные в кодовом блоке тела функции.\textbf{Аргументы функции} - это те значения переменных или литералов, которые указываются в круглых скобках при выхове функции.} -Для примера опишем функцию, суммирующую два числа. Для простоты, в качестве аргументов она будет принимать целые числа и возвращать целочисленный результат. Обратите внимание что функция не <<знает>> откуда взялись эти числа, мы можем их прочитать из консоли, можем задать в виде констант или получить в результате работы какой-то другой функции. Внутри функции \code{int main (int argc, char *argv[])} мы вызываем нашу функцию \code{sum(int x, int y)} суммирующую два числа и передаём в качестве аргументов эти числа. -\begin{lstlisting}[language=C,style=CCodeStyle] -int sum(int x, int y) { - int result = x + y; - return result; -} +Для примера опишем функцию, суммирующую два числа. Для простоты, в качестве аргументов она будет принимать целые числа и возвращать целочисленный результат. Обратите внимание что функция не <<знает>> откуда взялись эти числа, мы можем их прочитать из консоли, можем задать в виде констант или получить в результате работы какой-то другой функции. Внутри функции \code{int main (int argc, char *argv[])} программа вызывает нашу функцию \code{sum(int x, int y)} суммирующую два числа и передаём в качестве аргументов эти числа. -int main (int argc, const char* argv[]) { - int a; - scanf("%d", &a); - int x = sum(50, a); - printf("x = %d\n", 10); - return 0; -} -\end{lstlisting} +\begin{figure}[h!] + \begin{lstlisting}[language=C,style=CCodeStyle] + int sum(int x, int y) { + int result = x + y; + return result; + } + + int main (int argc, const char* argv[]) { + int a; + scanf("%d", &a); + int x = sum(50, a); + printf("x = %d\n", 10); + return 0; + } + \end{lstlisting} +\end{figure} Обратите внимание, что в качестве аргументов мы можем передавать константные значения, а также переменные. Значения переменных мы можем получить например из консоли, либо в результате выполнения какой-нибудь другой функции. + +\begin{figure}[h!] \begin{verbatim} $ ./program x = 110 $ \end{verbatim} +\end{figure} Как уже было сказано, параметры - это переменные, которые хранят в себе некоторые начальные значения вызова функции. Параметризация позволяет использовать одни и те же функции с разными исходными данными. Приглядимся повнимательнее к хорошо знакомой нам функции \code{printf();}. Строка, которую мы пишем в круглых скобках в двойных кавычках - это аргумент функции. То есть мы знаем, что функция умеет выводить на экран строки, как именно - нам нет дела, а какие именно строки - мы указываем в качестве аргумента. Функция \code{printf();} примечательна еще и тем, что она может принимать в себя нефиксированное количество аргументов. Описание работы таких функций, а также их написание выходит далеко за пределы основ языка, нам важно помнить что мы можем это использовать. В аргументе функции \code{printf()} мы можем написать заполнитель соответствующего типа и, например, вызвать нашу функцию \code{sum}. \subsection{Оформление функций. Понятие рефакторинга} Теперь мы без проблем можем оформить уже существующие у нас программы в виде функций. Например, оформим в виде функции программу проверки простоты числа. Для этого опишем функцию которая возвращает целое число, назовем ее \code{isPrime()}, в качестве параметра она будет принимать целое число, назовем его \code{number}. Найдем в предыдущих разделах (стр. \hyperref[code:isPrime]{\pageref{code:isPrime}}) программу определения простоты числа и скопируем в тело функции. Внесем небольшие правки, уберем вывод так как это будет, можно сказать, классическая проверяющая функция, вывод оставим для функции \code{int main (int argc, char *argv[])}, пусть о наличии у нас терминала <<знает>> только она. @@ -135,22 +150,22 @@ int main(int argc, char *argv[]) { } \end{lstlisting} \end{multicols} +Немного подправив вывод, внесем в него вызов функции \code{isPrime()} и объявим переменную \code{int num}, которую будем передавать в качестве аргумента в функцию \code{isPrime()}. Запустим нашу программу и убедимся что все работает – число 71 действительно является простым. +\begin{figure}[h!] + \begin{lstlisting}[language=C,style=CCodeStyle] + int main (int argc, const char* argv[]) { + int num = 71; + printf("Entered number %d is%s prime \n", + number, + isPrime(num) ? "" : " not" + ); + 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; -% } - + \end{lstlisting} +\end{figure} +Теперь мы можем написать программы любой сложности, содержащие функции \code{isPrime()} или \code{sum()}. О том, что мы работаем с консолью, в нашем случае должна знать только функция \code{int main (int argc, char *argv[])}, поэтому ввод значений и вывод на экран мы оставим в ней, а подсчёты, проверки или другие важные действия и алгоритмы положим в функции. Именно это абстрагирование является сильной стороной использования функций, так, например, у нас нет необходимости каждый раз вставлять в программу код взаимодействия с консолью при выводе каждой строки, а можно ограничиться вызовом функции \code{printf();} % Пришло время поговорить про прототипы. % Зачастую возникают ситуации, когда функция не описана до точки входа в программу, или вовсе лежит в другом файле. В этом случае мы должны сообщить компилятору, что такую функцию придётся дополнительно поискать. Для этого необходимо указать всю информацию о функции, кроме её тела. Такой оператор называется прототип функции.