diff --git a/book-preamble.tex b/book-preamble.tex new file mode 100644 index 0000000..9f5a586 --- /dev/null +++ b/book-preamble.tex @@ -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} diff --git a/build/main.pdf b/build/main.pdf index dd2d8af..a161719 100644 Binary files a/build/main.pdf and b/build/main.pdf differ diff --git a/common-preamble.tex b/common-preamble.tex new file mode 100755 index 0000000..a6f5606 --- /dev/null +++ b/common-preamble.tex @@ -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}} diff --git a/fancy-listings-preamble.tex b/fancy-listings-preamble.tex new file mode 100644 index 0000000..0eb9f8a --- /dev/null +++ b/fancy-listings-preamble.tex @@ -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={<@}{@>}} diff --git a/formatting.tex b/formatting.tex deleted file mode 100644 index 3363ad4..0000000 --- a/formatting.tex +++ /dev/null @@ -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% -}% diff --git a/main.tex b/main.tex index b6b1e75..8b87ae8 100644 --- a/main.tex +++ b/main.tex @@ -1,6 +1,6 @@ -\documentclass[a4paper]{article} -\usepackage[russian]{babel} -\include{formatting} +\documentclass[fontsize=14bp]{article} +\input{common-preamble} +\input{book-preamble} \begin{document} \maketitle @@ -35,7 +35,7 @@ \import{sections/}{12-files} \section{Распределение памяти} -Этот раздел находится в конце книги, но не по важности. Сильная сторона языка С (и, как следствие, С++) не только в возможности работать с указателями, но и в возможности самостоятельно управлять выделяемой памятью внутри программы. В языках высокого уровня данная возможность зачастую скрыта от программиста, чтобы по случайности программа не привела к зависанию среды виртуализации, по неосторожности не попыталась воспользоваться всей возможной оперативной памятью или не сломала операционную систему. Итак, как мы уже знаем, все переменные всех типов как-то хранятся в памяти, и до этого момента нас устраивало, как операционная система нам эту память выделяет. Но, пришло время взять бразды правления в свои руки. Процесс \textbf{выделения памяти} для программы называется \textbf{memory allocation}, отсюда и название функции, которая выделяет память и пишет в предложенный идентификатор указатель на начало этой области. +Этот раздел находится в конце документа, но не по важности. Сильная сторона языка С (и, как следствие, С++) не только в возможности работать с указателями, но и в возможности самостоятельно управлять выделяемой памятью внутри программы. В языках высокого уровня данная возможность зачастую скрыта от программиста, чтобы по случайности программа не привела к зависанию среды виртуализации, по неосторожности не попыталась воспользоваться всей возможной оперативной памятью или не сломала операционную систему. Итак, как мы уже знаем, все переменные всех типов как-то хранятся в памяти, и до этого момента нас устраивало, как операционная система нам эту память выделяет. Но, пришло время взять бразды правления в свои руки. Процесс \textbf{выделения памяти} для программы называется \textbf{memory allocation}, отсюда и название функции, которая выделяет память и пишет в предложенный идентификатор указатель на начало этой области. \subsection{\code{void* malloc(size);}} Функция \code{void* malloc(size);} принимает в качестве аргумента размер выделяемой памяти. Как видим, функция возвращает довольно необычный на первый взгляд тип: \code{void*}, то есть область памяти будет зафиксирована, но не размечена. То есть это будет просто некоторая пустая область из \code{size} байт. diff --git a/sections/04-variables.tex b/sections/04-variables.tex index a331b8a..d4a6e4a 100644 --- a/sections/04-variables.tex +++ b/sections/04-variables.tex @@ -4,19 +4,19 @@ Переменные делятся на целочисленные, символьные, указатели и числа с плавающей точкой (англ. floating point, дробное число). Все, кроме указателей и символьных переменных бывают как знаковыми так и беззнаковыми. То есть в знаковых самый старший бит в двоичной записи этих переменных отводится под определение, является ли число отрицательным, или положительным, в беззнаковых все биты используются для записи числа, что увеличивает его диапазон возможных значений, но позволяет записать только положительные числа. В классическом С нет булевого типа, вместо него используется целое число и значения нуля для \textbf{лжи} и \textit{любое} другое число для \textbf{истины}, обычно это единица. Об указателях и булевой алгебре мы будем подробно говорить в одном из последующих разделов. \begin{figure}[h!] \centering - \begin{tabular}{|p{1.5cm}|p{6.6cm}|p{2.4cm}|} + \begin{tabular}{|p{15mm}|p{65mm}|p{25mm}|} \hline Тип & Пояснение & Спецификатор формата \\ \hline char & Целочисленный, самый маленький из адресуемых типов, диапазон: [\textminus128, +127] & \%c \\ \hline - short\newline short int & Тип короткого целого числа со знаком, диапазон: [\textminus32 768, +32 767] & \%hi \\ + short\newline short int & Тип короткого целого числа со знаком, диапазон:\newline[\textminus32 768, +32 767] & \%hi \\ \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 - 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 - 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 float & Тип вещественного числа с плавающей запятой (одинарной точности) & \%f (автоматически преобразуется в double для printf()) \\ \hline @@ -363,7 +363,7 @@ a = a ^ b; //00001111 \end{figure} Применять бинарную алгебру можно и в больших проектах, работающих со сложными высокоуровневыми абстракциями. Помимо этого важно помнить, что поддержка бинарных операций есть в подавляющем числе языков программирования. Используя бинарную алгебру можно создавать оптимальные протоколы передачи данных и/или алгоритмы хранения и обработки. -\begin{figure}[h!] +\begin{figure}[H] \begin{verbatim} $ ./program a = 15 diff --git a/sections/07-functions.tex b/sections/07-functions.tex index 13312f6..2c3ff44 100644 --- a/sections/07-functions.tex +++ b/sections/07-functions.tex @@ -84,48 +84,53 @@ $ Теперь мы без проблем можем оформить уже существующие у нас программы в виде функций. Например, оформим в виде функции программу проверки простоты числа. Для этого опишем функцию которая возвращает целое число, назовем ее \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] - + +\begin{figure}[H] + \setlength{\columnsep}{22pt} + \begin{multicols}{2} + \begin{lstlisting}[language=C,style=CCodeStyle] int isPrime(int number){ - int dividers = 0, i = 1; + + int dividers = 0, i = 1; - while(i <= number){ - if(number % i++ ==0) - dividers++; - else - continue; + while(i <= number){ + if(number % i++ ==0) + dividers++; + else + continue; - if (dividers == 3) - return 0; - } - return (dividers == 2) + if (dividers == 3) + return 0; + } + return (dividers == 2) } -\end{lstlisting} -\columnbreak -\begin{lstlisting}[language=C,style=CCodeStyle] + \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; + int number; + int dividers = 0, i = 1; + printf("Enter number: "); + scanf("%d", &number); + while (i <= number) { + if (number++ % i == 0) { + dividers++; + } else { + continue; } - printf("Number %d is%s prime", - number, - (dividers == 2) ? "" : " not" - ); + if (dividers == 3) + break; + } + printf("Number %d is%s prime", + number, + (dividers == 2) ? "" : " not" + ); } -\end{lstlisting} + \end{lstlisting} \end{multicols} +\end{figure} +%\setlength{\columnsep}{10pt} Немного подправив вывод, внесем в него вызов функции \code{isPrime()} и объявим переменную \code{int num}, которую будем передавать в качестве аргумента в функцию \code{isPrime()}. Запустим нашу программу и убедимся что все работает – число 71 действительно является простым. \begin{figure}[h!] diff --git a/sections/08-pointers.tex b/sections/08-pointers.tex index ec95668..3f875a8 100644 --- a/sections/08-pointers.tex +++ b/sections/08-pointers.tex @@ -52,9 +52,13 @@ value of 'pointer' is 000000000061FE1C \frm{Для языка С также справедливо выражение <<передача по ссылке>>, поскольку в языке С нет отдельной операции передачи по ссылке. Так, например, в языке С++ передача по ссылке и передача по указателю - это разные операции.} То есть функция будет ссылаться на переменные, на которые мы укажем и оперировать их значениями. Давайте немного модифицируем нашу программу обмена значениями внутри двух переменных (\hyperref[code:programswap]{\ref{code:programswap}}): опишем её в виде функции, принимающей в качестве параметров два указателя на целые числа типа \code{char}, и передадим адреса созданных в \code{int main (int argc, char *argv[])} переменных. Внутри функции, при её вызове, у нас будут создаваться не переменные, а указатели на переменные, то есть мы будем ссылаться на те самые переменные, созданные вне функции, и будем менять именно их (тех переменных) значения. Таким образом, нам не нужно ничего возвращать, потому что в функции ничего не создавалось, и типом возвращаемого значения функции должен быть \code{void}. -\begin{multicols}{2} - \lstinputlisting[language=C,style=CCodeStyle]{../sources/swapfunc.c} -\columnbreak - \lstinputlisting[language=C,style=CCodeStyle]{../sources/swapprog.c} -\end{multicols} + +\begin{figure}[H] + \setlength{\columnsep}{30pt} + \begin{multicols}{2} + \lstinputlisting[language=C,style=CCodeStyle]{../sources/swapfunc.c} + \columnbreak + \lstinputlisting[language=C,style=CCodeStyle]{../sources/swapprog.c} + \end{multicols} +\end{figure} Применение такого подхода открывает перед нами широкие возможности. Важно, на схеме со стр. \pageref{fig:dereference}, что указатель - это тоже переменная, поэтому мы можем создавать указатели на указатели, и так далее, указатели любой сложности, тем самым увеличивая уровень абстракции программы. diff --git a/sections/09-arrays.tex b/sections/09-arrays.tex index d6d7ec8..bf78e45 100644 --- a/sections/09-arrays.tex +++ b/sections/09-arrays.tex @@ -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{макроконстантой}. \frm{Обратите внимание, что директива пишется немного не так, как обычный оператор языка, хоть и может находиться в любом месте кода. В конце директивы не ставится точка с запятой. Это важно именно потому что директивы работают с текстом программы, то есть если точка с запятой всё же будет поставлена, текст программы будет всегда содержать вместо макроконстанты число и точку с запятой, что может в корне изменить смысл программы.} Весьма удобно, но этим можно не ограничиваться, мы можем попросить компилятор заменить вызовы функций и операторы на короткие, удобные нам слова. Важно помнить, что директивы препроцессора работают с текстом программы, поэтому не осуществляют никаких дополнительных проверок. Это сложный и мощный инструмент, который чаще всего используется для решения нетривиальных задач, например, выбор кода, который попадёт в компиляцию в зависимости от операционной системы. Иногда в программах можно встретить описание недостающего, но такого привычного булева типа при помощи директив препроцессора: -\begin{lstlisting}[language=C,style=CCodeStyle] + +\begin{figure}[H] + \begin{lstlisting}[language=C,style=CCodeStyle] #define bool int #define true 1 #define false 0 -\end{lstlisting} + \end{lstlisting} +\end{figure} Но нам пока что достаточно умения создать глобальную именованную константу. Код ниже демонстрирует, что директивы не обязательно группировать именно в начале файла, а можно использовать там, где это удобно и уместно, так мы можем объявить константу с длиной массива в начале файла, а можем прямо внутри функции \code{int main (int argc, char *argv[])}. \begin{lstlisting}[language=C,style=CCodeStyle] 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{трёхмерным}. Массивы б\'{о}льших размерностей тоже можно встретить в программах, но значительно реже, только лишь потому, что их действительно немного сложнее представить себе. \begin{figure}[h!] - +\setlength{\columnsep}{30pt} \begin{multicols}{2} \begin{lstlisting}[language=C,style=CCodeStyle] int twoDimensional[5][5]; @@ -288,7 +291,7 @@ int twoDimensional[5][5]; \begin{lstlisting}[language=C,style=CCodeStyle] int threeDimensional[3][3][3]; \end{lstlisting} - +\centering \begin{tikzpicture}[every node/.style={minimum size=1cm},on grid] \begin{scope}[every node/.append style={yslant=-0.5},yslant=-0.5] \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,1.5) {1,0,1}; \node at (4.5,0.5) {0,0,1}; - \node at (5.5,2.5) {2,1,2}; - \node at (5.5,1.5) {1,1,2}; - \node at (5.5,0.5) {0,1,2}; + \node at (5.5,2.5) {2,0,2}; + \node at (5.5,1.5) {1,0,2}; + \node at (5.5,0.5) {0,0,2}; \draw (3,0) grid (6,3); \end{scope} \end{tikzpicture} @@ -367,10 +370,13 @@ for (r = 0; r < rows; r++) { Запустив нашу программу с формированием таблицы умножения увидим, что все отлично работает. Полный листинг программы приводить не целесообразно, поскольку это цикл с заполнением и цикл с выводом, полностью привед§нные выше. К тому же, такой код носит исключительно академический характер, и в случае действительной необходимости формирования таблицы Пифагора на экране промежуточное заполнение массива будет излишним, результат умножения целесообразнее сразу выводить на экран. Как уже говорилось, все массивы могут содержать данные любых типов, в том числе и указатели. Именно это позволяет массиву хранить другие массивы, строки и прочие ссылочные типы данных. Используя массивы указателей, мы можем создать, например, массив строк. -\begin{lstlisting}[language=C,style=CCodeStyle] -char* stringArray[3] = {"Hello", "C", "World"}; -int r; -for (r = 0; r < 3; r++) + +\begin{figure}[H] + \begin{lstlisting}[language=C,style=CCodeStyle] + char* stringArray[3] = {"Hello", "C", "World"}; + int r; + for (r = 0; r < 3; r++) printf("%s ", stringArray[r]); -\end{lstlisting} + \end{lstlisting} +\end{figure} Это указатели на строки, а точнее, на строковые литералы. Такой тип данных (строковый литерал) является указателем. И мы можем создать из этих указателей массив. Используя массивы указателей, мы можем создать, например, двумерный массив, где каждый элемент не обязан быть того же размера, что и остальные (но обязан быть того же типа, как мы помним). Но строки и сложно составленные указатели - это темы, которые очень сильно выходят за рамки Основ языка, хотя, конечно, это не помешает нам немного подробнее разобраться со строками в следующем разделе. diff --git a/sections/10-strings.tex b/sections/10-strings.tex index d225ce4..b6f1f20 100644 --- a/sections/10-strings.tex +++ b/sections/10-strings.tex @@ -153,23 +153,26 @@ int main(int argc, const char* argv[]) { \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}. -\begin{lstlisting}[language=C,style=CCodeStyle] -void helloFunction(char* name, char* out) { - char welcome[255] = "Hello, "; - strcat(welcome, name); - out = welcome; -} -int main(int argc, const char* argv[]) { - char name[256]; - char result[256]; - gets(name); +\begin{figure}[H] + \begin{lstlisting}[language=C,style=CCodeStyle] + void helloFunction(char* name, char* out) { + char welcome[255] = "Hello, "; + strcat(welcome, name); + out = welcome; + } - helloFunction(name, result); - puts(result); - return 0; -} -\end{lstlisting} + int main(int argc, const char* argv[]) { + char name[256]; + char result[256]; + gets(name); + + helloFunction(name, result); + puts(result); + return 0; + } + \end{lstlisting} +\end{figure} Запускаем, и \textbf{снова не работает}, да ещё и как интересно, смотрите! Предупреждение, ладно, понятно, мы о нём говорили, но дальше, когда мы вводим имя на выходе получается какая-то совсем уж непонятная строчка, совсем не похожая на приветствие. \begin{verbatim} diff --git a/sections/11-structs.tex b/sections/11-structs.tex index 9089d81..5490455 100644 --- a/sections/11-structs.tex +++ b/sections/11-structs.tex @@ -24,17 +24,20 @@ struct fraction { }; \end{lstlisting} Для сокращения записи опишем новый тип данных, назовём его \textbf{дробь}. Далее будут приведены два равнозначных способа сокращения записи структур: первый способ создаёт псевдоним для уже существующей структуры, а второй создаёт псевдоним для структуры прямо в момент её описания, поэтому и саму структуру можно не называть, а обращаться к ней только через псевдоним: -\begin{lstlisting}[language=C,style=CCodeStyle] -// alias for existing struct -typedef struct fraction Fraction; -// alias-defined structure -typedef struct { - int nat; // natural (integer) - int num; // numerator - int den; // denominator -} Fraction; -\end{lstlisting} +\begin{figure}[H] + \begin{lstlisting}[language=C,style=CCodeStyle] + // alias for existing struct + typedef struct fraction Fraction; + + // alias-defined structure + typedef struct { + int nat; // natural (integer) + int num; // numerator + int den; // denominator + } Fraction; + \end{lstlisting} +\end{figure} Обычно доступ к переменным внутри структуры осуществляется привычным для высокоуровневых языков способом - через точку. Есть одно исключение, но об этом чуть позже. Создадим три переменных для хранения двух дробей, с которыми будем совершать операции, и одну для хранения результата. Инициализируем переменные какими-нибудь значениями. Опишем целочисленные значения, опишем делимое для обеих дробей и опишем делитель для обеих дробей. Для простоты будем использовать простые дроби: \( 1\frac{1}{5} \) и \( -1\frac{1}{5} \).