Керниган и Ритчи - Язык программирования Си (793773), страница 10
Текст из файла (страница 10)
В общем виде условная инструкциязаписывается так:if (выражение)инструкция1elseинструкция2В конструкции if-else выполняется одна и только одна из двух инструкций. Если выражение истинно, товыполняется инструкция1, если нет, то инструкция2. Каждая из этих двух инструкций представляет собойлибо одну инструкцию, либо несколько, заключенных в фигурные скобки. В нашей программе после elseстоит инструкция if, управляющая двумя такими инструкциями.Упражнение 1.11. Как протестировать программу подсчета слов? Какой ввод вероятнее всего обнаружитошибки, если они были допущены?Упражнение 1.12. Напишите программу, которая печатает содержимое своего ввода, помещая по одномуслову на каждой строке.1.6.
МассивыА теперь напишем программу, подсчитывающую по отдельности каждую цифру, символы-разделители(пробелы, табуляции и новые-строки) и все другие символы. Это несколько искусственная программа, но онапозволит нам в одном примере продемонстрировать еще несколько возможностей языка Си. Имеетсядвенадцать категорий вводимых символов. Удобно все десять счетчиков цифр хранить в массиве, а не в видедесяти отдельных переменных. Вот один из вариантов этой программы:#include <stdio.h>/* подсчет цифр, символов-разделителей и прочих символов */main(){int с, i, nwhite, nother;int ndigit[10];nwhite = nother = 0;for (i = 0; i < 10; ++i)ndigit[i]= 0;while ((c = getchar()) != EOF)if (c >= '0' && с <= '9' )++ndigit[c - '0' ];else if (c == ' ' || с == '\n' || с == '\t')++nwhite;else++nother;printf ("цифры =");for (i=0; i < 10; ++i)printf(" %d", ndigit[i]);printf (", символы-разделители = %d, прочие = %d\n", nwhite, nother);}В результате выполнения этой программы будет напечатан следующий результат:цифры = 9 3 0 0 0 0 0 0 0 1 , символы-разделители = 123, прочие = 345Объявлениеint ndigit[10];объявляет ndigit массивом из 10 значений типа int.
В Си элементы массива всегда нумеруются начиная снуля, так что элементами этого массива будут ndigit[0], ndigit[1],…, ndigit[9], что учитывается вfor-циклах (при инициализации и печати массива).Индексом может быть любое целое выражение, образуемое целыми переменными (например, 1) и целымиконстантами.Приведенная программа опирается на определенные свойства кодировки цифр. Например, проверкаif (с >= '0' && с <= '9' ) ...определяет, является ли находящийся в c символ цифрой.
Если это так, тоc - '0'есть числовое значение цифры. Сказанное справедливо только в том случае, если для ряда значений '0' ,'1',...,'9' каждое следующее значение на 1 больше предыдущего. К счастью, это правило соблюдается вовсех наборах символов.По определению, значения типа char являются просто малыми целыми, так что переменные и константытипа char в арифметических выражениях идентичны значениям типа int.
Это и естественно, и удобно;например, c - '0' есть целое выражение с возможными значениями от 0 до 9, которые соответствуютсимволам от '0' до '9', хранящимся в переменной c. Таким образом, значение данного выраженияявляется правильным индексом для массива ndigit.Следующий фрагмент определяет, является символ цифрой, символом-разделителем или чем-нибудь иным.if (с >= '0' && с <= '9')++ndigit[c - '0'];else if (с ==' ' || с == '\n' || е == '\t')++nwhite;else++nother;Конструкция видаif (условие1)инструкция1else if (условие2)инструкция2elseинструкцияnчасто применяется для выбора одного из нескольких альтернативных путей, имеющихся в программе.Условия вычисляются по порядку в направлении сверху вниз до тех пор, пока одно из них не будетудовлетворено; в этом случае будет выполнена соответствующая ему инструкция, и работа всей конструкциизавершится.
(Любая из инструкций может быть группой инструкций в фигурных скобках.) Если ни одно изусловий не удовлетворено, выполняется последняя инструкция, расположенная сразу за else, если таковаяимеется. Если же else и следующей за ней инструкции нет (как это было в программе подсчета слов), тоникакие действия вообще не производятся. Между первым if и завершающим else может быть сколькоугодно комбинаций видаelse if (условие)инструкцияКогда их несколько, программу разумно форматировать так, как мы здесь показали. Если же каждыйследующий if сдвигать вправо относительно предыдущего else, то при длинном каскаде проверок текстокажется слишком близко прижатым к правому краю страницы.Инструкция switch, речь о которой пойдет в главе 3, обеспечивает другой способ изображениямногопутевого ветвления на языке Си. Он более подходит, в частности, тогда, когда условием переходаслужит совпадение значения некоторого выражения целочисленного типа с одной из констант, входящих взаданный набор.
Вариант нашей программы, реализованной с помощью switch, приводится в параграфе3.4.Упражнение 1.13. Напишите программу, печатающую гистограммы длин вводимых слов. Гистограмму легкорисовать горизонтальными полосами. Рисование вертикальными полосами — более трудная задача.Упражнение 1.14. Напишите программу, печатающую гистограммы частот встречаемости вводимыхсимволов.1.7.
ФункцииФункции в Си играют ту же роль, что и подпрограммы и функции в Фортране или процедуры и функции вПаскале. Функция обеспечивает удобный способ отдельно оформить некоторое вычисление и пользоватьсяим далее, не заботясь о том, как оно реализовано. После того, как функции написаны, можно забыть, как онисделаны, достаточно знать лишь, что они умеют делать.
Механизм использования функции в Си удобен, легоки эффективен. Нередко вы будете встречать короткие функции, вызываемые лишь единожды; ониоформлены в виде функции с одной-единственной целью — получить более ясную программу.До сих пор мы пользовались готовыми функциями вроде main, getchar и putchar, теперь настала поранам самим написать несколько функций. В Си нет оператора возведения в степень вроде ** в Фортране.Поэтому проиллюстрируем механизм определения функции на примере функции power(m, n), котораявозводит целое m в целую положительную степень n. Так, power(2, 5) имеет значение 32.
На самом деледля практического применения эта функция малопригодна, так как оперирует лишь малыми целымистепенями, однако она вполне может послужить иллюстрацией. (В стандартной библиотеке есть функцияpow(x, у), вычисляющая ху.)Итак, мы имеем функцию power и главную функцию main, пользующуюся ее услугами, так что всяпрограмма выглядит следующим образом:#include <stdio.h>int power(int m, int n);/* тест функции power */main(){int i;for (i = 0; i < 10; ++i)printf("%d %d %d\n", i, power(2,i), power(-3, i));return 0;}/* возводит base в п-ю степень; n >= 0 */int power(int base, int n){int i, p;P = 1;for (i = 1; i <= n; ++i)p = p * base;return p;}Определение любой функции имеет следующий вид:тип-результата имя-функции (список параметров, если он есть){объявленияинструкции}Определения функций могут располагаться в любом порядке в одном или в нескольких исходных файлах, нолюбая функция должна быть целиком расположена в каком-то одном.
Если исходный текст программыраспределен по нескольким файлам, то, чтобы ее скомпилировать и загрузить, вам придется сказатьнесколько больше, чем при использовании одного файла; но это уже относится к операционной системе, а нек языку. Пока мы предполагаем, что обе функции находятся в одном файле, так что будет достаточно техзнаний, которые вы уже получили относительно запуска программ на Си.В следующей строке из функции main к power обращаются дважды.printf("%d %d %d\n", i, power(2,i), power(-3,1));При каждом вызове функции power передаются два аргумента, и каждый раз главная программа main вответ получает целое число, которое затем приводится к должному формату и печатается.
Внутри выраженияpower(2,1) представляет собой целое значение точно так же, как 2 или i. (Не все функции в качестверезультата выдают целые значения; подробно об этом будет сказано в главе 4.)В первой строке определения power:int power(int base, int n)указываются типы параметров, имя функции и тип результата. Имена параметров локальны внутри power,это значит, что они скрыты для любой другой функции, так что остальные подпрограммы могут свободнопользоваться теми же именами для своих целей.
Последнее утверждение справедливо также дляпеременных i и р: i в power и i в main не имеют между собой ничего общего.Далее параметром мы будем называть переменную из списка параметров, заключенного в круглые скобки изаданного в определении функции, а аргументом — значение, используемое при обращении к функции.Иногда в том же смысле мы будем употреблять термины формальный аргумент и фактический аргумент.Значение, вычисляемое функцией power, возвращается в main с помощью инструкции return.














