refactored preambles
This commit is contained in:
parent
6f639f55cd
commit
50b4bbbdfa
|
@ -0,0 +1,29 @@
|
||||||
|
% \usepackage[printwatermark]{xwatermark}
|
||||||
|
|
||||||
|
\usepackage{ascii}
|
||||||
|
\usepackage{textcomp}
|
||||||
|
\usepackage{eurosym}
|
||||||
|
\usepackage{cclicenses}
|
||||||
|
|
||||||
|
\input{fancy-listings-preamble}
|
||||||
|
|
||||||
|
\usetikzlibrary{positioning}
|
||||||
|
|
||||||
|
\geometry{
|
||||||
|
paperheight=24cm,
|
||||||
|
paperwidth=17cm,
|
||||||
|
lmargin=1.5cm,
|
||||||
|
rmargin=2.5cm,
|
||||||
|
tmargin=2.5cm,
|
||||||
|
bmargin=2.5cm,
|
||||||
|
}
|
||||||
|
|
||||||
|
\author{Иван Овчинников}
|
||||||
|
\date{\today}
|
||||||
|
\title{Очередное введение в\\язык программирования C}
|
||||||
|
|
||||||
|
% \newwatermark[allpages,color=red!50,angle=70,scale=7,xpos=-36,ypos=14]{DRAFT}
|
||||||
|
|
||||||
|
\addto{\captionsrussian}{\renewcommand{\figurename}{}}
|
||||||
|
|
||||||
|
\newcommand{\sectionbreak}{\clearpage}
|
BIN
build/main.pdf
BIN
build/main.pdf
Binary file not shown.
|
@ -0,0 +1,85 @@
|
||||||
|
\usepackage{tikz}
|
||||||
|
\usepackage{import}
|
||||||
|
\usepackage{xcolor}
|
||||||
|
\usepackage{bookmark}
|
||||||
|
\usepackage{multicol,multirow,colortbl}
|
||||||
|
\usepackage{longtable}
|
||||||
|
\usepackage{setspace}
|
||||||
|
\usepackage{titlesec}
|
||||||
|
\usepackage{indentfirst}
|
||||||
|
\usepackage{amsmath,amsfonts,amssymb,amsthm,mathtools}
|
||||||
|
\usepackage{layout,lscape}
|
||||||
|
\usepackage{hyperref}
|
||||||
|
\usepackage{geometry}
|
||||||
|
\usepackage[russian]{babel}
|
||||||
|
\usepackage{nomencl}
|
||||||
|
\usepackage{makeidx}
|
||||||
|
\usepackage{fancyhdr}
|
||||||
|
\usepackage{tabularx,adjustbox}
|
||||||
|
\usepackage{float,makecell}
|
||||||
|
\usepackage{anyfontsize,tabto}
|
||||||
|
\usepackage{tocloft}
|
||||||
|
|
||||||
|
\makeindex
|
||||||
|
\makenomenclature
|
||||||
|
\babelfont{rm}{Times New Roman}
|
||||||
|
\babelfont{sf}{Liberation Serif}
|
||||||
|
\babelfont{tt}{Courier New}
|
||||||
|
\onehalfspacing
|
||||||
|
|
||||||
|
\hypersetup{
|
||||||
|
colorlinks=false,
|
||||||
|
linktoc=all
|
||||||
|
}
|
||||||
|
|
||||||
|
\fancypagestyle{plain}{ % для автосгенерированых
|
||||||
|
\fancyhf{}
|
||||||
|
\renewcommand{\headrulewidth}{0pt}
|
||||||
|
}
|
||||||
|
\fancypagestyle{titlepage}{
|
||||||
|
\fancyhf{}
|
||||||
|
\cfoot{\small{\textbf{Москва, \the\year{}г.}}}
|
||||||
|
}
|
||||||
|
\fancyhf{}
|
||||||
|
\renewcommand{\headrulewidth}{0pt}
|
||||||
|
|
||||||
|
\newcommand{\numerationTop}{
|
||||||
|
\fancyhead[C]{\thepage}
|
||||||
|
}
|
||||||
|
\newcommand{\numerationBottom}{
|
||||||
|
\fancyfoot[C]{\thepage}
|
||||||
|
}
|
||||||
|
|
||||||
|
\newcommand{\code}[1]{\texttt{#1}}
|
||||||
|
\renewcommand{\nomname}{ }
|
||||||
|
\newcommand*{\nom}[2]{#1\nomenclature{#1}{#2}}
|
||||||
|
|
||||||
|
\newcommand\blankpage{%
|
||||||
|
\null
|
||||||
|
\thispagestyle{empty}%
|
||||||
|
\addtocounter{page}{-1}%
|
||||||
|
\newpage
|
||||||
|
}
|
||||||
|
|
||||||
|
\newcommand{\frm}[1]{\newline%
|
||||||
|
\newline%
|
||||||
|
\indent\fbox{%
|
||||||
|
\parbox{0.9\textwidth}{%
|
||||||
|
#1}%
|
||||||
|
}%
|
||||||
|
\newline%
|
||||||
|
\newline%
|
||||||
|
}%
|
||||||
|
|
||||||
|
\makeatletter
|
||||||
|
\newcommand{\setword}[2]{%
|
||||||
|
\phantomsection
|
||||||
|
#1\def\@currentlabel{\unexpanded{#1}}\label{#2}%
|
||||||
|
}
|
||||||
|
\makeatother
|
||||||
|
|
||||||
|
\newcommand\lh[2]{\texttt{\textcolor{#1}{#2}}}
|
||||||
|
\newcommand\hrf[1]{\hyperref[#1]{\ref{#1}}}
|
||||||
|
\newcommand*\circled[1]{\tikz[baseline=(char.base)]{\node[shape=circle,draw,inner sep=2pt] (char) {#1};}}
|
||||||
|
|
||||||
|
\renewcommand{\cftsecleader}{\cftdotfill{\cftdotsep}}
|
|
@ -0,0 +1,104 @@
|
||||||
|
\usepackage{listings}
|
||||||
|
|
||||||
|
\definecolor{codekeywords}{rgb}{0.1,0.4,0.4}
|
||||||
|
\definecolor{codecomments}{rgb}{0,0.6,0}
|
||||||
|
\definecolor{codenumbers}{rgb}{0.4,0.4,0.4}
|
||||||
|
\definecolor{codestring}{rgb}{0.85,0.2,0.1}
|
||||||
|
\definecolor{backcolour}{rgb}{0.95,0.95,0.92}
|
||||||
|
\definecolor{codefine}{rgb}{0.7,0.5,0.3}
|
||||||
|
\definecolor{dkgreen}{rgb}{0,0.6,0}
|
||||||
|
\definecolor{gray}{rgb}{0.5,0.5,0.5}
|
||||||
|
\definecolor{mauve}{rgb}{0.58,0,0.82}
|
||||||
|
|
||||||
|
\lstdefinestyle{JCodeStyle}{
|
||||||
|
frame=single,
|
||||||
|
language=Java,
|
||||||
|
aboveskip=3mm,
|
||||||
|
belowskip=3mm,
|
||||||
|
showstringspaces=false,
|
||||||
|
columns=flexible,
|
||||||
|
basicstyle=\footnotesize\ttfamily,
|
||||||
|
numbers=left,
|
||||||
|
numberstyle=\tiny\color{gray},
|
||||||
|
keywordstyle=\color{blue},
|
||||||
|
commentstyle=\color{dkgreen},
|
||||||
|
stringstyle=\color{mauve},
|
||||||
|
breaklines=true,
|
||||||
|
breakatwhitespace=true,
|
||||||
|
tabsize=4,
|
||||||
|
escapeinside={<@}{@>}
|
||||||
|
}
|
||||||
|
|
||||||
|
\lstdefinestyle{PyCodeStyle}{
|
||||||
|
frame=single,
|
||||||
|
commentstyle=\color{codecomments},
|
||||||
|
numberstyle=\tiny\color{codenumbers},
|
||||||
|
stringstyle=\color{codestring},
|
||||||
|
basicstyle=\ttfamily\footnotesize,
|
||||||
|
keywordstyle=\color{codekeywords},
|
||||||
|
breakatwhitespace=false,
|
||||||
|
breaklines=true,
|
||||||
|
captionpos=b,
|
||||||
|
keepspaces=true,
|
||||||
|
numbers=left,
|
||||||
|
numbersep=5pt,
|
||||||
|
showspaces=false,
|
||||||
|
showstringspaces=false,
|
||||||
|
showtabs=false,
|
||||||
|
tabsize=4,
|
||||||
|
escapeinside={<@}{@>}
|
||||||
|
}
|
||||||
|
|
||||||
|
\lstdefinestyle{CCodeStyle}{
|
||||||
|
frame=single,
|
||||||
|
commentstyle=\color{codecomments},
|
||||||
|
morecomment=[l][\color{codefine}]{\#},
|
||||||
|
numberstyle=\tiny\color{codenumbers},
|
||||||
|
stringstyle=\color{codestring},
|
||||||
|
basicstyle=\ttfamily\footnotesize,
|
||||||
|
keywordstyle=\color{codekeywords},
|
||||||
|
emph={int,char,double,float,unsigned,void,bool},
|
||||||
|
emphstyle={\color{blue}},
|
||||||
|
breakatwhitespace=false,
|
||||||
|
breaklines=true,
|
||||||
|
captionpos=b,
|
||||||
|
keepspaces=true,
|
||||||
|
numbers=left,
|
||||||
|
numbersep=5pt,
|
||||||
|
showspaces=false,
|
||||||
|
showstringspaces=false,
|
||||||
|
showtabs=false,
|
||||||
|
tabsize=4,
|
||||||
|
escapeinside={<@}{@>}
|
||||||
|
}
|
||||||
|
|
||||||
|
\lstdefinestyle{ASMStyle}{
|
||||||
|
frame=single,
|
||||||
|
numberstyle=\tiny\color{codenumbers},
|
||||||
|
commentstyle=\color{codecomments},
|
||||||
|
keywordstyle=\color{codekeywords},
|
||||||
|
morecomment=[l]{//}, % l is for line comment
|
||||||
|
morecomment=[s]{/*}{*/}, % s is for start and end delimiter
|
||||||
|
basicstyle={\ttfamily\footnotesize},
|
||||||
|
morekeywords={
|
||||||
|
add,addi,and,andi,
|
||||||
|
bge,beq,bne,br,
|
||||||
|
cmpeqi,cmpgei,cmplti,cmpnei,
|
||||||
|
ldhu,ldw,ldwio,
|
||||||
|
mov,movi,movhi,muli,
|
||||||
|
nop,nor,
|
||||||
|
ret,
|
||||||
|
slli,srai,srli,stw,stwio},
|
||||||
|
breakatwhitespace=false,
|
||||||
|
breaklines=true,
|
||||||
|
captionpos=b,
|
||||||
|
keepspaces=true,
|
||||||
|
numbers=left,
|
||||||
|
numbersep=5pt,
|
||||||
|
showspaces=false,
|
||||||
|
showtabs=false,
|
||||||
|
tabsize=4,
|
||||||
|
escapeinside={<@}{@>}
|
||||||
|
}
|
||||||
|
|
||||||
|
\lstset{escapeinside={<@}{@>}}
|
|
@ -1,75 +0,0 @@
|
||||||
% \usepackage[printwatermark]{xwatermark}
|
|
||||||
\usepackage{import}
|
|
||||||
\usepackage{listings}
|
|
||||||
\usepackage{xcolor}
|
|
||||||
\usepackage{bookmark}
|
|
||||||
\usepackage{multicol}
|
|
||||||
\usepackage{setspace}
|
|
||||||
\usepackage{titlesec}
|
|
||||||
\usepackage{indentfirst}
|
|
||||||
\usepackage{amsmath,amsfonts,amssymb,amsthm,mathtools}
|
|
||||||
\usepackage{icomma}
|
|
||||||
\usepackage{layout}
|
|
||||||
\usepackage{titlesec}
|
|
||||||
\usepackage{hyperref}
|
|
||||||
\usepackage{tikz}
|
|
||||||
|
|
||||||
\usepackage{ascii}
|
|
||||||
\usepackage{textcomp}
|
|
||||||
\usepackage{eurosym}
|
|
||||||
\usepackage{cclicenses}
|
|
||||||
|
|
||||||
\usetikzlibrary{positioning}
|
|
||||||
\usepackage[lmargin=1.5cm,rmargin=2.5cm,tmargin=2.5cm,bmargin=2.5cm,paperheight=240mm,paperwidth=170mm]{geometry}
|
|
||||||
|
|
||||||
\definecolor{codekeywords}{rgb}{0.1,0.3,0.3}
|
|
||||||
\definecolor{codecomments}{rgb}{0,0.4,0}
|
|
||||||
\definecolor{codenumbers}{rgb}{0.4,0.4,0.4}
|
|
||||||
\definecolor{codestring}{rgb}{0.85,0.2,0.1}
|
|
||||||
\definecolor{backcolour}{rgb}{0.95,0.95,0.92}
|
|
||||||
\definecolor{codefine}{rgb}{0.7,0.5,0.3}
|
|
||||||
\lstdefinestyle{CCodeStyle}{
|
|
||||||
commentstyle=\color{codecomments},
|
|
||||||
morecomment=[l][\color{codefine}]{\#},
|
|
||||||
numberstyle=\tiny\color{codenumbers},
|
|
||||||
stringstyle=\color{codestring},
|
|
||||||
basicstyle=\ttfamily\footnotesize,
|
|
||||||
keywordstyle=\color{codekeywords},
|
|
||||||
emph={int,char,double,float,unsigned,void,bool},
|
|
||||||
emphstyle={\color{blue}},
|
|
||||||
breakatwhitespace=false,
|
|
||||||
breaklines=true,
|
|
||||||
captionpos=b,
|
|
||||||
keepspaces=true,
|
|
||||||
numbers=left,
|
|
||||||
numbersep=5pt,
|
|
||||||
showspaces=false,
|
|
||||||
showstringspaces=false,
|
|
||||||
showtabs=false,
|
|
||||||
tabsize=4
|
|
||||||
}
|
|
||||||
\author{Иван Овчинников}
|
|
||||||
\date{\today}
|
|
||||||
\title{Очередное введение в\\язык программирования C}
|
|
||||||
\babelfont{rm}{Times New Roman}
|
|
||||||
\babelfont{sf}{Microsoft Sans Serif}
|
|
||||||
\babelfont{tt}{Courier New}
|
|
||||||
% \newwatermark[allpages,color=red!50,angle=70,scale=7,xpos=-36,ypos=14]{DRAFT}
|
|
||||||
\onehalfspacing
|
|
||||||
\addto{\captionsrussian}{\renewcommand{\figurename}{}}
|
|
||||||
\hypersetup{
|
|
||||||
colorlinks=false,
|
|
||||||
linktoc=all
|
|
||||||
}
|
|
||||||
|
|
||||||
\newcommand{\code}[1]{\texttt{#1}}
|
|
||||||
\newcommand{\sectionbreak}{\clearpage}
|
|
||||||
\newcommand{\frm}[1]{\newline%
|
|
||||||
\newline%
|
|
||||||
\indent\fbox{%
|
|
||||||
\parbox{0.9\textwidth}{%
|
|
||||||
#1}%
|
|
||||||
}%
|
|
||||||
\newline%
|
|
||||||
\newline%
|
|
||||||
}%
|
|
8
main.tex
8
main.tex
|
@ -1,6 +1,6 @@
|
||||||
\documentclass[a4paper]{article}
|
\documentclass[fontsize=14bp]{article}
|
||||||
\usepackage[russian]{babel}
|
\input{common-preamble}
|
||||||
\include{formatting}
|
\input{book-preamble}
|
||||||
|
|
||||||
\begin{document}
|
\begin{document}
|
||||||
\maketitle
|
\maketitle
|
||||||
|
@ -35,7 +35,7 @@
|
||||||
\import{sections/}{12-files}
|
\import{sections/}{12-files}
|
||||||
|
|
||||||
\section{Распределение памяти}
|
\section{Распределение памяти}
|
||||||
Этот раздел находится в конце книги, но не по важности. Сильная сторона языка С (и, как следствие, С++) не только в возможности работать с указателями, но и в возможности самостоятельно управлять выделяемой памятью внутри программы. В языках высокого уровня данная возможность зачастую скрыта от программиста, чтобы по случайности программа не привела к зависанию среды виртуализации, по неосторожности не попыталась воспользоваться всей возможной оперативной памятью или не сломала операционную систему. Итак, как мы уже знаем, все переменные всех типов как-то хранятся в памяти, и до этого момента нас устраивало, как операционная система нам эту память выделяет. Но, пришло время взять бразды правления в свои руки. Процесс \textbf{выделения памяти} для программы называется \textbf{memory allocation}, отсюда и название функции, которая выделяет память и пишет в предложенный идентификатор указатель на начало этой области.
|
Этот раздел находится в конце документа, но не по важности. Сильная сторона языка С (и, как следствие, С++) не только в возможности работать с указателями, но и в возможности самостоятельно управлять выделяемой памятью внутри программы. В языках высокого уровня данная возможность зачастую скрыта от программиста, чтобы по случайности программа не привела к зависанию среды виртуализации, по неосторожности не попыталась воспользоваться всей возможной оперативной памятью или не сломала операционную систему. Итак, как мы уже знаем, все переменные всех типов как-то хранятся в памяти, и до этого момента нас устраивало, как операционная система нам эту память выделяет. Но, пришло время взять бразды правления в свои руки. Процесс \textbf{выделения памяти} для программы называется \textbf{memory allocation}, отсюда и название функции, которая выделяет память и пишет в предложенный идентификатор указатель на начало этой области.
|
||||||
|
|
||||||
\subsection{\code{void* malloc(size);}}
|
\subsection{\code{void* malloc(size);}}
|
||||||
Функция \code{void* malloc(size);} принимает в качестве аргумента размер выделяемой памяти. Как видим, функция возвращает довольно необычный на первый взгляд тип: \code{void*}, то есть область памяти будет зафиксирована, но не размечена. То есть это будет просто некоторая пустая область из \code{size} байт.
|
Функция \code{void* malloc(size);} принимает в качестве аргумента размер выделяемой памяти. Как видим, функция возвращает довольно необычный на первый взгляд тип: \code{void*}, то есть область памяти будет зафиксирована, но не размечена. То есть это будет просто некоторая пустая область из \code{size} байт.
|
||||||
|
|
|
@ -4,19 +4,19 @@
|
||||||
Переменные делятся на целочисленные, символьные, указатели и числа с плавающей точкой (англ. floating point, дробное число). Все, кроме указателей и символьных переменных бывают как знаковыми так и беззнаковыми. То есть в знаковых самый старший бит в двоичной записи этих переменных отводится под определение, является ли число отрицательным, или положительным, в беззнаковых все биты используются для записи числа, что увеличивает его диапазон возможных значений, но позволяет записать только положительные числа. В классическом С нет булевого типа, вместо него используется целое число и значения нуля для \textbf{лжи} и \textit{любое} другое число для \textbf{истины}, обычно это единица. Об указателях и булевой алгебре мы будем подробно говорить в одном из последующих разделов.
|
Переменные делятся на целочисленные, символьные, указатели и числа с плавающей точкой (англ. floating point, дробное число). Все, кроме указателей и символьных переменных бывают как знаковыми так и беззнаковыми. То есть в знаковых самый старший бит в двоичной записи этих переменных отводится под определение, является ли число отрицательным, или положительным, в беззнаковых все биты используются для записи числа, что увеличивает его диапазон возможных значений, но позволяет записать только положительные числа. В классическом С нет булевого типа, вместо него используется целое число и значения нуля для \textbf{лжи} и \textit{любое} другое число для \textbf{истины}, обычно это единица. Об указателях и булевой алгебре мы будем подробно говорить в одном из последующих разделов.
|
||||||
\begin{figure}[h!]
|
\begin{figure}[h!]
|
||||||
\centering
|
\centering
|
||||||
\begin{tabular}{|p{1.5cm}|p{6.6cm}|p{2.4cm}|}
|
\begin{tabular}{|p{15mm}|p{65mm}|p{25mm}|}
|
||||||
\hline
|
\hline
|
||||||
Тип & Пояснение & Спецификатор формата \\
|
Тип & Пояснение & Спецификатор формата \\
|
||||||
\hline
|
\hline
|
||||||
char & Целочисленный, самый маленький из адресуемых типов, диапазон: [\textminus128, +127] & \%c \\
|
char & Целочисленный, самый маленький из адресуемых типов, диапазон: [\textminus128, +127] & \%c \\
|
||||||
\hline
|
\hline
|
||||||
short\newline short int & Тип короткого целого числа со знаком, диапазон: [\textminus32 768, +32 767] & \%hi \\
|
short\newline short int & Тип короткого целого числа со знаком, диапазон:\newline[\textminus32 768, +32 767] & \%hi \\
|
||||||
\hline
|
\hline
|
||||||
int & Основной тип целого числа со знаком, диапазон: [\textminus2 147 483 648, +2 147 483 647] & \%i или \%d \\
|
int & Основной тип целого числа со знаком, диапазон:\newline[\textminus2 147 483 648, +2 147 483 647] & \%i или \%d \\
|
||||||
\hline
|
\hline
|
||||||
long\newline long int & Тип длинного целого числа со знаком, диапазон: [\textminus2 147 483 648, +2 147 483 647] & \%li или \%ld \\
|
long\newline long int & Тип длинного целого числа со знаком, диапазон:\newline[\textminus2 147 483 648, +2 147 483 647] & \%li или \%ld \\
|
||||||
\hline
|
\hline
|
||||||
long long\newline long long int & Тип двойного длинного целого числа со знаком, диапазон: [\textminus9 223 372 036 854 775 808, +9 223 372 036 854 775 807] & \%lli \\
|
long long\newline long long int & Тип двойного длинного целого числа со знаком, диапазон:\newline[\textminus9 223 372 036 854 775 808, +9 223 372 036 854 775 807] & \%lli \\
|
||||||
\hline
|
\hline
|
||||||
float & Тип вещественного числа с плавающей запятой (одинарной точности) & \%f (автоматически преобразуется в double для printf()) \\
|
float & Тип вещественного числа с плавающей запятой (одинарной точности) & \%f (автоматически преобразуется в double для printf()) \\
|
||||||
\hline
|
\hline
|
||||||
|
@ -363,7 +363,7 @@ a = a ^ b; //00001111
|
||||||
\end{figure}
|
\end{figure}
|
||||||
Применять бинарную алгебру можно и в больших проектах, работающих со сложными высокоуровневыми абстракциями. Помимо этого важно помнить, что поддержка бинарных операций есть в подавляющем числе языков программирования. Используя бинарную алгебру можно создавать оптимальные протоколы передачи данных и/или алгоритмы хранения и обработки.
|
Применять бинарную алгебру можно и в больших проектах, работающих со сложными высокоуровневыми абстракциями. Помимо этого важно помнить, что поддержка бинарных операций есть в подавляющем числе языков программирования. Используя бинарную алгебру можно создавать оптимальные протоколы передачи данных и/или алгоритмы хранения и обработки.
|
||||||
|
|
||||||
\begin{figure}[h!]
|
\begin{figure}[H]
|
||||||
\begin{verbatim}
|
\begin{verbatim}
|
||||||
$ ./program
|
$ ./program
|
||||||
a = 15
|
a = 15
|
||||||
|
|
|
@ -84,10 +84,13 @@ $
|
||||||
Теперь мы без проблем можем оформить уже существующие у нас программы в виде функций. Например, оформим в виде функции программу проверки простоты числа. Для этого опишем функцию которая возвращает целое число, назовем ее \code{isPrime()}, в качестве параметра она будет принимать целое число, назовем его \code{number}. Найдем в предыдущих разделах (стр. \hyperref[code:isPrime]{\pageref{code:isPrime}}) программу определения простоты числа и скопируем в тело функции. Внесем небольшие правки, уберем вывод так как это будет, можно сказать, классическая проверяющая функция, вывод оставим для функции \code{int main (int argc, char *argv[])}, пусть о наличии у нас терминала <<знает>> только она.
|
Теперь мы без проблем можем оформить уже существующие у нас программы в виде функций. Например, оформим в виде функции программу проверки простоты числа. Для этого опишем функцию которая возвращает целое число, назовем ее \code{isPrime()}, в качестве параметра она будет принимать целое число, назовем его \code{number}. Найдем в предыдущих разделах (стр. \hyperref[code:isPrime]{\pageref{code:isPrime}}) программу определения простоты числа и скопируем в тело функции. Внесем небольшие правки, уберем вывод так как это будет, можно сказать, классическая проверяющая функция, вывод оставим для функции \code{int main (int argc, char *argv[])}, пусть о наличии у нас терминала <<знает>> только она.
|
||||||
\frm{Такой процесс, перенос участков кода между функциями, выделение участков кода в функции, синтаксические, стилистические и другие улучшения, называетя \textbf{рефакторингом}. Обычно, рефакторингом занимаются сами разработчики в свободное от основной деятельности времени, в периоды код ревью или по необходимости улучшить читаемость/повторяемость собственного кода.}
|
\frm{Такой процесс, перенос участков кода между функциями, выделение участков кода в функции, синтаксические, стилистические и другие улучшения, называетя \textbf{рефакторингом}. Обычно, рефакторингом занимаются сами разработчики в свободное от основной деятельности времени, в периоды код ревью или по необходимости улучшить читаемость/повторяемость собственного кода.}
|
||||||
Следовательно, допишем условия: если делителей два, то число простое, возвращаем \code{ИСТИНУ}, то есть любое ненулевое значение, в нашем примере - единицу. Если же делителей больше – число не простое, возвращаем \code{ЛОЖЬ}, в нашем случае, это ноль. Такой вывод можно записать и другим способом, \code{return (dividers == 2)} – это выражение в случае истины вернет единицу в случае лжи ноль. Или можно воспользоваться тернарным оператором, то есть, написать \code{return (dividers == 2) ? 1 : 0}: если условие в скобках истинно вернется единица, ложно – ноль. Также важно, что выйти из функции мы можем на любом этапе ее выполнения, например если делителей уже три, то нам нужно не завершать цикл, а вернуть \code{ЛОЖЬ} из функции.
|
Следовательно, допишем условия: если делителей два, то число простое, возвращаем \code{ИСТИНУ}, то есть любое ненулевое значение, в нашем примере - единицу. Если же делителей больше – число не простое, возвращаем \code{ЛОЖЬ}, в нашем случае, это ноль. Такой вывод можно записать и другим способом, \code{return (dividers == 2)} – это выражение в случае истины вернет единицу в случае лжи ноль. Или можно воспользоваться тернарным оператором, то есть, написать \code{return (dividers == 2) ? 1 : 0}: если условие в скобках истинно вернется единица, ложно – ноль. Также важно, что выйти из функции мы можем на любом этапе ее выполнения, например если делителей уже три, то нам нужно не завершать цикл, а вернуть \code{ЛОЖЬ} из функции.
|
||||||
|
|
||||||
|
\begin{figure}[H]
|
||||||
|
\setlength{\columnsep}{22pt}
|
||||||
\begin{multicols}{2}
|
\begin{multicols}{2}
|
||||||
\begin{lstlisting}[language=C,style=CCodeStyle]
|
\begin{lstlisting}[language=C,style=CCodeStyle]
|
||||||
|
|
||||||
int isPrime(int number){
|
int isPrime(int number){
|
||||||
|
|
||||||
int dividers = 0, i = 1;
|
int dividers = 0, i = 1;
|
||||||
|
|
||||||
|
|
||||||
|
@ -126,6 +129,8 @@ int main(int argc, char *argv[]) {
|
||||||
}
|
}
|
||||||
\end{lstlisting}
|
\end{lstlisting}
|
||||||
\end{multicols}
|
\end{multicols}
|
||||||
|
\end{figure}
|
||||||
|
%\setlength{\columnsep}{10pt}
|
||||||
Немного подправив вывод, внесем в него вызов функции \code{isPrime()} и объявим переменную \code{int num}, которую будем передавать в качестве аргумента в функцию \code{isPrime()}. Запустим нашу программу и убедимся что все работает – число 71 действительно является простым.
|
Немного подправив вывод, внесем в него вызов функции \code{isPrime()} и объявим переменную \code{int num}, которую будем передавать в качестве аргумента в функцию \code{isPrime()}. Запустим нашу программу и убедимся что все работает – число 71 действительно является простым.
|
||||||
|
|
||||||
\begin{figure}[h!]
|
\begin{figure}[h!]
|
||||||
|
|
|
@ -52,9 +52,13 @@ value of 'pointer' is 000000000061FE1C
|
||||||
\frm{Для языка С также справедливо выражение <<передача по ссылке>>, поскольку в языке С нет отдельной операции передачи по ссылке. Так, например, в языке С++ передача по ссылке и передача по указателю - это разные операции.}
|
\frm{Для языка С также справедливо выражение <<передача по ссылке>>, поскольку в языке С нет отдельной операции передачи по ссылке. Так, например, в языке С++ передача по ссылке и передача по указателю - это разные операции.}
|
||||||
То есть функция будет ссылаться на переменные, на которые мы укажем и оперировать их значениями. Давайте немного модифицируем нашу программу обмена значениями внутри двух переменных (\hyperref[code:programswap]{\ref{code:programswap}}): опишем её в виде функции, принимающей в качестве параметров два указателя на целые числа типа \code{char}, и передадим адреса созданных в \code{int main (int argc, char *argv[])} переменных. Внутри функции, при её вызове, у нас будут создаваться не переменные, а указатели на переменные, то есть мы будем ссылаться на те самые переменные, созданные вне функции, и будем менять именно их (тех переменных) значения. Таким образом, нам не нужно ничего возвращать, потому что в функции ничего не создавалось, и типом возвращаемого значения функции должен быть \code{void}.
|
То есть функция будет ссылаться на переменные, на которые мы укажем и оперировать их значениями. Давайте немного модифицируем нашу программу обмена значениями внутри двух переменных (\hyperref[code:programswap]{\ref{code:programswap}}): опишем её в виде функции, принимающей в качестве параметров два указателя на целые числа типа \code{char}, и передадим адреса созданных в \code{int main (int argc, char *argv[])} переменных. Внутри функции, при её вызове, у нас будут создаваться не переменные, а указатели на переменные, то есть мы будем ссылаться на те самые переменные, созданные вне функции, и будем менять именно их (тех переменных) значения. Таким образом, нам не нужно ничего возвращать, потому что в функции ничего не создавалось, и типом возвращаемого значения функции должен быть \code{void}.
|
||||||
|
|
||||||
|
|
||||||
|
\begin{figure}[H]
|
||||||
|
\setlength{\columnsep}{30pt}
|
||||||
\begin{multicols}{2}
|
\begin{multicols}{2}
|
||||||
\lstinputlisting[language=C,style=CCodeStyle]{../sources/swapfunc.c}
|
\lstinputlisting[language=C,style=CCodeStyle]{../sources/swapfunc.c}
|
||||||
\columnbreak
|
\columnbreak
|
||||||
\lstinputlisting[language=C,style=CCodeStyle]{../sources/swapprog.c}
|
\lstinputlisting[language=C,style=CCodeStyle]{../sources/swapprog.c}
|
||||||
\end{multicols}
|
\end{multicols}
|
||||||
|
\end{figure}
|
||||||
Применение такого подхода открывает перед нами широкие возможности. Важно, на схеме со стр. \pageref{fig:dereference}, что указатель - это тоже переменная, поэтому мы можем создавать указатели на указатели, и так далее, указатели любой сложности, тем самым увеличивая уровень абстракции программы.
|
Применение такого подхода открывает перед нами широкие возможности. Важно, на схеме со стр. \pageref{fig:dereference}, что указатель - это тоже переменная, поэтому мы можем создавать указатели на указатели, и так далее, указатели любой сложности, тем самым увеличивая уровень абстракции программы.
|
||||||
|
|
|
@ -5,11 +5,14 @@
|
||||||
Помимо уже хорошо знакомой вам директивы \code{\#include}, частично описанной в разделе \hyperref[text:directive]{\ref{text:directive}}, естественно, существуют и другие. Некоторые из них ограничивают импорт описанных в заголовочном файле функций, некоторые <<\textbf{описывают}>> какие-то константы и даже действия. Вот, директиву \textbf{описать} мы и рассмотрим подробнее. Она не зря называется директивой препроцессора, поскольку даёт указание не процессору во время выполнения программы выделить память, присвоить значения, а непосредственно компилятору: заменить в тексте программы одни слова на другие. Таким образом можно задавать константы проекта, и даже делать сокращённые записи целых действий. Например, написав \code{\#define ARRAY\_LENGTH 50} мы предпишем компилятору, перед запуском трансляции нашего кода заменить все слова \code{ARRAY\_LENGTH} на цифру 50. В такой записи, слово \code{ARRAY\_LENGTH} будет называться \textit{макроконстантой}.
|
Помимо уже хорошо знакомой вам директивы \code{\#include}, частично описанной в разделе \hyperref[text:directive]{\ref{text:directive}}, естественно, существуют и другие. Некоторые из них ограничивают импорт описанных в заголовочном файле функций, некоторые <<\textbf{описывают}>> какие-то константы и даже действия. Вот, директиву \textbf{описать} мы и рассмотрим подробнее. Она не зря называется директивой препроцессора, поскольку даёт указание не процессору во время выполнения программы выделить память, присвоить значения, а непосредственно компилятору: заменить в тексте программы одни слова на другие. Таким образом можно задавать константы проекта, и даже делать сокращённые записи целых действий. Например, написав \code{\#define ARRAY\_LENGTH 50} мы предпишем компилятору, перед запуском трансляции нашего кода заменить все слова \code{ARRAY\_LENGTH} на цифру 50. В такой записи, слово \code{ARRAY\_LENGTH} будет называться \textit{макроконстантой}.
|
||||||
\frm{Обратите внимание, что директива пишется немного не так, как обычный оператор языка, хоть и может находиться в любом месте кода. В конце директивы не ставится точка с запятой. Это важно именно потому что директивы работают с текстом программы, то есть если точка с запятой всё же будет поставлена, текст программы будет всегда содержать вместо макроконстанты число и точку с запятой, что может в корне изменить смысл программы.}
|
\frm{Обратите внимание, что директива пишется немного не так, как обычный оператор языка, хоть и может находиться в любом месте кода. В конце директивы не ставится точка с запятой. Это важно именно потому что директивы работают с текстом программы, то есть если точка с запятой всё же будет поставлена, текст программы будет всегда содержать вместо макроконстанты число и точку с запятой, что может в корне изменить смысл программы.}
|
||||||
Весьма удобно, но этим можно не ограничиваться, мы можем попросить компилятор заменить вызовы функций и операторы на короткие, удобные нам слова. Важно помнить, что директивы препроцессора работают с текстом программы, поэтому не осуществляют никаких дополнительных проверок. Это сложный и мощный инструмент, который чаще всего используется для решения нетривиальных задач, например, выбор кода, который попадёт в компиляцию в зависимости от операционной системы. Иногда в программах можно встретить описание недостающего, но такого привычного булева типа при помощи директив препроцессора:
|
Весьма удобно, но этим можно не ограничиваться, мы можем попросить компилятор заменить вызовы функций и операторы на короткие, удобные нам слова. Важно помнить, что директивы препроцессора работают с текстом программы, поэтому не осуществляют никаких дополнительных проверок. Это сложный и мощный инструмент, который чаще всего используется для решения нетривиальных задач, например, выбор кода, который попадёт в компиляцию в зависимости от операционной системы. Иногда в программах можно встретить описание недостающего, но такого привычного булева типа при помощи директив препроцессора:
|
||||||
|
|
||||||
|
\begin{figure}[H]
|
||||||
\begin{lstlisting}[language=C,style=CCodeStyle]
|
\begin{lstlisting}[language=C,style=CCodeStyle]
|
||||||
#define bool int
|
#define bool int
|
||||||
#define true 1
|
#define true 1
|
||||||
#define false 0
|
#define false 0
|
||||||
\end{lstlisting}
|
\end{lstlisting}
|
||||||
|
\end{figure}
|
||||||
Но нам пока что достаточно умения создать глобальную именованную константу. Код ниже демонстрирует, что директивы не обязательно группировать именно в начале файла, а можно использовать там, где это удобно и уместно, так мы можем объявить константу с длиной массива в начале файла, а можем прямо внутри функции \code{int main (int argc, char *argv[])}.
|
Но нам пока что достаточно умения создать глобальную именованную константу. Код ниже демонстрирует, что директивы не обязательно группировать именно в начале файла, а можно использовать там, где это удобно и уместно, так мы можем объявить константу с длиной массива в начале файла, а можем прямо внутри функции \code{int main (int argc, char *argv[])}.
|
||||||
\begin{lstlisting}[language=C,style=CCodeStyle]
|
\begin{lstlisting}[language=C,style=CCodeStyle]
|
||||||
int main(int argc, char* argv[]) {
|
int main(int argc, char* argv[]) {
|
||||||
|
@ -261,7 +264,7 @@ float average(int* array, int length) {
|
||||||
|
|
||||||
Попробуем визуализировать двумерный массив. Создадим двумерный массив в коде, например, 5х5 элементов. Массив 5х5 – это 5 столбцов и 5 строчек. Соответственно, \textit{каждая строчка – это будет у нас младший индекс, а каждый столбец – старший индекс}. Трехмерный массив может быть, например, 3х3х3 – его можно визулизировать как всем известный кубик Рубика то есть, это три стоящих друг за другом таблицы 3х3. Также опишем его в коде ниже. Получается, что мы к таблице (ширине и высоте) добавили третье \textbf{измерение}, поэтому и массив получается \textbf{многомерным}, в данном случае, \textbf{трёхмерным}. Массивы б\'{о}льших размерностей тоже можно встретить в программах, но значительно реже, только лишь потому, что их действительно немного сложнее представить себе.
|
Попробуем визуализировать двумерный массив. Создадим двумерный массив в коде, например, 5х5 элементов. Массив 5х5 – это 5 столбцов и 5 строчек. Соответственно, \textit{каждая строчка – это будет у нас младший индекс, а каждый столбец – старший индекс}. Трехмерный массив может быть, например, 3х3х3 – его можно визулизировать как всем известный кубик Рубика то есть, это три стоящих друг за другом таблицы 3х3. Также опишем его в коде ниже. Получается, что мы к таблице (ширине и высоте) добавили третье \textbf{измерение}, поэтому и массив получается \textbf{многомерным}, в данном случае, \textbf{трёхмерным}. Массивы б\'{о}льших размерностей тоже можно встретить в программах, но значительно реже, только лишь потому, что их действительно немного сложнее представить себе.
|
||||||
\begin{figure}[h!]
|
\begin{figure}[h!]
|
||||||
|
\setlength{\columnsep}{30pt}
|
||||||
\begin{multicols}{2}
|
\begin{multicols}{2}
|
||||||
\begin{lstlisting}[language=C,style=CCodeStyle]
|
\begin{lstlisting}[language=C,style=CCodeStyle]
|
||||||
int twoDimensional[5][5];
|
int twoDimensional[5][5];
|
||||||
|
@ -288,7 +291,7 @@ int twoDimensional[5][5];
|
||||||
\begin{lstlisting}[language=C,style=CCodeStyle]
|
\begin{lstlisting}[language=C,style=CCodeStyle]
|
||||||
int threeDimensional[3][3][3];
|
int threeDimensional[3][3][3];
|
||||||
\end{lstlisting}
|
\end{lstlisting}
|
||||||
|
\centering
|
||||||
\begin{tikzpicture}[every node/.style={minimum size=1cm},on grid]
|
\begin{tikzpicture}[every node/.style={minimum size=1cm},on grid]
|
||||||
\begin{scope}[every node/.append style={yslant=-0.5},yslant=-0.5]
|
\begin{scope}[every node/.append style={yslant=-0.5},yslant=-0.5]
|
||||||
\node at (0.5,2.5) {2,0,0};
|
\node at (0.5,2.5) {2,0,0};
|
||||||
|
@ -321,9 +324,9 @@ int threeDimensional[3][3][3];
|
||||||
\node at (4.5,2.5) {2,0,1};
|
\node at (4.5,2.5) {2,0,1};
|
||||||
\node at (4.5,1.5) {1,0,1};
|
\node at (4.5,1.5) {1,0,1};
|
||||||
\node at (4.5,0.5) {0,0,1};
|
\node at (4.5,0.5) {0,0,1};
|
||||||
\node at (5.5,2.5) {2,1,2};
|
\node at (5.5,2.5) {2,0,2};
|
||||||
\node at (5.5,1.5) {1,1,2};
|
\node at (5.5,1.5) {1,0,2};
|
||||||
\node at (5.5,0.5) {0,1,2};
|
\node at (5.5,0.5) {0,0,2};
|
||||||
\draw (3,0) grid (6,3);
|
\draw (3,0) grid (6,3);
|
||||||
\end{scope}
|
\end{scope}
|
||||||
\end{tikzpicture}
|
\end{tikzpicture}
|
||||||
|
@ -367,10 +370,13 @@ for (r = 0; r < rows; r++) {
|
||||||
Запустив нашу программу с формированием таблицы умножения увидим, что все отлично работает. Полный листинг программы приводить не целесообразно, поскольку это цикл с заполнением и цикл с выводом, полностью привед§нные выше. К тому же, такой код носит исключительно академический характер, и в случае действительной необходимости формирования таблицы Пифагора на экране промежуточное заполнение массива будет излишним, результат умножения целесообразнее сразу выводить на экран.
|
Запустив нашу программу с формированием таблицы умножения увидим, что все отлично работает. Полный листинг программы приводить не целесообразно, поскольку это цикл с заполнением и цикл с выводом, полностью привед§нные выше. К тому же, такой код носит исключительно академический характер, и в случае действительной необходимости формирования таблицы Пифагора на экране промежуточное заполнение массива будет излишним, результат умножения целесообразнее сразу выводить на экран.
|
||||||
|
|
||||||
Как уже говорилось, все массивы могут содержать данные любых типов, в том числе и указатели. Именно это позволяет массиву хранить другие массивы, строки и прочие ссылочные типы данных. Используя массивы указателей, мы можем создать, например, массив строк.
|
Как уже говорилось, все массивы могут содержать данные любых типов, в том числе и указатели. Именно это позволяет массиву хранить другие массивы, строки и прочие ссылочные типы данных. Используя массивы указателей, мы можем создать, например, массив строк.
|
||||||
|
|
||||||
|
\begin{figure}[H]
|
||||||
\begin{lstlisting}[language=C,style=CCodeStyle]
|
\begin{lstlisting}[language=C,style=CCodeStyle]
|
||||||
char* stringArray[3] = {"Hello", "C", "World"};
|
char* stringArray[3] = {"Hello", "C", "World"};
|
||||||
int r;
|
int r;
|
||||||
for (r = 0; r < 3; r++)
|
for (r = 0; r < 3; r++)
|
||||||
printf("%s ", stringArray[r]);
|
printf("%s ", stringArray[r]);
|
||||||
\end{lstlisting}
|
\end{lstlisting}
|
||||||
|
\end{figure}
|
||||||
Это указатели на строки, а точнее, на строковые литералы. Такой тип данных (строковый литерал) является указателем. И мы можем создать из этих указателей массив. Используя массивы указателей, мы можем создать, например, двумерный массив, где каждый элемент не обязан быть того же размера, что и остальные (но обязан быть того же типа, как мы помним). Но строки и сложно составленные указатели - это темы, которые очень сильно выходят за рамки Основ языка, хотя, конечно, это не помешает нам немного подробнее разобраться со строками в следующем разделе.
|
Это указатели на строки, а точнее, на строковые литералы. Такой тип данных (строковый литерал) является указателем. И мы можем создать из этих указателей массив. Используя массивы указателей, мы можем создать, например, двумерный массив, где каждый элемент не обязан быть того же размера, что и остальные (но обязан быть того же типа, как мы помним). Но строки и сложно составленные указатели - это темы, которые очень сильно выходят за рамки Основ языка, хотя, конечно, это не помешает нам немного подробнее разобраться со строками в следующем разделе.
|
||||||
|
|
|
@ -153,6 +153,8 @@ int main(int argc, const char* argv[]) {
|
||||||
\frm{В некоторых случаях может показаться, что никакой проблемы нет, поскольку написанная таким образом программа благополучно поприветствует пользователя, но такое поведение не гарантируется ни одним компилятором и ни одной операционной системой, поскольку возвращаемый таким образом указатель может быть переписан абсолютно любой следующей инструкцией кода. Такое \textit{исчезающее} значение называется \textbf{xvalue}.}
|
\frm{В некоторых случаях может показаться, что никакой проблемы нет, поскольку написанная таким образом программа благополучно поприветствует пользователя, но такое поведение не гарантируется ни одним компилятором и ни одной операционной системой, поскольку возвращаемый таким образом указатель может быть переписан абсолютно любой следующей инструкцией кода. Такое \textit{исчезающее} значение называется \textbf{xvalue}.}
|
||||||
Выход очень простой: раз указатель не идёт в \code{int main (int argc, char *argv[])}, надо чтобы \code{int main (int argc, char *argv[])} дал нам указатель. Добавим в параметры функции указатель на выходную строку, и напишем что для начала сложить строки и положить в локальный массив \code{strcat(welcome, name)}. Добавим в основную функцию массив \code{char result[]}, который будет хранить результат и передадим в функцию \code{helloFunction} аргументы \code{name} и \code{result}. А раз функция больше ничего не возвращает, вполне легально сделать её \code{void}.
|
Выход очень простой: раз указатель не идёт в \code{int main (int argc, char *argv[])}, надо чтобы \code{int main (int argc, char *argv[])} дал нам указатель. Добавим в параметры функции указатель на выходную строку, и напишем что для начала сложить строки и положить в локальный массив \code{strcat(welcome, name)}. Добавим в основную функцию массив \code{char result[]}, который будет хранить результат и передадим в функцию \code{helloFunction} аргументы \code{name} и \code{result}. А раз функция больше ничего не возвращает, вполне легально сделать её \code{void}.
|
||||||
|
|
||||||
|
|
||||||
|
\begin{figure}[H]
|
||||||
\begin{lstlisting}[language=C,style=CCodeStyle]
|
\begin{lstlisting}[language=C,style=CCodeStyle]
|
||||||
void helloFunction(char* name, char* out) {
|
void helloFunction(char* name, char* out) {
|
||||||
char welcome[255] = "Hello, ";
|
char welcome[255] = "Hello, ";
|
||||||
|
@ -170,6 +172,7 @@ int main(int argc, const char* argv[]) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
\end{lstlisting}
|
\end{lstlisting}
|
||||||
|
\end{figure}
|
||||||
|
|
||||||
Запускаем, и \textbf{снова не работает}, да ещё и как интересно, смотрите! Предупреждение, ладно, понятно, мы о нём говорили, но дальше, когда мы вводим имя на выходе получается какая-то совсем уж непонятная строчка, совсем не похожая на приветствие.
|
Запускаем, и \textbf{снова не работает}, да ещё и как интересно, смотрите! Предупреждение, ладно, понятно, мы о нём говорили, но дальше, когда мы вводим имя на выходе получается какая-то совсем уж непонятная строчка, совсем не похожая на приветствие.
|
||||||
\begin{verbatim}
|
\begin{verbatim}
|
||||||
|
|
|
@ -24,6 +24,8 @@ struct fraction {
|
||||||
};
|
};
|
||||||
\end{lstlisting}
|
\end{lstlisting}
|
||||||
Для сокращения записи опишем новый тип данных, назовём его \textbf{дробь}. Далее будут приведены два равнозначных способа сокращения записи структур: первый способ создаёт псевдоним для уже существующей структуры, а второй создаёт псевдоним для структуры прямо в момент её описания, поэтому и саму структуру можно не называть, а обращаться к ней только через псевдоним:
|
Для сокращения записи опишем новый тип данных, назовём его \textbf{дробь}. Далее будут приведены два равнозначных способа сокращения записи структур: первый способ создаёт псевдоним для уже существующей структуры, а второй создаёт псевдоним для структуры прямо в момент её описания, поэтому и саму структуру можно не называть, а обращаться к ней только через псевдоним:
|
||||||
|
|
||||||
|
\begin{figure}[H]
|
||||||
\begin{lstlisting}[language=C,style=CCodeStyle]
|
\begin{lstlisting}[language=C,style=CCodeStyle]
|
||||||
// alias for existing struct
|
// alias for existing struct
|
||||||
typedef struct fraction Fraction;
|
typedef struct fraction Fraction;
|
||||||
|
@ -35,6 +37,7 @@ typedef struct {
|
||||||
int den; // denominator
|
int den; // denominator
|
||||||
} Fraction;
|
} Fraction;
|
||||||
\end{lstlisting}
|
\end{lstlisting}
|
||||||
|
\end{figure}
|
||||||
|
|
||||||
Обычно доступ к переменным внутри структуры осуществляется привычным для высокоуровневых языков способом - через точку. Есть одно исключение, но об этом чуть позже. Создадим три переменных для хранения двух дробей, с которыми будем совершать операции, и одну для хранения результата. Инициализируем переменные какими-нибудь значениями. Опишем целочисленные значения, опишем делимое для обеих дробей и опишем делитель для обеих дробей. Для простоты будем использовать простые дроби: \( 1\frac{1}{5} \) и \( -1\frac{1}{5} \).
|
Обычно доступ к переменным внутри структуры осуществляется привычным для высокоуровневых языков способом - через точку. Есть одно исключение, но об этом чуть позже. Создадим три переменных для хранения двух дробей, с которыми будем совершать операции, и одну для хранения результата. Инициализируем переменные какими-нибудь значениями. Опишем целочисленные значения, опишем делимое для обеих дробей и опишем делитель для обеих дробей. Для простоты будем использовать простые дроби: \( 1\frac{1}{5} \) и \( -1\frac{1}{5} \).
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue