
\chapter{Функции и структура программы}
\label{chapt:functions_and_program_structure}

\index{модульность}%
Функции подразделяют большие вычислительные задачи на более мелкие и позволяют
воспользоваться тем, что уже сделано другими разработчиками, а не начинать
создание программы каждый раз <<с нуля>>. В выбранных должным образом функциях
<<упрятаны>> несущественные для других частей программы детали их
функционирования, что делает программу в целом более ясной и облегчает внесение
в неё изменений.

Язык проектировался так, чтобы функции были эффективными и простыми в
использовании. Обычно программы на Си состоят из большого числа небольших
функций, а не из немногих больших. Программу можно располагать в одном или
нескольких исходных файлах.
\index{компиляция!раздельная}%
Эти файлы можно компилировать отдельно, а загружать вместе, в том числе и с
ранее откомпилированными
\index{библиотечная функция}%
библиотечными функциями. Процесс загрузки здесь не рассматривается поскольку он
различен в разных системах.

Описание и определение функции -- это та область, где стандартом ANSI в язык
внесены самые существенные изменения. Как мы видели в
гл.~\ref{chapt:tutorial_intro}, в описании функции теперь разрешено задавать
типы аргументов. Синтаксис определения функции также изменён, так что теперь
описания и определения функций соответствуют друг другу. Это позволяет
компилятору обнаруживать много больше ошибок, чем раньше. Кроме того, если типы
аргументов соответствующим образом описаны, то необходимые преобразования
аргументов выполняются автоматически.

Стандарт вносит ясность в правила, определяющие области действия имён; в
частности, он требует, чтобы для каждого внешнего объекта было только одно
определение. В нём обобщены средства инициализации: теперь можно
инициализировать автоматические массивы и структуры.

Улучшен также препроцессор Си. Он включает более широкий набор директив условной
компиляции, предоставляет возможность из макроаргументов генерировать стринги в
кавычках, а кроме того, содержит более совершенный механизм управления процессом
макрорасширения.

\section{Основные сведения о функциях}
\label{sec:functions_basics}

\index{программа!поиска!по образцу}%
Начнём с того, что сконструируем программу, печатающую те строки вводимого
текста, в которых содержится некоторый <<образец>>, заданный в виде стринга
литер. (Эта программа представляет собой частный случай функции \verb|grep|
системы UNIX.) Рассмотрим пример: в результате поиска образца \verb|"ould"| в
строках текста

\begin{ShortCodePar}
Ah Love! could you and I with Fate conspire
To grasp this sorry Scheme of Things entire,
Would not we shatter it to bits -- and then
Re-mould it nearer to the Heart's Desire!
\end{ShortCodePar}

\noindent мы получим

\begin{ShortCodePar}
Ah Love! could you and I with Fate conspire
Would not we shatter it to bits -- and then
Re-mould it nearer to the Heart's Desire!
\end{ShortCodePar}

\noindent Работа по поиску образца чётко распадается на три этапа:

\begin{ShortCodeParWithCC}{\\\{\}}
while (\textit{существует ещё строка})
    if (\textit{строка содержит образец})
        \textit{напечатать её}
\end{ShortCodeParWithCC}

Хотя все три составляющие процесса поиска можно поместить в функцию \verb|main|,
всё же лучше сохранить приведённую структуру и каждую её часть реализовать в
виде отдельной функции.
\index{сокрытие информации}%
Легче иметь дело с тремя небольшими частями, чем с одной большой, поскольку,
если несущественные особенности реализации скрыты в функциях, вероятность их
нежелательного воздействия друг на друга минимальна. Кроме того, оформленные в
виде функций соответствующие части могут оказаться полезными и в других
программах.

Конструкция <<\verb|while (|\textit{существует ещё строка}\verb|)|>>
реализована в \verb|getline|, см. гл.~\ref{chapt:tutorial_intro}, а фразу
<<\textit{напечатать её}>> можно записать с помощью готовой функции
\verb|printf|. Таким образом, нам остаётся перевести на Си только то, что
определяет, входит ли заданный образец в строку.

\index{функция!strindex@\texttt{strindex}}%
Чтобы решить эту задачу, мы напишем функцию \verb|strindex(s,t)|‚ которая
указывает место (индекс) в строке \verb|s|, где начинается строка \verb|t|, или
$-1$‚ если \verb|s| не содержит \verb|t|. Так как в Си нумерация элементов в
массивах начинается с нуля, отрицательное число $-1$ подходит в качестве сигнала
неудачного поиска. Если далее нам потребуется более сложное отождествление по
образцу, мы просто заменим \verb|strindex| на другую функцию, оставив при этом
остальную часть программы без изменений. (Библиотечная функция \verb|strstr|
аналогична функции \verb|strindex| и отличается от последней только тем, что
выдаёт указатель, а не индекс.)

\index{программа!поиска!по образцу}%
После такого проектирования программы её <<деталировка>> оказывается очевидной.
Мы имеем представление о программе в целом и знаем, как взаимодействуют её
части. В нашей программе образец для поиска задаётся стрингом-литералом, что
снижает её универсальность. В гл.~\ref{chapt:pointers_and_arrays} мы ещё
вернёмся к проблеме инициализации литерных массивов и покажем, как образец
сделать параметром, устанавливаемым при запуске программы.
\index{функция!getline@\texttt{getline}}%
Здесь приведена несколько изменённая версия функции \verb|getline|‚ и было бы
поучительно сравнить её с версией, рассмотренной в
гл.~\ref{chapt:tutorial_intro}.

\begin{LongCodePar}
#include <stdio.h>
#define MAXLINE 1000 /* макс-ный размер вводимой строки */
int getline(char line[], int max);
int strindex(char sourse[], char searchfor[]);
char pattern[] = "ould"; /* образец для поиска */

/* найти все строки, содержащие образец */
main()
{
    char line[MAXLINE];
    int found = 0;
    while (getline(line, MAXLINE) > 0)
        if (strindex(line, pattern) >= 0) {
            printf("%s", line);
            found++;
        }
    return found;
}

/* getline: читает строку в s, возвращает длину */
int getline(char s[], int lim)
{
    int c, i;
    i = 0;
    while (--lim > 0 && (c=getchar()) != EOF && c != '\n')
        s[i++] = c;
    if (c == '\n')
        s[i++] = c;
    s[i] = '\0';
    return i;
}

/* strindex: вычисляет место t в s
   или выдаёт -1, если  t  нет в s */
int strindex(char s[], char t[])
{
    int i, j, k;
    for (i = 0; s[i] != '\0'; i++) {
        for (j=i, k=0; t[k]!='\0' && s[j]==t[k]; j++, k++)
            ;
        if (k > 0 && t[k] == '\0')
            return i;
    }
    return -1;
}
\end{LongCodePar}

\index{определение!функции}%
\index{функция!определение}%
Определение любой функции имеет следующий вид:

\begin{ShortCodeParWithCC}{\\\[\]}
\textit[тип-результата имя-функции](\textit[декларации-аргументов])
{
    \textit[декларации и инструкции]
}
\end{ShortCodeParWithCC}

\noindent%
\index{функция!пустая}%
Отдельные части определения могут отсутствовать, как, например, в определении
<<минимальной>> функции

\begin{ShortCodePar}
dummy() { }
\end{ShortCodePar}

\noindent которая ничего не вычисляет и ничего не выдаёт. Такая ничего не
делающая функция в процессе разработки программы бывает полезна в качестве
<<хранителя места>>. Если тип результата опущен‚ то предполагается, что функция
возвращает значение типа \verb|int|.

Любая программа -- это просто совокупность определений переменных и функций.
Связи между функциями осуществляются через аргументы, возвращаемые значения и
внешние переменные. В исходном файле функции разрешается располагать в любом
порядке; исходную программу можно разбивать на любое число файлов, но так, чтобы
ни одна из функций не оказалась разрезанной.

\index{return-инструкция@\texttt{return}-инструкция}%
Инструкция \verb|return| реализует механизм возврата результата от вызываемой к
вызывающей функции. За словом \verb|return| может следовать любое выражение:

\begin{ShortCodeParWithCC}{\\\{\}}
return \textit{выражение};
\end{ShortCodeParWithCC}

\noindent Если потребуется, \textit{выражение} будет приведено к типу
\textit{тип-результата}. Часто \textit{выражение} заключают в скобки, но они не
обязательны.

\index{return-инструкция@\texttt{return}-инструкция}%
Вызывающая функция в праве проигнорировать возвращаемое значение. Более того,
\textit{выражение} в \verb|return| может отсутствовать, и тогда вообще никакое
значение не будет возвращено в вызывающую функцию. Управление возвращается в
вызывающую функцию без результирующего значения также и в том случае, когда
вычисления достигли <<конца>> (т.е. последней закрывающей фигурной скобки
функции). Не запрещена (но должна вызывать настороженность) ситуация, когда в
одной и той же функции одни \verb|return| имеют при себе выражения, а другие --
не имеют. Во всех случаях, когда функция <<забыла>> передать результат в
\verb|return|, её значение есть <<мусор>>.

