Упражнение 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 == ' ' || c == '\n' || c == '\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-циклах (при инициализации и печати массива).
Индексом может быть любое целое выражение, образуемое целыми переменными (например i) и целыми константами.
Приведенная программа опирается на определенные свойства кодировки цифр. Например, проверка
if (c = '0' && c = '9')
определяет, является ли находящийся в c символ цифрой. Если это так, то
c -'0'
есть числовое значение цифры. Сказанное справедливо только в том случае, если для ряда значений '0','1',, '9' каждое следующее значение на 1 больше предыдущего. К счастью, это правило соблюдается во всех наборах
символов.
По определению, значения типа char являются просто малыми целыми, так что переменные и константы типа char в арифметических выражениях идентичны значениям типа int. Это и естественно, и удобно; например, c-'0' есть целое выражение с возможными значениями от 0 до 9, которые соответствуют символам от '0' до '9', хранящимся в переменной c. Таким образом, значение данного выражения является правильным индексом для массива ndigit.
Следующий фрагмент определяет, является символ цифрой, символом-разделителем или чем-нибудь иным.
if (c = '0' && c = '9')
++n[c-'0'];
else if (c ==' ' || c == '\n' || c == '\t')
++nwhite;
else
++nother;
Конструкция вида
if (условие1)
инструкция1
else if (условие2)
инструкция2
:
:
else
инструкция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, y), вычисляющая x в степени y.)
Итак, мы имеем функцию 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-ю степень, n = 0 */
int power(int base, int n)
{
int i, p;
p = 1;
for (i = 1; i = n; ++i)