7. Обработка сивольных данных.
Обработка символьных данных Язык Си лучше всего подходит для системной работы: написания компиляторов, интерпретаторов, опрерационных систем, редакторов текста и.т.п. В стнадартной библиотеке Си предусмотрены многие полезные функции, выполняющие простые действия с символьными данными.
Рассмотрим из них - putchar и getchar выполняющие ввод и вывод символа соответственно и создадим на их основе ряд своих полезных функций.
Рассмотрим примеры. Программа 1.вывводит на экран всепрописныелатин-скиебуквы. Мы уже напоминали что типы char и intвзаимозаменяемы.
Последовательное прибавление к очередному значению с обеспечивает выбор очередной буквы ввиду их лексической упорядоченности.
Пример 1.
#include <stdio.h>
intmain()
{
char c;
c='A'
while(c<='Z')
{
putchar(c);
c=c+1;
}
}
Прежде, чем перейти к рассмотрению примеров, обсудим, как машина должна определять конец входного потока символов, вводимых с клавиатуры терминала. Можно, конечно, выбрать некоторый символ как признак конца потока, но нужна гарантия, что он нигде не повторится. В использованной нами операционной системе для получения такого символа надо нажать CTRL+Z. В программе значение этого символа мы будем использовать через символическое имя EOF(end of file). Теперь мы можем написать программы копирования файла(прмер 2.8) . Пока не обнаружен конец входного потока, ЭВМ получает с клавиатуры символ (это делает функция getchar) и сразу же выодит его на экран дисплея с помощью функции putchar. Для завершения программы достаточно нажать CTRL+Z.
Пример 2. /*ЭХО ПРОГРАММА*/
#include <stdio.h>
int main()
{
char c;
c=getchar();
while(c!=EOF)
{
putchar(c);
c=getchar();
}
}
Программу копирования можно написать и более компактно. В языке Си любое присваивание например, c=getchar(), можно использовать в любом выражении в качестве операнда; его значение - это просто значение, присваиваеое левой части. Учитывая сказанное, перепишем Эхо Программу . Это компактная, элегантная программа принимает символ с клавиатуры и присваивает его переменной с, а затем сравнивает его с признаком конца файла. Пока этот признак не обнаружен, выполняется тело цикла и символ выдается на экран. В противном случае цикл, а вместе с ним и вся программа завершаются.
Пример 3. *ЭХО ПРОГРАММА ВАР2.*/
#includestdio.h
int main()
{
char c; while((c=getchar())!=EOF)putchar(c);
}
Отметим, что включение присваиваний в проверки - сильноеединство языка, способствующее созданию программ. Учтите, что скобки вокруг присваивания внутри условия необходимы: приоритет операции != выше приоритета операции присваивания.
Скобки внутри условия, вокруг присваивания, необходимы. Приоритет != выше, чем приоритет =, из чего следует, что при отсутствии скобок проверка != будет выполняться до операции присваивания =. Таким образом, запись
c=getchar() !=EOF
эквивалентна записи
c= (getchar() !=EOF)
А это совсем не то, что нам нужно: переменной cбудет присваиваться 0 или 1 в зависимости от того, встретит или не встретитgetcharпризнак конца файла.
Подсчет символов
Следующая программа занимается подсчетом символов; она имеет много сходных черт с программой копирования.
#include<stdio.h>
/* подсчет вводимых символов; 1-я версия */
main()
{
long nc;
nc = 0;
while (getchar() != EOF)
++nc;
printf(“%ld\n”, nc);
}
Инструкция
++nc;
представляет новый оператор ++, который означает увеличить на единицу. Вместо этого можно было бы написать nc=nc+1, но ++ncнамного короче, а часто и эффективнее. Существует аналогичный оператор --, означающий уменьшить на единицу. Операторы ++ и -- могут быть как префиксными (++nc), так и постфиксными (nc++). Как будет показано в главе 2, эти две формы в выражениях имеют разные значения, но и ++nc, иnc++ добавляют кncединицу. В данном случае мы остановились на префиксной записи.
Программа подсчета символов накапливает сумму в переменной типа long. Целые типаlongимеют не менее 32 битов. Хотя на некоторых машинах типыintиlongимеют одинаковый размер, существуют, однако, машины, в которыхintзанимает 16 бит с максимально возможным значением 32767, а это - сравнительно маленькое число, и счетчик типаintможет переполниться. Спецификация %ldвprintfуказывает, что соответствующий аргумент имеет типlong.
Возможно охватить еще больший диапазон значений, если использовать тип double(т. е.floatс двойной точностью). Применим также инструкциюforвместоwhile, чтобы продемонстрировать другой способ написания цикла.
#include<stdio.h>
/* подсчет вводимых символов; 2-й версия */
main()
{
double nc;
for (nc = 0; getchar() != EOF; ++nc)
;
printf(“%.0f\n”, nc);
}
В printfспецификатор %fприменяется как дляfloat, так и дляdouble; спецификатор %.0fозначает печать без десятичной точки и дробной части (последняя в нашем случае отсутствует).
Тело указанного for-цикла пусто, поскольку кроме проверок и приращений счетчика делать ничего не нужно. Но правила грамматики Си требуют, чтобыfor- цикл имел тело. Выполнение этого требования обеспечивает изолированная точка с запятой, называемая пустой инструкцией. Мы поставили точку с запятой на отдельной строке для большей наглядности.
Наконец, заметим, что если ввод не содержит ни одного символа, то при первом же обращении к getcharусловие вwhileилиforне будет выполнено и программа выдаст нуль, что и будет правильным результатом. Это важно. Одно из привлекательных свойств цикловwhileиforсостоит в том, что условие проверяется до того, как выполняется тело цикла. Если ничего делать не надо, то ничего делаться и не будет, пусть даже тело цикла не выполнится ни разу. Программа должна вести себя корректно и при нулевом количестве вводимых символов. Само устройство цикловwhileиforдает дополнительную уверенность в правильном поведении программы в случае граничных условий.