Функция \verb|main| в программе поиска по образцу выдаёт в качестве результата
количество найденных строк. Это число доступно в той среде, из которой данная
программа была вызвана.

\index{компиляция!нескольких файлов}%
Механизмы компиляции и загрузки Си-программ, расположенных в нескольких исходных
файлах, могут различаться разных системах.
\index{cc@\texttt{cc}}%
В системе UNIX, например, эти работы выполняет упомянутая в
гл.~\ref{chapt:tutorial_intro} команда \verb|cc|. Предположим, что три функции
нашего последнего примера расположены в трёх разных файлах: \verb|main.c|,
\verb|getline.c| и \verb|strindex.c|. Тогда команда

\begin{ShortCodePar}
cc main.c getline.c strindex.c
\end{ShortCodePar}

\noindent скомпилирует указанные файлы, поместив результат компиляции в файлы
объектных модулей \verb|main.o|‚ \verb|getline.o| и \verb|strindex.o|,
\index{a.out@\texttt{a.out}}%
и затем загрузит их в исполняемый файл \verb|a.out|. Если обнаружилась ошибка,
например, в \verb|main.c|‚ то его можно скомпилировать снова и результат
загрузить с ранее полученными объектными файлами, выполнив следующую команду:

\begin{ShortCodePar}
cc main.c getline.o strindex.o
\end{ShortCodePar}

\noindent Команда \verb|cc| использует стандартные окончания файлов
<<\verb|.c|>> и <<\verb|.o|>>, чтобы отличать исходные файлы от объектных.

\paragraph{Упражнение 4.1.} Напишите функцию \verb|strrindex(s,t)|, которая
выдаёт позицию \emph{самого правого} вхождения \verb|t| в \verb|s| или $-1$‚
если вхождения не обнаружено.

\section{Функции, возвращающие нецелые значения}

В предыдущих примерах функции либо вообще не возвращали результирующих значений
(\verb|void|), либо возвращали целые значения (\verb|int|). А как быть, когда
результат функции должен иметь другой тип? Многие вычислительные функции, как,
например, \verb|sqrt|‚ \verb|sin| и \verb|cos|, возвращают значения типа
\verb|double|; другие специальные функции могут выдавать значения ещё каких-то
типов.
\index{функция!atof@\texttt{atof}}%
Чтобы проиллюстрировать, каким образом сделать так, чтобы функция возвращала
нецелое значение, напишем функцию \verb|atof(s)|, которая переводит стринг
\verb|s| в соответствующее число с плавающей точкой двойной точности. Функция
\verb|atof| представляет собой расширение функции \verb|atoi|, две версии
которой были рассмотрены в
гл.~\ref{chapt:types-operators-expressions}~и~\ref{chapt:control_flow}. Она
имеет дело со знаком (которого может и не быть), с десятичной точкой, а также с
целой и дробной частями, одна из которых может отсутствовать. Наша версия
\emph{не} является высококачественной программой преобразования вводимых чисел;
такая программа потребовала бы заметно больше памяти.
\index{файл!головной!<stdlib.h>@\texttt{<stdlib.h>}}%
Функция \verb|atof| входит в стандартную библиотеку программ; её описание
содержится в головном файле \verb|<stdlib.h>|.

Прежде всего отметим, что декларировать тип возвращаемого значения должна сама
\verb|atof|, так как этот тип не есть \verb|int|. Указатель типа задаётся перед
именем функции.

\begin{LongCodePar}
#include <ctype.h>
/* atof: преобразование стринга s в double */
double atof(char s[])
{
    double val, power;
    int i, sign;
    for (i = 0; isspace(s[i]); i++)
        ;        /* игнорирование левых пробельных литер */
    sign = (s[i] == '-') ? -1 : 1;
    if (s[i] == '+' || s[i] == '-')
        i++;
    for (val = 0.0; isdigit(s[i]); i++)
        val = 10.0 * val + (s[i] - '0');
    if (s[i] == '.')
        i++;
    for (power = 1.0; isdigit(s[i]); i++) {
        val = 10.0 * val + (s[i] - '0');
        power *= 10.0;
    }
    return sign * val / power;
}
\end{LongCodePar}

Кроме того, важно, чтобы вызывающая программа знала, что \verb|atof| возвращает
нецелое значение. Один из способов обеспечить это -- явно описать \verb|atof| в
вызывающей программе.
\index{программа!калькулятор}%
Подобное описание демонстрируется ниже в программе простенького калькулятора
(достаточного для проверки баланса чековой книжки), который каждую вводимую
строку воспринимает как число, прибавляет его к текущей сумме и печатает её
новое значение.

\begin{LongCodePar}
#include <stdio.h>
#define MAXLINE 100
/* примитивный калькулятор */
main()
{
    double sum, atof(char []);
    char line[MAXLINE];
    int getline(char line[], int max);
    sum = 0;
    while (getline(line, MAXLINE) > 0)
        printf("\t%g\n", sum += atof(line));
    return 0;
}
\end{LongCodePar}

\noindent%
\index{прототип функции}%
\index{функция!прототип}%
В декларации

\begin{ShortCodePar}
double sum, atof(char []);
\end{ShortCodePar}

\noindent говорится, что \verb|sum| -- переменная типа \verb|double|‚ а
\verb|atof| -- функция, которая принимает аргумент (один) типа \verb|char[]| и
возвращает результат типа \verb|double|.

\index{несоответствие типов деклараций}%
\index{тип!несовместимость в декларациях}%
\index{return-инструкция@\texttt{return}-инструкция}%
Описание и определение функции \verb|atof| должны соответствовать друг другу.
Если в одном исходном файле сама функция \verb|atof| и обращение к ней в
\verb|main| имеют разные типы, то это несоответствие будет зафиксировано
компилятором как ошибка. Но если функция \verb|atof| была скомпилирована
отдельно (что более вероятно), то несоответствие типов не будет обнаружено, и
\verb|atof| возвратит значение типа \verb|double|, которое функция \verb|main|
воспримет как \verb|int|, что приведёт к бессмысленному результату.

Это последнее утверждение, вероятно, вызовет у вас удивление, поскольку ранее
говорилось о необходимости соответствия описаний и определений.
\index{декларация!функции!неявная}%
\index{функция!неявная декларация}%
Причина несоответствия, возможно, будет следствием того, что вообще отсутствует
прототип функции, и функция неявно декларируется при первом своём появлении в
выражении, как, например, в

\begin{ShortCodePar}
sum += atof(line)
\end{ShortCodePar}

\noindent Если в выражении встретилось имя, нигде ранее не описанное, за которым
следует открывающая скобка, то такое имя по контексту считается именем функции,
возвращающей результат типа \verb|int|; при этом относительно её аргументов
ничего не предполагается. Если в декларации функции аргументы не указаны, как в
%
% исправлена ошибка
% в оригинале "считается именем функции, получающей результат"
%

\begin{ShortCodePar}
double atof();
\end{ShortCodePar}

\noindent то и в этом случае считается, что ничего об аргументах \verb|atof| не
известно, и все проверки на соответствие её параметров будут выключены.
\index{декларация!функции!старым способом}%
\index{функция!в старом стиле}%
Предполагается, что такая специальная интерпретация пустого списка позволит
новым компиляторам транслировать старые Си-программы.
\index{void@\texttt{void}!список аргументов}%
Если у функции есть аргументы, опишите их, если их нет, используйте слово
\verb|void|.

\index{функция!atoi@\texttt{atoi}}%
Располагая соответствующим образом описанной функцией \verb|atof|, мы можем
написать функцию \verb|atoi|‚ преобразующую стринг литер в целое значение,
следующим образом:

\begin{ShortCodePar}
/* atoi: преобразование стринга s в int с помощью atof */
int atoi(char s[])
{
    double atof(char s[]);
    return (int) atof(s);
}
\end{ShortCodePar}

\noindent%
\index{преобразование!\texttt{return}-инструкцией}%
\index{тип!преобразование в \texttt{return}}%
\index{return@\texttt{return}!преобразование типа в}%
\index{return-инструкция@\texttt{return}-инструкция}%
Обратите внимание на вид декларации и инструкции \verb|return|. Значение
выражения в

\begin{ShortCodeParWithCC}{\\\{\}}
return \textit{выражение};
\end{ShortCodeParWithCC}

\noindent приводится к типу функции перед тем, как оно будет передано в качестве
результата. Следовательно, поскольку функция \verb|atoi| возвращает значение
\verb|int|, результат вычисления \verb|atof| типа \verb|double| в инструкции
\verb|return| автоматически преобразуется в тип \verb|int|. При преобразовании
возможна потеря информации, и некоторые компиляторы предупреждают об этом.
Оператор приведения явно указывает на необходимость преобразования типа и
подавляет любое предупреждающее сообщение.

\paragraph{Упражнение 4.2.} Дополните функцию \verb|atof| таким образом, чтобы
она справлялась с числами вида

\begin{ShortCodePar}
123.45e-6
\end{ShortCodePar}

\noindent в которых в конце может стоять \verb|e| (или \verb|E|) с последующей
экспонентой (быть может, со знаком).

\section{Внешние переменные}
\label{sec:external_variables}

