forked from ivan-igorevich/basic-c
functions ready to be reviewed
This commit is contained in:
parent
a70a189280
commit
85d24e586d
BIN
build/main.pdf
BIN
build/main.pdf
Binary file not shown.
166
main.tex
166
main.tex
|
@ -21,171 +21,9 @@
|
||||||
\import{sections/}{05-conditions}
|
\import{sections/}{05-conditions}
|
||||||
% 06 cycles
|
% 06 cycles
|
||||||
\import{sections/}{06-cycles}
|
\import{sections/}{06-cycles}
|
||||||
|
% 07 functions
|
||||||
|
\import{sections/}{07-functions}
|
||||||
|
|
||||||
\section{Функции}
|
|
||||||
\subsection{Понятие функции, параметры и аргументы}
|
|
||||||
Функция - это такая обособленная часть кода, которую можно выполнять любое количество раз. У функций обязательно в таком порядке должны быть описаны: тип возвращаемого значения, название, параметры и так называемое тело, т есть собственно исполняемый код. Рассмотрим более детально функцию \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}
|
|
||||||
ТипВозвращаемогоЗначения Имя (СписокАргументов)
|
|
||||||
{
|
|
||||||
ТелоФункции
|
|
||||||
return ВозвращаемоеЗначение;
|
|
||||||
}
|
|
||||||
\end{verbatim}
|
|
||||||
\end{figure}
|
|
||||||
Далее приведём небольшой пример, который призван продемонстрировать, как выглядит простейшее \textit{объявление} и \textit{описпание} функций (function declaration and definition), а также их вызов из функции \code{int main (int argc, char *argv[])}.
|
|
||||||
|
|
||||||
\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
|
|
||||||
some function
|
|
||||||
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{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[])}, пусть о наличии у нас терминала <<знает>> только она.
|
|
||||||
\frm{Такой процесс, перенос участков кода между функциями, выделение участков кода в функции, синтаксические, стилистические и другие улучшения, называетя \textbf{рефакторингом}. Обычно, рефакторингом занимаются сами разработчики в свободное от основной деятельности времени, в периоды код ревью или по необходимости улучшить читаемость/повторяемость собственного кода.}
|
|
||||||
Следовательно, допишем условия: если делителей два, то число простое, возвращаем \code{ИСТИНУ}, то есть любое ненулевое значение, в нашем примере - единицу. Если же делителей больше – число не простое, возвращаем \code{ЛОЖЬ}, в нашем случае, это ноль. Такой вывод можно записать и другим способом, \code{return (dividers == 2)} – это выражение в случае истины вернет единицу в случае лжи ноль. Или можно воспользоваться тернарным оператором, то есть, написать \code{return (dividers == 2) ? 1 : 0}: если условие в скобках истинно вернется единица, ложно – ноль. Также важно, что выйти из функции мы можем на любом этапе ее выполнения, например если делителей уже три, то нам нужно не завершать цикл, а вернуть \code{ЛОЖЬ} из функции.
|
|
||||||
\begin{multicols}{2}
|
|
||||||
\begin{lstlisting}[language=C,style=CCodeStyle]
|
|
||||||
|
|
||||||
int isPrime(int number){
|
|
||||||
int dividers = 0, i = 1;
|
|
||||||
|
|
||||||
|
|
||||||
while(i <= number){
|
|
||||||
if(number % i++ ==0)
|
|
||||||
dividers++;
|
|
||||||
else
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (dividers == 3)
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return (dividers == 2)
|
|
||||||
}
|
|
||||||
\end{lstlisting}
|
|
||||||
\columnbreak
|
|
||||||
\begin{lstlisting}[language=C,style=CCodeStyle]
|
|
||||||
int main(int argc, char *argv[]) {
|
|
||||||
int number;
|
|
||||||
int dividers = 0, i = 1;
|
|
||||||
printf("Enter number: ");
|
|
||||||
scanf("%d", &number);
|
|
||||||
while (i <= number) {
|
|
||||||
if (number++ % i == 0) {
|
|
||||||
dividers++;
|
|
||||||
} else {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (dividers == 3)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
printf("Number %d is%s prime",
|
|
||||||
number,
|
|
||||||
(dividers == 2) ? "" : " not"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
\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;
|
|
||||||
}
|
|
||||||
|
|
||||||
\end{lstlisting}
|
|
||||||
\end{figure}
|
|
||||||
Теперь мы можем написать программы любой сложности, содержащие функции \code{isPrime()} или \code{sum()}. О том, что мы работаем с консолью, в нашем случае должна знать только функция \code{int main (int argc, char *argv[])}, поэтому ввод значений и вывод на экран мы оставим в ней, а подсчёты, проверки или другие важные действия и алгоритмы положим в функции. Именно это абстрагирование является сильной стороной использования функций, так, например, у нас нет необходимости каждый раз вставлять в программу код взаимодействия с консолью при выводе каждой строки, а можно ограничиться вызовом функции \code{printf();}
|
|
||||||
|
|
||||||
% Пришло время поговорить про прототипы.
|
|
||||||
% Зачастую возникают ситуации, когда функция не описана до точки входа в программу, или вовсе лежит в другом файле. В этом случае мы должны сообщить компилятору, что такую функцию придётся дополнительно поискать. Для этого необходимо указать всю информацию о функции, кроме её тела. Такой оператор называется прототип функции.
|
|
||||||
% Опишем прототип функции isPrime, описав сигнатуру этой функции.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
% int isPrime(int number);
|
|
||||||
% И пара слов о заголовочных файлах. Заголовочные файлы это мощный инструмент модульной разработки. Мы уже неоднократно видели подключение заголовочного файла stdio.h, давайте посмотрим, что же скрывает и как именно работает эта строка. Обнаружив данный файл на диске мы видим, что в нём содержатся другие подключения библиотек, директивы препроцессора (о которых более подробно мы будем говорить на следующих занятиях) и прототипы функций (например, так часто используемой нами
|
|
||||||
% printf()). (Где-то вот здесь… на 259 строке)
|
|
||||||
|
|
||||||
% // Здесь показ содержимого stdio.h
|
|
||||||
\section{Указатели}
|
\section{Указатели}
|
||||||
% Коллеги, здравствуйте. Вот и пришла пора поговорить о серьёзном низкоуровневом программировании. О том, от чего стараются оградить программистов языки высокого уровня и современные фреймворки. Об указателях.
|
% Коллеги, здравствуйте. Вот и пришла пора поговорить о серьёзном низкоуровневом программировании. О том, от чего стараются оградить программистов языки высокого уровня и современные фреймворки. Об указателях.
|
||||||
% На этом уроке мы поговорим о том, что такое указатели и как они соотносятся с остальными переменными, что такое передача аргумента по значению и по ссылке.
|
% На этом уроке мы поговорим о том, что такое указатели и как они соотносятся с остальными переменными, что такое передача аргумента по значению и по ссылке.
|
||||||
|
|
|
@ -0,0 +1,155 @@
|
||||||
|
\section{Функции}
|
||||||
|
\subsection{Понятие функции, параметры и аргументы}
|
||||||
|
Функция - это такая обособленная часть кода, которую можно выполнять любое количество раз. У функций обязательно в таком порядке должны быть описаны: тип возвращаемого значения, название, параметры и так называемое тело, т есть собственно исполняемый код. Рассмотрим более детально функцию \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}
|
||||||
|
ТипВозвращаемогоЗначения Имя (СписокАргументов)
|
||||||
|
{
|
||||||
|
ТелоФункции
|
||||||
|
return ВозвращаемоеЗначение;
|
||||||
|
}
|
||||||
|
\end{verbatim}
|
||||||
|
\end{figure}
|
||||||
|
Далее приведём небольшой пример, который призван продемонстрировать, как выглядит простейшее \textit{объявление} и \textit{описпание} функций (function declaration and definition), а также их вызов из функции \code{int main (int argc, char *argv[])}.
|
||||||
|
|
||||||
|
\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
|
||||||
|
some function
|
||||||
|
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{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[])}, пусть о наличии у нас терминала <<знает>> только она.
|
||||||
|
\frm{Такой процесс, перенос участков кода между функциями, выделение участков кода в функции, синтаксические, стилистические и другие улучшения, называетя \textbf{рефакторингом}. Обычно, рефакторингом занимаются сами разработчики в свободное от основной деятельности времени, в периоды код ревью или по необходимости улучшить читаемость/повторяемость собственного кода.}
|
||||||
|
Следовательно, допишем условия: если делителей два, то число простое, возвращаем \code{ИСТИНУ}, то есть любое ненулевое значение, в нашем примере - единицу. Если же делителей больше – число не простое, возвращаем \code{ЛОЖЬ}, в нашем случае, это ноль. Такой вывод можно записать и другим способом, \code{return (dividers == 2)} – это выражение в случае истины вернет единицу в случае лжи ноль. Или можно воспользоваться тернарным оператором, то есть, написать \code{return (dividers == 2) ? 1 : 0}: если условие в скобках истинно вернется единица, ложно – ноль. Также важно, что выйти из функции мы можем на любом этапе ее выполнения, например если делителей уже три, то нам нужно не завершать цикл, а вернуть \code{ЛОЖЬ} из функции.
|
||||||
|
\begin{multicols}{2}
|
||||||
|
\begin{lstlisting}[language=C,style=CCodeStyle]
|
||||||
|
|
||||||
|
int isPrime(int number){
|
||||||
|
int dividers = 0, i = 1;
|
||||||
|
|
||||||
|
|
||||||
|
while(i <= number){
|
||||||
|
if(number % i++ ==0)
|
||||||
|
dividers++;
|
||||||
|
else
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (dividers == 3)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return (dividers == 2)
|
||||||
|
}
|
||||||
|
\end{lstlisting}
|
||||||
|
\columnbreak
|
||||||
|
\begin{lstlisting}[language=C,style=CCodeStyle]
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
int number;
|
||||||
|
int dividers = 0, i = 1;
|
||||||
|
printf("Enter number: ");
|
||||||
|
scanf("%d", &number);
|
||||||
|
while (i <= number) {
|
||||||
|
if (number++ % i == 0) {
|
||||||
|
dividers++;
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (dividers == 3)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
printf("Number %d is%s prime",
|
||||||
|
number,
|
||||||
|
(dividers == 2) ? "" : " not"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
\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;
|
||||||
|
}
|
||||||
|
|
||||||
|
\end{lstlisting}
|
||||||
|
\end{figure}
|
||||||
|
Теперь мы можем написать программы любой сложности, содержащие функции \code{isPrime()} или \code{sum()}. О том, что мы работаем с консолью, в нашем случае должна знать только функция \code{int main (int argc, char *argv[])}, поэтому ввод значений и вывод на экран мы оставим в ней, а подсчёты, проверки или другие важные действия и алгоритмы положим в функции. Именно это абстрагирование является сильной стороной использования функций, так, например, у нас нет необходимости каждый раз вставлять в программу код взаимодействия с консолью при выводе каждой строки, а можно ограничиться вызовом функции \code{printf();}
|
||||||
|
\subsection{Прототип функции, заголовочные файлы}
|
||||||
|
Зачастую возникают ситуации, когда функция не описана до точки входа в программу, или вовсе лежит в другом файле, возможно, даже написанном не нами. В этом случае мы должны сообщить компилятору, что такую функцию придётся дополнительно поискать. Для этого необходимо указать всю информацию о функции, кроме её тела. Такое объявление называется \textbf{прототип или определение функции} (англ. function definition).
|
||||||
|
\frm{С определением функции тесно связано понятие \textit{сигнатуры} функции. Сигнатура функции для разных языков программирования представляется немного разным составом сведений, так, например, в языке С сигнатура - это тип возвращаемого значения, название функции и порядок типов параметров, например, для функции суммирования чисел, описанной выше, это будет \code{int sum(int, int)}.}
|
||||||
|
Опишем прототип функции \code{isPrime()}, описав сигнатуру этой функции. Обратите внимание, что допустимо в определении функции также писать названия параметров, а не только их типы, но это необязательно.
|
||||||
|
|
||||||
|
\begin{figure}[h!]
|
||||||
|
\begin{lstlisting}[language=C,style=CCodeStyle]
|
||||||
|
int isPrime(int number);
|
||||||
|
\end{lstlisting}
|
||||||
|
\end{figure}
|
||||||
|
Из таких определений часто составляют так называемые \textit{заголовочные файлы}. Заголовочные файлы это мощный инструмент модульной разработки. Мы уже неоднократно видели подключение заголовочного файла \code{stdio.h}, Обнаружив данный файл на диске компьютера, мы увидим, что в нём содержатся другие подключения библиотек, директивы препроцессора (о которых более подробно мы будем говорить на следующих занятиях) и прототипы функций (например, так часто используемой нами \code{printf()}). Заголовочным этот файл называется, потому что его обычно пишут в коде программы в самом верху, и фактически, компилятор просто вставляет его содержимое в текст программы. Расширение файла (\code{.h}) является сокращением от английского слова header, заголовок. Обратите внимание, что подключая заголовочный файл \code{stdio.h} мы получаем вообще всю функциональность стандартного ввода-вывода, то есть, например, работу с файлами, которую можем и не использовать. В стандарте С++20 было принято решение о переходе для поддержки повторяемости кода от заголовочных файлов к целостным модулям, импортируемым отдельно. Это позволяет интегрировать в программу только нужный функционал, игнорируя всю остальную библиотеку.
|
Loading…
Reference in New Issue