\index{модульность}%
\index{переменная!внешняя}%
Программа на Си обычно оперирует с множеством внешних объектов: переменных и
функций. Прилагательное <<внешний>> (<<\verb|external|>>) противоположно
прилагательному <<внутренний>> (<<\verb|internal|>>), которое относится к
аргументам и переменным, определяемым внутри функций. Внешние переменные
специфицируются вне функций и потенциально доступны для многих функций. Сами
функции всегда являются внешними объектами, поскольку в Си запрещено определять
функции внутри других функций.
\index{связь!внешняя}%
По умолчанию одинаковые внешние имена, используемые в разных файлах, ссылаются
на один и тот же внешний объект (функцию). (В стандарте это называется
\emph{соединением внешних связей} (\emph{external linkage}).) В этом смысле
внешние переменные похожи на области \verb|COMMON| в Фортране и на переменные
самого внешнего блока в Паскале. Позже мы покажем‚ как внешние функции и
переменные сделать видимыми только внутри одного исходного файла.

Поскольку внешние переменные доступны всюду, их можно использовать в качестве
связующих данных между функциями как альтернативу связей через аргументы и
возвращаемые значения. Для любой функции внешняя переменная доступна по её
имени, если это имя было должным образом описано.

Если число переменных, совместно используемых функциями, велико, связи между
последними через внешние переменные могут оказаться более удобными и
эффективными, чем длинные списки аргументов. Но, как отмечалось в
гл.~\ref{chapt:tutorial_intro}, к этому заявлению следует относиться критически,
поскольку такая практика ухудшает структуру программы и приводит к слишком
большому числу связей между функциями по данным.

Внешние переменные полезны, так как они имеют б\'{o}льшую область действия и
время жизни.
\index{переменная!автоматическая}%
Автоматические переменные действительны только внутри функции, они возникают в
момент входа в функцию и исчезают при выходе из неё. Внешние переменные,
напротив, существуют постоянно, так что их значения сохраняются в интервалах
между обращениями к функциям. Таким образом, если двум функциям приходится
пользоваться одними и теми же данными и ни одна из них не вызывает другую, то
часто бывает удобно оформить эти общие данные в виде внешних переменных, а не
передавать их в функцию и обратно через аргументы.

\index{польская запись}%
\index{реверсная польская запись}%
В связи с приведёнными рассуждениями разберём пример.
\index{программа!калькулятор}%
Поставим себе задачу написать программу-калькулятор, понимающую операторы
\verb|+|, \verb|-|, \verb|*| и \verb|/|. Такой калькулятор легче будет написать,
если ориентироваться на польскую, а не инфиксную запись выражений. (Обратная
польская запись применяется в некоторых карманных калькуляторах и в языках типа
Forth и Postscript.)

В обратной польской записи каждый оператор следует за своими операндами.
Выражение в инфиксной записи, скажем

\begin{ShortCodePar}
(1 - 2) * (4 + 5)
\end{ShortCodePar}

\noindent в польской записи представляется как

\begin{ShortCodePar}
1 2 - 4 5 + *
\end{ShortCodePar}

\noindent Скобки не нужны, неоднозначности в вычислениях не бывает, поскольку
известно, сколько операндов требуется для каждого оператора.

Реализовать нашу программу весьма просто. Каждый операнд посылается в стек; если
встречается оператор, то соответствующее число операндов (два в случае бинарных
операторов) берётся из стека и выполняется операция, после чего результат
посылается в стек. В нашем примере числа $1$ и $2$ посылаются в стек, затем они
замещаются на их разность $-1$. Далее в стек посылаются числа $4$ и $5$, которые
затем заменяются на их сумму, $9$. Числа $-1$ и $9$ заменяются в стеке на их
произведение (т.е. на $-9$). Встретив литеру новая-строка, программа выталкивает
значение из стека и печатает его.

Программа, следовательно, состоит из цикла, обрабатывающего на каждом своём шаге
очередной встречаемый оператор или операнд:

\begin{LongCodeParWithCC}{\\\{\}}
while (\textit{следующий элемент не конец-файла})
    if (\textit{число})
        \textit{послать его в стек}
    else if (\textit{оператор})
        \textit{взять из стека операнды}
        \textit{выполнить операцию}
        \textit{результат послать в стек}
    else if (\textit{новая-строка})
        \textit{взять с вершины стека число и напечатать}
    else
        \textit{ошибка}
\end{LongCodeParWithCC}

\index{модульность}%
Операции <<послать в стек>> и <<взять из стека>> сами по себе тривиальны, однако
необходимость добавления механизмов обнаружения и нейтрализации ошибок делает их
достаточно длинными.
\index{сокрытие информации}%
Поэтому эти операции стоит оформить в виде функций. Также разумно иметь
отдельную функцию, получающую очередной оператор или операнд.

Главный вопрос, который мы ещё не рассмотрели, -- это вопрос о том, где
расположить стек и каким функциям разрешить к нему прямой доступ. Стек можно
расположить в функции \verb|main| и передавать сам стек и текущую позицию в нём
в качестве аргументов
\index{функция!pop@\texttt{pop}}%
\index{функция!push@\texttt{push}}%
функциям \verb|push| (<<послать в стек>>) и \verb|pop|
(<<взять из стека>>). Но функции \verb|main| нет дела до переменных, относящихся
к стеку, -- ей нужны только операции \verb|push| и \verb|pop|. Поэтому мы
решили стек и связанную с ним информацию хранить во внешних переменных,
доступных для \verb|push| и \verb|pop|, но не для \verb|main|.

Переход от эскиза к конкретной программе достаточно лёгок. Если теперь программу
представить как текст, расположенный в некотором исходном файле, она будет иметь
следующий вид:

\begin{LongCodeParWithCC}{\\\!\?}
#include...  /* могут быть в любом количестве */
#define...   /* могут быть в любом количестве */
\textit!описания функций для? main
main() { ... }
\textit!внешние переменные для? push \textit!и? pop
void push(double f) { ... }
double pop(void) { ... }
int getop(char s[]) { ... }
\textit!подпрограммы, вызываемые функцией? getop
\end{LongCodeParWithCC}

\noindent Позже мы обсудим, как текст этой программы можно разбить на два или
большее число файлов.

\index{switch-инструкция@\texttt{switch}-инструкция}%
Функция \verb|main| -- это цикл, содержащий большой переключатель, передающий
управление на ту или иную ветвь в зависимости от типа оператора или операнда.
Здесь представлен более типичный случай применения переключателя по сравнению с
рассмотренным в разд.~\ref{sec:switch}.

\index{программа!калькулятор}%
\begin{LongCodePar}
#include <stdio.h>
#include <stdlib.h>    /* для atof() */
#define MAXOP 100      /* макс. размер опер-да или опер-ра */
#define NUMBER '0'     /* признак числа */
int getop(char []);
void push(double);
double pop(void);
/* калькулятор с обратной польской записью */
main()
{
    int type;
    double op2;
    char s[MAXOP];
    while ((type = getop(s)) != EOF) {
        switch (type) {
        case NUMBER:
            push(atof(s));
            break;
        case '+':
            push(pop() + pop());
            break;
        case '*':
            push(pop() * pop());
            break;
        case '-':
            op2 = pop();
            push(pop() - op2);
            break;
        case '/':
            op2 = pop();
            if (op2 != 0.0)
                push(pop() / op2);
            else
                printf("ошибка: деление на нуль\n");
            break;
        case '\n':
            printf("\t%.8g\n", pop());
            break;
        default:
            printf("ошибка: неизвестная операция %s\n", s);
            break;
        }
    }
    return 0;
}
\end{LongCodePar}

\noindent%
\index{вычисление, порядок}%
\index{порядок!вычислений}%
Так как операторы \verb|+| и \verb|*| коммутативны, порядок, в котором операнды
берутся из стека, не важен, однако в случае операторов \verb|-| и \verb|/| левый
и правый операнды должны различаться. Так, в

\begin{ShortCodePar}
push(pop() - pop());    /* НЕПРАВИЛЬНО */
\end{ShortCodePar}

\noindent порядок, в котором выполняются обращения к \verb|рор|, не определён.
Чтобы гарантировать правильный порядок, необходимо первое значение из стека
присвоить временной переменной, как это и сделано в \verb|main|.

\begin{LongCodePar}
#define MAXVAL  100   /* максимальная глубина стека */
int sp = 0;           /* позиция след. своб. эл-та стека */
double val[MAXVAL];   /* стек */

/* push: положить значение f в стек */
void push(double f)
{
    if (sp < MAXVAL)
        val[sp++] = f;
    else
        printf("ошибка: стек полон, %g не помещается\n", f);
}

/* pop: взять с вершины стека и выдать в качестве рез-та */
double pop(void)
{
    if (sp > 0)
        return val[--sp];
    else {
        printf("ошибка: стек пуст\n");
        return 0.0;
    }
}
\end{LongCodePar}

Переменная считается внешней, если она определена вне функций. Таким образом,
стек и индекс стека, которые должны быть доступны и для \verb|push|, и для
\verb|pop|, определяются вне этих функций.
\index{сокрытие информации}%
Но \verb|main| не использует ни стек, ни позицию в стеке, и поэтому их
представление может быть скрыто от \verb|main|.

\index{функция!getop@\texttt{getop}}%
Займёмся реализацией \verb|getop| -- функции, получающей следующий оператор или
операнд. Нам предстоит решить довольно простую задачу. Более точно: требуется
пропустить пробелы и табуляции; если следующая литера -- не цифра и не
десятичная точка, то выдать её; в противном случае накопить цепочку цифр с
десятичной точкой, если она есть, и выдать признак числа \verb|NUMBER| в
качестве результата.

\begin{LongCodePar}
#include <ctype.h>
int getch(void);
void ungetch(int);

/* getop: получает следующий оператор или операнд */
int getop(char s[])
{
    int i, c;
    while ((s[0] = c = getch()) == ' ' || c == '\t')
        ;
    s[1] = '\0';
    if (!isdigit(c) && c != '.')
        return c;          /* не число */
    i = 0;
    if (isdigit(c))        /* накапливаем целую часть */
        while (isdigit(s[++i] = c = getch()))
            ;
    if (c == '.')          /* накапливаем дробную часть */
        while (isdigit(s[++i] = c = getch()))
            ;
    s[i] = '\0';
    if (c != EOF)
        ungetch(c);
    return NUMBER;
}
\end{LongCodePar}

\index{функция!getch@\texttt{getch}}%
\index{функция!ungetch@\texttt{ungetch}}%
Как работают функции \verb|getch| и \verb|ungetch|? Во многих случаях программа
не может <<сообразить>>, прочла ли она всё, что требуется, пока не прочтёт
лишнего. Так, накопление числа производится до тех пор, пока не встретится
литера, отличная от цифры. Но это означает, что программа прочла на одну литеру
больше, чем нужно, а именно литеру, которую нельзя включать в число.

Эту проблему можно было бы решить при наличии обратной чтению
\index{ввод!возврат литеры на}%
операции <<положить-назад>>, с помощью которой можно было бы вернуть
преждевременно прочитанную литеру. Тогда каждый раз, когда программа считает на
одну литеру больше, чем требуется, эта операция возвращала бы её вводу, и
поэтому остальная часть программы могла бы вести себя так, как будто эта литера
и вовсе не читалась. К счастью, описанный механизм обратной посылки литеры легко
моделируется с помощью пары согласованных друг с другом функций, из которых
\verb|getch| поставляет очередную литеру из ввода, а \verb|ungetch| отправляет
назад литеру во входной поток, так что при следующем обращении к \verb|getch| мы
вновь её получим.

Нетрудно догадаться, как они работают вместе. Функция \verb|ungetch| запоминает
посылаемую назад литеру в некотором буфере, представляющем собой массив литер,
доступный для обеих этих функций; \verb|getch| читает из буфера, если там что-то
есть, или обращаются к \verb|getchar|, если буфер пустой. Следует предусмотреть
индекс, указывающий на положение текущей литеры в буфере.

Так как функции \verb|getch| и \verb|ungetch| совместно используют буфер и
индекс, значения последних должны сохраняться между вызовами. Поэтому буфер и
индекс должны быть внешними по отношению к этим программам, и мы можем записать
\verb|getch|, \verb|ungetch| и общие для них переменные в следующем виде:

\begin{LongCodePar}
#define BUFSIZE 100
char buf[BUFSIZE];  /* буфер для ungetch */
int bufp = 0;       /* след. свободная позиция в буфере */

int getch(void)     /* дай (возможно возвращённую) литеру */
{
    return (bufp > 0) ? buf[--bufp] : getchar();
}
void ungetch(int c) /* верни литеру на ввод */
{
    if (bufp >= BUFSIZE)
        printf("ungetch: слишком много литер\n");
    else
        buf[bufp++] = c;
}
\end{LongCodePar}
%
% в оригинале в строке 2 опечатка ungetc
%

\noindent Стандартная библиотека включает функцию \verb|ungetc|, обеспечивающую
возврат одной литеры (см. гл.~\ref{chapt:input-output}). Мы же, чтобы
проиллюстрировать более общий подход, для запоминания возвращаемых литер
использовали массив.

\paragraph{Упражнение 4.3.} Исходя из предложенной нами схемы, дополните
программу-калькулятор таким образом, чтобы она <<понимала>> оператор взятия
модуля (\verb|%|) и отрицательные числа.


\paragraph{Упражнение 4.4.} Добавьте команды, с помощью которых можно было бы
печатать верхний элемент стека (с сохранением его на стеке), дублировать его на
стеке, менять местами два верхних элемента стека. Введите команду очистки стека.

\paragraph{Упражнение 4.5.} Предусмотрите возможность использования в программе
библиотечных функций \verb|sin|, \verb|exp| и \verb|pow|. См. библиотеку
\verb|<math.h>| в приложении~\ref{apx:stdlib} (разд.~\ref{apx:sect:math_h}).

\paragraph{Упражнение 4.6.} Введите команды для работы с переменными (легко
обеспечить до 26 переменных, каждая из которых имеет имя, представленное одной
буквой латинского алфавита). Добавьте переменную, предназначенную для хранения
самого последнего из напечатанных значений.

\paragraph{Упражнение 4.7.} Напишите программу \verb|ungets(s)|, возвращающую
стринг \verb|s| во входной поток. Должна ли \verb|ungets| <<знать>> что-либо о
переменных \verb|buf| и \verb|bufp| или ей достаточно пользоваться только
функцией \verb|ungetch|?

\paragraph{Упражнение 4.8.} Предположим, что число литер, возвращаемых назад, не
превышает 1. Модифицируйте с учётом этого факта функции \verb|getch| и
\verb|ungetch|.

\paragraph{Упражнение 4.9.} В наших функциях не предусмотрена возможность
возврата \verb|EOF|. Подумайте, что надо сделать, чтобы можно было возвращать
\verb|EOF|, и скорректируйте соответственно программу.

\paragraph{Упражнение 4.10.} В основу программы калькулятора можно положить
применение функции \verb|getline|, которая читает целиком строку; при этом
отпадает необходимость в \verb|getch| и \verb|ungetch|. Напишите программу,
реализующую этот подход.

\section{Правила областей действия}

\index{компиляция!раздельная}%
Функции и внешние переменные, из которых состоит Си-программа, каждый раз
компилировать все вместе нет никакой необходимости. Исходный текст можно хранить
в нескольких файлах. Ранее скомпилированные программы можно загружать из
\index{библиотечная функция}%
библиотек. В связи с этим возникают следующие вопросы:

\begin{itemize}
  \item Как писать декларации, чтобы на протяжении компиляции используемые
  переменные были должным образом описаны?
  \item В каком порядке располагать декларации, чтобы во время загрузки все
  части программы оказались связаны нужным образом?
  \item Как организовать декларации, чтобы для нескольких одноимённых деклараций
  была только одна копия?
  \item Как инициализировать внешние переменные?  
\end{itemize}

\noindent Начнём с того, что разобьём программу-калькулятор на несколько файлов.
Конечно, эта программа слишком мала, чтобы её стоило разбивать на файлы, однако
разбиение нашей программы позволит продемонстрировать проблемы, возникающие в
больших программах.

\index{область действия!правила определения}%
\emph{Областью действия} имени считается часть программы, в которой это имя
можно использовать.
\index{область действия!автоматических переменных}%
Для автоматических переменных, описанных в начале функции,
областью действия является функция, в которой они описаны. Локальные переменные
разных функций, имеющие, однако, одинаковые имена, никак не связаны друг с
другом. То же утверждение справедливо и в отношении параметров функции, которые
фактически являются локальными переменными.

\index{область действия!внешних объектов}%
Область действия внешней переменной или функции простирается от точки программы,
где она декларирована‚ до конца файла, подлежащего компиляции. Например, если
\verb|main|, \verb|sp|, \verb|val|, \verb|push| и \verb|pop| определены в одном
файле в указанном порядке, т.е.

\begin{ShortCodePar}
main() { ... }
int sp = 0;
double val[MAXVAL];
void push(double f) { ... }
double pop(void) { ... }
\end{ShortCodePar}

\noindent то к переменным \verb|sp| и \verb|val| можно адресоваться из
\verb|push| и \verb|pop| просто по их именам; никаких дополнительных деклараций
для них не требуется. Заметим, что в \verb|main| эти имена не видимы так же, как
и сами \verb|push| и \verb|pop|.

\index{спецификатор!extern@\texttt{extern}}%
\index{extern@\texttt{extern}}%
С другой стороны, если на внешнюю переменную нужно сослаться до того, как она
определена, или если она определена в другом файле, то её декларация должна быть
помечена словом \verb|extern|.

\index{декларация!а не определение}%
Важно отличать \emph{декларацию (описание)} внешней переменной от её
\emph{определения}. Декларация объявляет свойства переменной (прежде всего её
тип), а определение, кроме того, приводит к выделению для неё памяти. Если
строки

\begin{ShortCodePar}
int sp;
double val[MAXVAL];
\end{ShortCodePar}

\noindent расположены вне всех функций, то они \emph{определяют} внешние
переменные \verb|sp| и \verb|val|, т.е. отводят для них память, и, кроме того,
служат декларациями для остальной части исходного файла. А вот строки

\begin{ShortCodePar}
extern int sp;
extern double val[];
\end{ShortCodePar}

\noindent декларируют для остальной части файла, что \verb|sp| -- переменная
типа \verb|int| и что \verb|val| -- массив типа \verb|double| (размер которого
определён где-то в другом месте); при этом ни переменная, ни массив не
создаются, и память им не отводится.

На всю совокупность файлов, из которых состоит исходная программа, для каждой
внешней переменной должно быть одно-единственное \emph{определение}; другие
файлы, чтобы получить доступ к внешней переменной, должны иметь в себе
декларацию \verb|extern|. (Впрочем, декларацию \verb|extern| можно поместить и в
файл, в котором содержится определение.) В определениях массивов необходимо
указывать их размеры, что же касается деклараций \verb|extern|, то здесь они не
обязательны.

\index{инициализация!переменных!внешних}%
Инициализировать внешнюю переменную можно только в определении.

Хотя маловероятно, что нашу программу кто-нибудь станет организовывать таким
способом, но мы определим \verb|push| и \verb|pop| в одном файле, а \verb|val| и
\verb|sp| -- в другом, где их и инициализируем. При этом для установления
связей понадобятся такие определения и декларации:

{\setlength{\parindent}{\codeIndent}
\textit{В файле 1:}
}
\begin{Verbatim}[samepage=true,xleftmargin=\doubleCodeIndent]
extern int sp;
extern double val[];
void push(double f) { ... }
double pop(void) { ... }
\end{Verbatim}

{\setlength{\parindent}{\codeIndent}
\textit{В файле 2:}
}
\begin{Verbatim}[samepage=true,xleftmargin=\doubleCodeIndent]
int sp = 0;
double val[MAXVAL];
\end{Verbatim}

\noindent Поскольку декларации \verb|extern| находятся в начале \textit{файла 1}
и вне определений функций, их действие распространяется на все функции, причём
одного набора деклараций достаточно для всего \textit{файла 1}. Та же
организация \verb|extern|-деклараций необходима и в случае, когда программа
состоит из одного файла, но определения \verb|sp| и \verb|val| расположены после
их использования.

\section{Головные файлы}

\index{файл!головной}%
Теперь представим себе, что компоненты программы-калькулятора существенно
б\'{o}льших размеров, и зададимся вопросом, как в этом случае распределить их
по нескольким файлам. Программу \verb|main| поместим в файл, который мы назовём
\verb|main.c|; \verb|push|, \verb|pop| и их переменные расположим во втором
файле, \verb|stack.c|; а \verb|getop| -- в третьем, \verb|getop.c|. Наконец,
\verb|getch| и \verb|ungetch| разместим в четвёртом файле \verb|getch.c|; мы
отделили их от остальных функций, поскольку в реальной программе они будут
получены из заранее скомпилированной библиотеки.

Существует ещё один момент, о котором следует предупредить читателя, --
определения и декларации совместно используются несколькими файлами. Насколько
это возможно, мы бы хотели централизовать описания так, чтобы для них
существовала только одна копия. Тогда программу в процессе её развития будет
легче и исправлять, и поддерживать в правильном состоянии. Для этого общую
информацию расположим в \emph{головном файле} \verb|calc.h|‚ который будем по
мере необходимости включать в другие файлы. (Строка \verb|#include| описывается
в разд.~\ref{sec:c_preprocessor}.) В результате получим программу, файловая
структура которой показана на следующей странице.

Неизбежен компромисс между стремлением, чтобы каждый файл владел только той
информацией, которая ему необходима для работы, и тем, что на практике иметь
дело с большим количеством головных файлов довольно трудно. Для программ, не
превышающих некоторого среднего размера, вероятно, лучше всего иметь один
головной файл, в котором собраны вместе все объекты, каждый из которых
используется в двух различных файлах; так мы здесь и поступили. Для программ
б\'{o}льших размеров потребуется более сложная организация с б\'{o}льшим числом
головных файлов.

\section{Статические переменные}

\index{память!статическая|(}%
Переменные \verb|sp| и \verb|val| в файле \verb|stack.c|, а также \verb|buf| и
\verb|bufp| в \verb|getch.c| находятся в личном пользовании функций этих файлов,
и нет смысла открывать к ним доступ кому-либо ещё.
\index{static@\texttt{static}!декларация функции}%
\index{static@\texttt{static}!спецификатор класса памяти}%
\index{static-переменные@\texttt{static}-переменные!внешние}%
Указание \verb|static|, применённое к внешней переменной или функции,
ограничивает область действия соответствующего объекта концом файла. Это способ
скрыть имена. Так, переменные \verb|buf| и \verb|bufp| должны быть внешними,
поскольку их совместно используют функции \verb|getch| и \verb|ungetch|, но их
следует сделать невидимыми для <<пользователей>> функций \verb|getch| и
\verb|ungetch|.

\begin{center}
\footnotesize
\begin{tabular}{lllll}
&&\Verb| |calc.h:&&\\
\cline{3-3}
&&\multicolumn{1}{|l|}{\Verb|\#define NUMBER '0'\ \ \ \ |}&&\\
&&\multicolumn{1}{|l|}{\Verb|void push(double);|}&&\\
&&\multicolumn{1}{|l|}{\Verb|double pop(void);|}&&\\
&&\multicolumn{1}{|l|}{\Verb|int getop(char[]);|}&&\\
&&\multicolumn{1}{|l|}{\Verb|int getch(void);|}&&\\
&&\multicolumn{1}{|l|}{\Verb|void ungetch(int);|}&&\\
\cline{3-3}
&&&&\\
\Verb| |main.c:&&\Verb| |getop.c:&&\Verb| |stack.c:\\
\cline{1-1}\cline{3-3}\cline{5-5} 
\multicolumn{1}{|l|}{\Verb|\#include <stdio.h>\ \ \ \ |}&&
\multicolumn{1}{|l|}{\Verb|\#include <stdio.h>|}&&
\multicolumn{1}{|l|}{\Verb|\#include <stdio.h>\ \ \ \ |}\\

\multicolumn{1}{|l|}{\Verb|\#include <stdlib.h>|}&&
\multicolumn{1}{|l|}{\Verb|\#include <ctype.h>|}&&
\multicolumn{1}{|l|}{\Verb|\#include ''calc.h''|}\\

\multicolumn{1}{|l|}{\Verb|\#include ''calc.h''|}&&
\multicolumn{1}{|l|}{\Verb|\#include ''calc.h''|}&&
\multicolumn{1}{|l|}{\Verb|\#define MAXVAL 100|}\\

\multicolumn{1}{|l|}{\Verb|\#define MAXOP 100|}&&
\multicolumn{1}{|l|}{\Verb|getop() \{|}&&
\multicolumn{1}{|l|}{\Verb|int sp = 0;|}\\

\multicolumn{1}{|l|}{\Verb|main() \{|}&&
\multicolumn{1}{|l|}{\Verb|\ \ \ \ \ \ ... |}&&
\multicolumn{1}{|l|}{\Verb|double val[MAXVAL];|}\\

\multicolumn{1}{|l|}{\Verb|\ \ \ \ \ ... |}&&
\multicolumn{1}{|l|}{\Verb|\}|}&&
\multicolumn{1}{|l|}{\Verb|void push(double) \{|}\\
\cline{3-3}
\multicolumn{1}{|l|}{\Verb|\}|}&&
&&
\multicolumn{1}{|l|}{\Verb|\ \ \ \ \ ... |}\\
\cline{1-1}
&&
&&
\multicolumn{1}{|l|}{\Verb|\}|}\\

&&
\Verb| |getch.c:&&
\multicolumn{1}{|l|}{\Verb|double pop(void) \{|}\\
\cline{3-3}
&&
\multicolumn{1}{|l|}{\Verb|\#include <stdio.h>|}&&
\multicolumn{1}{|l|}{\Verb|\ \ \ \ \ ... |}\\

&&
\multicolumn{1}{|l|}{\Verb|\#define BUFSIZE 100|}&&
\multicolumn{1}{|l|}{\Verb|\}|}\\
\cline{5-5} 
&&\multicolumn{1}{|l|}{\Verb|char buf[BUFSIZE];|}&&\\
&&\multicolumn{1}{|l|}{\Verb|int bufp = 0;|}&&\\
&&\multicolumn{1}{|l|}{\Verb|int getch(void) \{|}&&\\
&&\multicolumn{1}{|l|}{\Verb|\ \ \ \ \ ... |}&&\\
&&\multicolumn{1}{|l|}{\Verb|\}|}&&\\
&&\multicolumn{1}{|l|}{\Verb|void ungetch(int) \{|}&&\\
&&\multicolumn{1}{|l|}{\Verb|\ \ \ \ \ ... |}&&\\
&&\multicolumn{1}{|l|}{\Verb|\}|}&&\\
\cline{3-3}
&&&&\\
\end{tabular}
\end{center}
%
% в оригинале в схеме файлов есть опечатки с направлением фигурных скобок
% тут они исправлены
%

\index{спецификатор!static@\texttt{static}}%
\index{static@\texttt{static}!спецификатор класса памяти}%
Статическая память специфицируется словом \verb|static|‚ которое помещается
перед обычным описанием. Если рассматриваемые нами две функции и две переменные
компилируются в одном файле, как в показанном ниже примере:

\begin{ShortCodePar}
static char buf[BUFSIZE];    /* буфер для ungetch */
static int  bufp = 0;        /* след. своб. позиция в buf */
int getch(void) { ... }
void ungetch(int c) { ... }
\end{ShortCodePar}

\noindent то никакая другая программа не будет иметь доступ ни к \verb|buf|, ни
\verb|bufp|, и этими именами можно свободно пользоваться в других файлах для
совсем иных целей. Точно так же, помещая указание \verb|static| перед
декларациями переменных \verb|sp| и \verb|val|, с которыми работают только
\verb|push| и \verb|pop|, мы можем скрыть их от остальных функций.

\index{static@\texttt{static}!декларация функции}%
Указание \verb|static| чаще всего используется для переменных, но с равным
успехом его можно применять и к функциям. Обычно имена функций глобальны и
видимы из любого места программы. Если же функция помечена словом \verb|static|,
то её имя становится невидимым вне файла, в котором она определена.

\index{static-переменные@\texttt{static}-переменные!внутренние}%
Декларацию \verb|static| можно использовать и для внутренних переменных. Как и
автоматические переменные, внутренние статические переменные локальны в
функциях, но в отличие от автоматических они не возникают только на период
активации функции, а существуют постоянно. Это значит, что для внутренних
статических переменных отводится постоянная память (так же, как и для команд
самой функции).
\index{память!статическая|)}%


\paragraph{Упражнение 4.11.} Модифицируйте функцию \verb|getop| так, чтобы
отпала необходимость в функции \verb|ungetch|. Совет: используйте внутреннюю
статическую переменную.

\section{Регистровые переменные}

\index{спецификатор!register@\texttt{register}}%
\index{эффективность}%
\index{register@\texttt{register}}%
Спецификация \verb|register| в декларации сообщает компилятору, что данная
переменная будет использоваться интенсивно. Идея состоит в том, чтобы переменные
со спецификацией \verb|register| разместить на регистрах машины, благодаря чему
программа, возможно, станет более короткой и быстрой. Однако компилятор имеет
право проигнорировать это указание.

Вот два примера деклараций с \verb|register|:

\begin{ShortCodePar}
register int x;
register char c;
\end{ShortCodePar}

Спецификация \verb|register| может применяться только к автоматическим
переменным и к формальным параметрам функции. Для последних спецификации
\verb|register| задаются в списке параметров, как, например, в

\begin{ShortCodePar}
f(register unsigned m, register long n)
{
    register int i;
    ...
}
\end{ShortCodePar}

На практике существуют ограничения на \verb|register|-переменные, связанные с
возможностями аппаратуры. Только небольшое число переменных каждой функции, и
причём только определённых типов, могут располагаться в регистрах. Избыточные
указания \verb|register| ни на что не влияют, так как эти указания игнорируются
в отношении переменных, которым не хватило регистров, или которым они по
каким-то причинам не были выделены. Кроме того, применительно к регистровой
переменной независимо от того, выделен на самом деле регистр для неё или нет, не
определено понятие адреса (см. гл.~\ref{chapt:pointers_and_arrays}). Конкретные
ограничения на количество и типы регистровых переменных зависят от машины.

\section{Блочная структура}

\index{блок}%
\index{блок!структура}%
Поскольку функции в Си нельзя определять внутри других функций, он не является
языком, допускающим блочную структуру программы в том смысле, как они разрешены
в Паскале и подобных ему языках. Но переменные внутри функций можно определять в
блочно-структурной манере.
\index{составная инструкция}%
\index{инструкция!составная}%
\index{фигурные скобки}%
Декларации переменных (вместе с инициализацией)
разрешено помещать не только в начале функции, но и после \emph{любой} левой
фигурной скобки, открывающей составную инструкцию.
\index{имени затенение}%
Переменная, описанная таким способом, <<затеняет>> переменные с тем же именем,
расположенные в объемлющих блоках, и существует вплоть до соответствующей правой
фигурной скобки. Например, в

\begin{ShortCodePar}
if (n > 0) {
    int i;   /* описание новой переменной i */
    for (i = 0; i < n; i++)
        ...
}
\end{ShortCodePar}

\noindent областью действия переменной \verb|i| является ветвь \verb|if|,
выполняемая при \verb|n > 0|; и эта переменная никакого отношения к любым
\verb|i|, расположенным вне данного блока, не имеет.
\index{инициализация}%
\index{блок!инициализация}%
\index{инициализация!в блоке}%
Автоматические переменные, декларируемые и инициализируемые в блоке,
инициализируются каждый раз при входе в блок. Переменные \verb|static|
инициализируются только один раз при первом входе в блок.

Автоматические переменные и формальные параметры также <<затеняют>> внешние
переменные и функции с теми же именами. Например, в

\begin{ShortCodePar}
int x;
int y;
f(double x)
{
    double y;
    ...
}
\end{ShortCodePar}

\noindent ссылки на \verb|x| внутри функции \verb|f| рассматриваются как
параметр типа \verb|double|, в то время как вне \verb|f| они отсылают нас к
внешней переменной типа \verb|int|. То же самое можно сказать и о переменной
\verb|y|.

Конечно, это вопрос стиля программирования, использовать ли одни и те же имена
для разных переменных. Однако потенциальная опасность получить ошибку при
<<перекрытии>> имён столь велика, что лучше этого избегать.

\section{Инициализация}

\index{инициализатор}%
\index{инициализация}%
Мы уже много раз упоминали об инициализации, но всегда по случаю, в ходе
обсуждения других вопросов. В этом разделе мы суммируем все правила,
определяющие инициализацию памяти различных классов.

\index{инициализация!по умолчанию}%
\index{инициализация!переменных!внешних}%
\index{инициализация!переменных!статических}%
\index{по умолчанию!инициализация}%
При отсутствии явной инициализации для внешних и статических переменных
гарантируется их обнуление; автоматические и регистровые переменные имеют
неопределённые начальные значения (<<мусор>>).

Скалярные переменные можно инициализировать в их определениях, помещая после
имени знак \verb|=| и соответствующее выражение.

\begin{ShortCodePar}
int x = 1;
char squote = '\'';
long day = 1000L * 60L * 60L * 24L;/* день в миллисекундах */
\end{ShortCodePar}
%
% в целях выравнивания в предыдущем блоке кода
% строка "long day = 1000L * 60L * 60L * 24L; /* день в миллисекундах */"
% заменена на "long day = 1000L * 60L * 60L * 24L;/* день в миллисекундах */"
% данное изменение не влияет на смысл кода
%

\noindent Для внешних и статических переменных инициализирующие выражения должны
быть константными, при этом инициализация осуществляется только один раз до
начала выполнения программы.
\index{инициализация!переменных!автоматических}%
Инициализация автоматических и регистровых переменных выполняется каждый раз при
входе в функцию или блок. Для таких переменных инициализирующее выражение -- не
обязательно константное. Это может быть любое выражение, использующее ранее
определённые значения, включая даже и вызовы функций. Например, в программе
бинарного поиска, описанной в разд.~\ref{sec:else_if}, инициализации можно
записать в виде

\begin{ShortCodePar}
int binsearch(int x, int v[], int n)
{
    int low = 0;
    int high = n - 1;
    int mid;
    ...
}
\end{ShortCodePar}

\noindent а не как

\begin{ShortCodePar}
int low, high, mid;
low = 0;
high = n - 1; 
\end{ShortCodePar}

\noindent%
\index{программа!читаемость}%
В сущности, инициализация автоматической переменной -- это более
короткая запись инструкции присваивания. Какая запись предпочтительнее -- в
основном дело вкуса. До сих пор мы пользовались главным образом явными
присваиваниями, поскольку инициализация в декларациях менее заметна и дальше
отстоит от места использования переменной.

\index{массив!размер по умолчанию}%
\index{инициализация!массива}%
\index{по умолчанию!размер массива}%
\index{фигурные скобки}%
Массив можно инициализировать в его определении с помощью заключённого в
фигурные скобки списка инициализаторов, разделённых запятыми. Например, чтобы
инициализировать массив \verb|days|, элементы которого суть количества дней в
каждом месяце, можно написать

{\setlength{\codeIndent}{\codeIndentBk-0.5em}
\begin{ShortCodePar}
int days[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
\end{ShortCodePar}
\setlength{\codeIndent}{\codeIndentBk}}

\noindent Если размер массива не указан, то длину массива компилятор вычисляет
по числу заданных инициализаторов; в нашем случае их количество равно $12$.

Если количество инициализаторов меньше числа, указанного в определении длины
массива, то для внешних, статических и автоматических переменных оставшиеся
элементы будут нулевыми. Задание слишком большого числа инициализаторов
считается ошибкой. В языке нет возможности ни задавать кратность для
инициализатора, ни инициализировать средние элементы массива без задания всех
предшествующих значений.
%%
%% исправлена опечатка
%% в оригинале "инициализовать"
%%

\index{инициализация!стринговой константой}%
Инициализация литерных массивов -- особый случай: вместо конструкции с фигурными
скобками и запятыми можно использовать стринг литер. Например, возможна такая
запись:

\begin{ShortCodePar}
int pattern[] = "ould";
\end{ShortCodePar}

\noindent что представляет собой более короткий эквивалент записи

\begin{ShortCodePar}
int pattern[] = {'o', 'u', 'l', 'd', '\0'};
\end{ShortCodePar}

\noindent В данном случае размер массива равен пяти (четыре обычные литеры и
завершающая литера \verb|'\0'|).

\section{Рекурсия}

\index{рекурсия}%
В Си допускается рекурсивное обращение к функциям, т.е. функция может обращаться
сама к себе, прямо или косвенно. Рассмотрим печать числа в виде стринга литер.
Как мы упоминали ранее, цифры генерируются в обратном порядке -- младшие цифры
получаются раньше старших, а печататься они должны в правильной
последовательности.

Проблему можно решить двумя способами. Первый -- запомнить цифры в некотором
массиве в том порядке, как они получались, а затем напечатать их в обратном
порядке; так это и было сделано в \verb|itoa|, приведённой в
разд.~\ref{sec:do_while}.
\index{функция!printd@\texttt{printd}}%
Второй способ -- воспользоваться рекурсией, при
которой \verb|printd| сначала вызывает себя, чтобы напечатать все старшие цифры,
и затем печатает последнюю младшую цифру. Эта программа, как и предыдущий её
вариант, работает неправильно в случае самого большого по модулю отрицательного
числа.

\begin{LongCodePar}
#include <stdio.h>
/* printd: печатает n как целое десятичное число */
void printd(int n)
{
    if (n < 0) {
        putchar('-');
        n = -n;
    }
    if (n / 10)
        printd(n / 10);
    putchar(n % 10 + '0');
}
\end{LongCodePar}

Когда функция рекурсивно обращаются сама к себе, каждое следующее обращение
сопровождается получением ею нового полного комплекта автоматических переменных,
независимых от предыдущих комплектов. Так, в обращении \verb|printd(123)| при
первом вызове аргумент \verb|n = 123|, при втором -- \verb|printd| получает
аргумент $12$, при третьем вызове -- значение $1$. Функция \verb|printd| на
третьем уровне вызова печатает $1$ и возвращается на второй уровень, после чего
она печатает цифру $2$ и возвращается на первый уровень. Здесь она печатает $3$
и заканчивает работу.

Следующий хороший пример рекурсии -- это
\index{быстрая сортировка}%
\index{программа!сортировки}%
\index{сортировка!численная}%
\index{числа!сортировка}%
быстрая сортировка, предложенная
\index{Хоар Ч. А. Р.}%
Ч.А.Р. Хоаром в 1962 г. Для заданного массива выбирается один элемент, который
разбивает остальные элементы на два подмножества -- те, что меньше, и те, что не
меньше него. Та же процедура рекурсивно применяется и к двум полученным
подмножествам. Если в подмножестве менее двух элементов, то сортировать нечего,
и рекурсия завершается.
%%
%% исправлена неточность имени
%% в оригинале Charles Antony Richard Hoare
%% был назван "К.А.Р.Хоором"
%% можно спорить о трансфонетизации и транслитерации,
%% но версия оригинала очевидно ошибочная
%%

\index{функция!qsort@\texttt{qsort}}%
Наша версия быстрой сортировки, разумеется, не самая быстрая среди всех
возможных, но зато одна из самых простых. В качестве делящего элемента мы
используем серединный элемент.

\begin{LongCodePar}
/* qsort: сортирует v[left]...v[right] по возрастанию */
void qsort(int v[], int left, int right)
{
    int i, last;
    void swap(int v[], int i, int j);
    if (left >= right) /* ничего не делается, если       */
        return;        /* в массиве менее двух элементов */
    swap(v, left, (left + right)/2); /* делящий элемент    */
    last = left;                     /* переносится в v[0] */
    for (i = left+1; i <= right; i++) /* деление на части */
        if (v[i] < v[left])
            swap(v, ++last, i);
    swap(v, left, last);   /* перезапоминаем делящий эл-т */
    qsort(v, left, last-1);
    qsort(v, last+1, right);
}
\end{LongCodePar}

\noindent%
\index{функция!swap@\texttt{swap}}%
В нашей программе операция перестановки оформлена в виде отдельной функции
(\verb|swap|), поскольку трижды встречается в \verb|qsort|.

\begin{LongCodePar}
/* swap: переставить v[i] и v[j] между собой */
void swap(int v[], int i, int j)
{
    int temp;
    temp = v[i];
    v[i] = v[j];
    v[j] = temp;
}
\end{LongCodePar}

\noindent Стандартная библиотека имеет функцию \verb|qsort|, позволяющую
сортировать объекты любого типа.

\index{эффективность}%
Рекурсивная программа не обеспечивает ни экономного расходования памяти,
поскольку требуется где-то поддерживать стек значений, подлежащих обработке, ни
быстродействия; но по сравнению со своим нерекурсивным эквивалентом она часто
короче, а часто намного легче для написания и понимания. Такого рода программы
особенно удобны для обработки рекурсивно определяемых структур данных типа
деревьев; с хорошим примером на эту тему вы познакомитесь в
разд.~\ref{sec:self_reference_structures}.

\paragraph{Упражнение 4.12.} Примените идеи, которые мы использовали в
\verb|printd| для написания рекурсивной версии функции \verb|itoa|; иначе
говоря, преобразуйте целое число в цепочку цифр с помощью рекурсивной программы.

\paragraph{Упражнение 4.13.} Напишите рекурсивную версию функции
\verb|reverse(s)|, оборачивающую стринг на его же месте.

\section{Си-препроцессор}
\label{sec:c_preprocessor}

\index{макро-процессор}%
\index{препроцессор}%
\index{управляющая!строка}%
Некоторые возможности языка Си обеспечиваются препроцессором, который работает
на первом шаге компиляции. Наиболее часто используются две возможности:
\verb|#include|, включающая файл во время компиляции, и \verb|#define|,
заменяющая одни текстовые цепочки на другие. В этом разделе обсуждаются условная
компиляция и макроподстановка с аргументами.

\subsection{Включение файла}

\index{файл!включение}%
\index{include@\texttt{{\#}include}}%
Средство \verb|#include| позволяет, в частности, легко манипулировать наборами
\verb|#define| и деклараций. Любая строка вида

\begin{ShortCodeParWithCC}{\\\{\}}
#include "\textit{имя-файла}"
\end{ShortCodeParWithCC}

\noindent или

\begin{ShortCodeParWithCC}{\\\{\}}
#include <\textit{имя-файла}>
\end{ShortCodeParWithCC}

\noindent заменяется содержимым файла с именем \textit{имя-файла}. Если
\textit{имя-файла} заключено в двойные кавычки, то, как правило, файл ищется
среди исходных файлов программы; если такового не оказалось или
\textit{имя-файла} заключено в угловые скобки \verb|<| и \verb|>|, то поиск
осуществляется в системных библиотеках. Включаемый файл сам может содержать в
себе строки \verb|#include|.

\index{файл!головной!<stdio.h>@\texttt{<stdio.h>}}%
\index{stdio.h@\texttt{<stdio.h>}}%
Часто исходные файлы начинаются с нескольких строк \verb|#include|, ссылающихся
на общие инструкции \verb|#define| и \verb|extern|-декларации или прототипы
нужных библиотечных функций из головных файлов типа \verb|<stdio.h>|. (Строго
говоря, эти включения не обязательно являются файлами; технические детали того,
как осуществляется доступ к головной информации, зависят от конкретной
реализации.)

Средство \verb|#include| -- хороший способ собрать вместе декларации большой
программы. Он гарантирует, что все исходные файлы будут пользоваться одними и
теми же определениями и описаниями переменных, благодаря чему предотвращаются
особенно неприятные ошибки. Естественно, при внесении изменений во включаемый
файл все зависимые от него файлы должны перекомпилироваться.

\subsection{Макроподстановка}

\index{препроцессор!макрос}%
\index{define@\texttt{{\#}define}}%
Определение макроподстановки имеет вид:

\begin{ShortCodeParWithCC}{\\\{\}}
#define   \textit{имя}   \textit{замещающий-текст}
\end{ShortCodeParWithCC}

\noindent Макроподстановка используется для простейшей замены: во всех местах,
где встречается лексема \textit{имя}, вместо неё будет помещён
\textit{замещающий-текст}. Имена в \verb|#define| задаются по тем же правилам,
что и имена обычных переменных. Замещающий текст может быть произвольным. Обычно
замещающий текст завершает строку, в которой расположено слово \verb|#define|,
\index{define@\texttt{{\#}define}!в несколько строк}%
но в длинных определениях его можно продолжить на следующих строках, поставив в
конце каждой продолжаемой строки обратную наклонную черту \verb|\|. Область
действия имени в \verb|#define| простирается от данного определения до конца
файла. В определении макроподстановки могут фигурировать более ранние
\verb|#define|-определения. Подстановка осуществляется только для тех имён,
которые расположены вне текстов, заключённых в кавычки. Например, если
\verb|YES| определено с помощью \verb|#define|‚ то никакой подстановки в
\verb|printf("YES")| или в \verb|YESMAN| выполнено не будет.

Любое имя можно определить с произвольным замещающим текстом.
\index{бесконечный цикл \texttt{for(;;)}}%
\index{for(;;) бесконечный цикл@\texttt{for(;;)} бесконечный цикл}%
Например,

\begin{ShortCodePar}
#define forever for(;;)    /* бесконечный цикл */
\end{ShortCodePar}

\noindent определяет новое слово \verb|forever| для бесконечного цикла.

\index{макрос!с аргументами}%
\index{define@\texttt{{\#}define}!с аргументами}%
Макроподстановку можно определить с аргументами, вследствие чего замещающий
текст будет варьироваться в зависимости от задаваемых параметров. Например,
определим \verb|max| следующим образом:

\begin{ShortCodePar}
#define max(A, B)   ((A) > (B) ? (A) : (B))
\end{ShortCodePar}

\noindent Хотя обращения к \verb|max| выглядят как обычные обращения к функции,
они будут вызывать только текстовую замену. Каждый формальный параметр (в данном
случае \verb|A| и \verb|B|) будет заменяться соответствующим ему аргументом.
Так, строка

\begin{ShortCodePar}
x = max(p+q, r+s);
\end{ShortCodePar}

\noindent будет заменена на строку

\begin{ShortCodePar}
x = ((p+q) > (r+s) ? (p+q) : (r+s));
\end{ShortCodePar}

\noindent Поскольку аргументы допускают любой вид замены, указанное определение
\verb|max| подходит для данных любого типа, так что не нужно писать разные
\verb|max| для данных разных типов, как это было бы в случае задания с помощью
функций.

\index{побочный эффект}%
Если вы внимательно проанализируете текстовое расширение \verb|max|, то
обнаружите некоторые подводные камни. Выражения вычисляются дважды и, если они
вызывают побочный эффект (из-за инкрементных операций или функций ввода-вывода),
это может привести к нежелательным последствиям. Например,

\begin{ShortCodePar}
max(i++, j++)    /* НЕВЕРНО */
\end{ShortCodePar}

\noindent вызовет увеличение \verb|i| и \verb|j| дважды. Кроме того, следует
позаботиться о скобках, чтобы обеспечить нужный
\index{вычисление, порядок}%
\index{порядок!вычислений}%
порядок вычислений. Посмотрите, что случится, если при определении

\begin{ShortCodePar}
#define   square(x)   x * x    /* НЕВЕРНО */
\end{ShortCodePar}

\noindent воспользоваться записью типа \verb|square(z+1)|.

Тем не менее макросредства имеют свои преимущества.
\index{файл!головной!<stdio.h>@\texttt{<stdio.h>}}%
\index{stdio.h@\texttt{<stdio.h>}}%
Практическим примером их использования являются часто применяемые \verb|getchar|
и \verb|putchar| из \verb|<stdio.h>|‚ которые реализованы с помощью макросов,
чтобы избежать накладных расходов от вызова функции на каждую обрабатываемую
литеру. Функции в \verb|<ctype.h>| обычно также реализуются с помощью макросов.

\index{undef@\texttt{{\#}undef}}%
Имена можно <<скрыть>> от препроцессора с помощью \verb|#undef|.

\begin{ShortCodePar}
#undef getchar
int getchar(void) { ... }
\end{ShortCodePar}

\noindent Как правило, это делается, чтобы макроопределение <<перекрыть>>
настоящей функцией с тем же именем.

Имена формальных параметров не заменяются, если они находятся в стрингах,
заключённых в кавычки.
\index{препроцессор!оператор \texttt{\#}}%
А вот комбинация в замещающем тексте: формальный параметр с предшествующим
знаком \verb|#| -- в макрорасширении будет заменена на аргумент, заключённый в
кавычки.
\index{конкатенация!стрингов}%
Такую конструкцию можно использовать для конкатенации с другими литерными
стрингами, как‚ например‚ в следующем макроопределении, предназначенном для
отладочной выдачи:

\begin{ShortCodePar}
#define   dprint(expr)   printf(#expr " = %g\n", expr)
\end{ShortCodePar}

\noindent Обращение к макроопределению

\begin{ShortCodePar}
dprint(x/y)
\end{ShortCodePar}

\noindent даст расширение

\begin{ShortCodePar}
printf("x/y" " = %g\n", x/y);
\end{ShortCodePar}

\noindent а в результате конкатенации двух соседних стрингов получим

\begin{ShortCodePar}
printf("x/y = %g\n", x/y);
\end{ShortCodePar}

\noindent Внутри фактического аргумента каждый знак \verb|"| заменяется на
\verb|\"|, а каждая \verb|\| на \verb|\\| так, чтобы результат подстановки
приводил к правильной литерной константе.

\index{конкатенация!лексем}%
\index{лексема!конкатенация}%
\index{препроцессор!оператор \texttt{\#\#}}%
Оператор \verb|##| препроцессором понимается как операция конкатенации; он
позволяет в макрорасширениях конкатенировать аргументы. Если в замещающем тексте
параметр соседствует с \verb|##|, то он заменяется на соответствующий ему
аргумент, а оператор \verb|##| и окружающие его пробельные литеры выбрасываются.
Например, в макроопределении \verb|paste| конкатенируются два аргумента

\begin{ShortCodePar}
#define   paste(front, back)   front ## back
\end{ShortCodePar}

\noindent так что \verb|paste(name, 1)| сгенерирует имя \verb|name1|.

Правила вложенных использований оператора \verb|##| не определены; другие
подробности, относящиеся к \verb|##|, можно найти в
приложении~\ref{apx:ref_manual}.

\paragraph{Упражнение 4.14.} Определите \verb|swap(t,x,y)| в виде макроса,
который осуществляет обмен значениями указанного типа \verb|t| между аргументами
\verb|x| и \verb|y|. (Примените блочную структуру.)

\subsection{Условная компиляция}

\index{условная компиляция}%
Самим ходом препроцессирования можно управлять с помощью условных инструкций.
Они представляют собой средство для выборочного включения того или иного текста
программы в зависимости от значения условия, вычисляемого во время компиляции.

Вычисляется
\index{выражение!константное}%
\index{константное выражение}%
\index{if@\texttt{{\#}if}}%
константное целое выражение, заданное в строке \verb|#if|.
\index{оператор!sizeof@\texttt{sizeof}}%
Это выражение не должно содержать ни одного оператора \verb|sizeof| или
приведения к типу и ни одной \verb|enum|-константы. Если оно имеет ненулевое
значение, то будут включены все последующие строки вплоть до
\index{endif@\texttt{{\#}endif}}%
\verb|#endif|,
\index{elif@\texttt{{\#}elif}}%
или \verb|#elif|,
\index{else a@\texttt{{\#}else}}%
или \verb|#else|. (Инструкция препроцессора \verb|#elif|
похожа на \verb|else if|.)
\index{препроцессор!оператор \texttt{defined}}%
\index{defined@\texttt{defined}}%
Выражение \verb|defined(|\textit{\Verb|имя|}\verb|)| в \verb|#if| есть $1$, если
\textit{имя} было определено, и $0$ в противном случае.

Например, чтобы застраховаться от повторного включения головного файла
\verb|hdr.h|, его можно оформить следующим образом:

\begin{ShortCodePar}
#if !defined(HDR)
#define HDR

/* здесь содержимое hdr.h */

#endif
\end{ShortCodePar}

\noindent При первом включении файла \verb|hdr.h| будет определено имя
\verb|HDR|, а при последующих включениях препроцессор обнаружит, что имя
\verb|HDR| уже определено и перепрыгнет сразу на \verb|#endif|. Этот приём может
оказаться полезным, когда нужно избежать многократного включения одного и того
же файла. Если им пользоваться систематически, то в результате каждый головной
файл будет сам включать головные файлы, от которых он зависит, освободив от
этого занятия пользователя.

Вот пример цепочки проверок имени \verb|SYSTEM|, позволяющей выбрать нужный файл
для включения:

\begin{LongCodePar}
#if SYSTEM == SYSV
    #define HDR "sysv.h"
#elif SYSTEM == BCD
    #define HDR "bcd.h"
#elif SYSTEM == MSDOS
    #define HDR "msdos.h"
#else
    #define HDR "default.h"
#endif
#include HDR
\end{LongCodePar}

\noindent%
\index{ifdef@\texttt{{\#}ifdef}}%
\index{ifndef@\texttt{{\#}ifndef}}%
Инструкции \verb|#ifdef| и \verb|#ifndef| специально предназначены для
проверки того, определено или не определено заданное в них имя. И следовательно,
первый пример, приведённый выше для иллюстрации \verb|#if|, можно записать и в
таком виде:

\begin{ShortCodePar}
#ifndef HDR
#define HDR

/* здесь содержимое hdr.h */

#endif
\end{ShortCodePar}
