Главная » Просмотр файлов » Керниган и Ритчи - Язык программирования Си

Керниган и Ритчи - Язык программирования Си (793773), страница 33

Файл №793773 Керниган и Ритчи - Язык программирования Си (Керниган и Ритчи - Язык программирования Си) 33 страницаКерниган и Ритчи - Язык программирования Си (793773) страница 332019-04-24СтудИзба
Просмтор этого файла доступен только зарегистрированным пользователям. Но у нас супер быстрая регистрация: достаточно только электронной почты!

Текст из файла (страница 33)

Число элементов массива keytab будет вычислено по количествуинициализаторов, поскольку они представлены полностью, а внутри квадратных скобок"[]" ничего незадано.Программа подсчета ключевых слов начинается с определения keytab. Программа main читает ввод,многократно обращаясь к функции getword и получая на каждом ее вызове очередное слово. Каждое словоищется в keytab. Для этого используется функция бинарного поиска, которую мы написали в главе 3. Списокключевых слов должен быть упорядочен в алфавитном порядке.#include <stdio.h>#include <ctype.h>#include <string.h>#define MAXWORD 100int getword(char *, int);int binsearch(char *, struct key *, int);/* подсчет ключевых слов Си */main(){int n;char word[MAXWORD];while(getword(word, MAXWORD) != EOF)if (isalpha(word[0]))if ((n = binsearch(word, keytab, NKEYS)) >= 0)keytab[n].count++;for (n = 0; n < NKEYS; n++)if (keytab[n].count > 0)printf("%4d %s\n", keytab[n].count, keytab[n].word);return 0;}/* binsearch: найти слово в tab[0] ...

tab[n - Т] */int binsearch(char *word, struct key tab[], int n){int cond;int low, high, mid;low = 0;high = n - 1 ;while (low <= high) {mid = (low + high)/2;if ((cond = strcmp(word, tab[mid].word)) < 0)high = mid - 1;else if (cond > 0)low = mid + 1;elsereturn mid;}return -1;}Чуть позже мы рассмотрим функцию getword, а сейчас нам достаточно знать, что при каждом ее вызовеполучается очередное слово, которое запоминается в массиве, заданном первым аргументом.NKEYS — количество ключевых слов в keytab. Хотя мы могли бы подсчитать число таких слов вручную,гораздо легче и безопасней сделать это с помощью машины, особенно если список ключевых слов можетбыть изменен. Одно из возможных решений — поместить в конец списка инициализаторов пустой указатель(NULL) и затем перебирать в цикле элементы keytab, пока не встретится концевой элемент.Но возможно и более простое решение.

Поскольку размер массива полностью определен во времякомпиляции и равен произведению количества элементов массива на размер его отдельного элемента, числоэлементов массива можно вычислить по формулеразмер keytab / размер struct keyВ Си имеется унарный оператор sizeof , который работает во время компиляции. Его можно применять длявычисления размера любого объекта. Выраженияsizeof объектиsizeof (имя-типа)выдают целые значения, равные размеру указанного объекта или типа в байтах.

(Строго говоря, sizeofвыдает беззнаковое целое, тип которого size_t определен в заголовочном файле <stddef.h>.) Чтокасается объекта, то это может быть переменная, массив или структура. В качестве имени типа можетвыступать имя базового типа (int, double...) или имя производного типа, например структуры илиуказателя.В нашем случае, чтобы вычислить количество ключевых слов, размер массива надо поделить на размеродного элемента. Указанное вычисление используется в инструкции #define для установки значенияNKEYS:#define NKEYS (sizeof keytab / sizeof(struct key))Этот же результат можно получить другим способом — поделить размер массива на размер какого-то егоконкретного элемента:#define NKEYS (sizeof keytab / sizeof keytab[0])Преимущество такого рода записей в том, что их не надо корректировать при изменении типа.Поскольку препроцессор не обращает внимания на имена типов, оператор sizeof нельзя применять в #if.Но в #define выражение препроцессором не вычисляется, так что предложенная нами запись допустима.Теперь поговорим о функции getword.

Мы написали getword в несколько более общем виде, чемтребуется для нашей программы, но она от этого не стала заметно сложнее. Функция getword берет извходного потока следующее "слово". Под словом понимается цепочка букв-цифр, начинающаяся с буквы, илиотдельный символ, отличный от символа-разделителя. В случае конца файла функция возвращает EOF, востальных случаях ее значением является код первого символа слова или сам символ, если это не буква./* getword: принимает следующее слово или символ из ввода */int getword (char *word, int lim){int c, getch(void);void ungetch(int);char *w = word;while (isspace(c = getch()));if (c != EOF)*w++ = c;if (!isalpha(c)) {*w = '\0';return c;}for ( ; --lim > 0; w++)if (!isalnum(*w = getch())) {ungetch(*w);break;}*w = '\0';return word[0];}Функция getword обращается к getch и ungetch, которые мы написали в главе 4. По завершении наборабукв-цифр оказывается, что getword взяла лишний символ.

Обращение к ungetch позволяет вернуть егоназад во входной поток. В getword используются также isspace — для пропуска символов-разделителей,isalpha — для идентификации букв и isalnum — для распознавания букв-цифр. Все они описаны встандартном заголовочном файле <ctype.h>.Упражнение 6.1. Наша версия getword не обрабатывает должным образом знак подчеркивания, строковыеконстанты, комментарии и управляющие строки препроцессора. Напишите более совершенный вариантпрограммы.6.4.

Указатели на структурыДля иллюстрации некоторых моментов, касающихся указателей на структуры и массивов структур,перепишем программу подсчета ключевых слов, пользуясь для получения элементов массива вместоиндексов указателями.Внешнее объявление массива keytab остается без изменения, a main и binsearch нужномодифицировать.#include <stdio.h>#include <ctype.h>#include <string.h>#define MAXWORD 100int getword(char *, int);struct key *binsearch(char *, struct key *, int);/* подсчет ключевых слов Си: версия с указателями */main(){char word [MAXWORD];struct key *p;while (getword(word, MAXWORD) != EOF)if (isalpha(word[0]))if ((p = binsearch(word, keytab, NKEYS)) != NULL)p->count++;for (p = keytab; p < keytab + NKEYS; p++)if (p->count > 0)printf("%4d %s\n", p->count, p->word);return 0;}/* binsearch: найти слово word в tab[0]...tab[n-1] */struct key *binsearch(char *word, struct key *tab, int n){int cond;struct key *low = &tab[0];struct key *high = &tab[n];struct key *mid;while (low < high) {mid = low + (high - low) / 2;if ((cond = strcmp(word, mid->word)) < 0)high = mid;else if (cond > 0) ,low = mid + 1 ;elsereturn mid;}return NULL;}Некоторые детали этой программы требуют пояснений.

Во-первых, описание функции binsearch должноотражать тот факт, что она возвращает указатель на struct key, а не целое; это объявлено как в прототипефункции, так и в функции binsearch. Если binsearch находит слово, то она выдает указатель на него, впротивном случае она возвращает NULL. Во-вторых, к элементам keytab доступ в нашей программеосуществляется через указатели. Это потребовало значительных изменений в binsearch.Инициализаторами для low и high теперь служат указатели на начало и на место сразу после конца массива.Вычисление положения среднего элемента с помощью формулыmid = (low + high) / 2/* НЕВЕРНО */не годится, поскольку указатели нельзя складывать. Однако к ним можно применить операцию вычитания, итак как high-low есть число элементов, присваиваниеmid = low + (high-low) / 2превратит mid в указатель на элемент, лежащий посередине между low и high.Самое важное при переходе на новый вариант программы — сделать так, чтобы не генерировалисьнеправильные указатели и не было попыток обратиться за пределы массива.

Проблема в том, что и &tab[1], и &tab[n] находятся вне границ массива. Первый адрес определенно неверен, нельзя такжеосуществить доступ и по второму адресу. По правилам языка, однако, гарантируется, что адрес ячейкипамяти, следующей сразу за концом массива (т. е. &tab[n]), в арифметике с указателями воспринимаетсяправильно.В главной программе main мы написалиfor (р = keytab; р < keytab + NKEYS; р++)Если р — это указатель на структуру, то при выполнении операций с р учитывается размер структуры.

Поэтомур++ увеличит р на такую величину, чтобы выйти на следующий структурный элемент массива, а проверкаусловия вовремя остановит цикл.Не следует, однако, полагать, что размер структуры равен сумме размеров ее элементов. Вследствиевыравнивания объектов разной длины в структуре могут появляться безымянные "дыры". Например, еслипеременная типа char занимает один байт, a int — четыре байта, то для структурыstruct {char с;int i;};может потребоваться восемь байтов, а не пять.

Оператор sizeof возвращает правильное значение.Наконец, несколько слов относительно формата программы. Если функция возвращает значение сложноготипа, как, например, в нашем случае она возвращает указатель на структуру:struct key *binsearch(char *word, struct key *tab, int n)то "высмотреть" имя функции оказывается совсем не просто. В подобных случаях иногда пишут так:struct key *binsearch(char *word, struct key *tab, int n)Какой форме отдать предпочтение — дело вкуса. Выберите ту, которая больше всего вам нравится, ипридерживайтесь ее.6.5. Структуры со ссылками на себяПредположим, что мы хотим решить более общую задачу — написать программу, подсчитывающую частотувстречаемости для любых слов входного потока.

Характеристики

Тип файла
PDF-файл
Размер
2,25 Mb
Тип материала
Высшее учебное заведение

Список файлов книги

Свежие статьи
Популярно сейчас
Зачем заказывать выполнение своего задания, если оно уже было выполнено много много раз? Его можно просто купить или даже скачать бесплатно на СтудИзбе. Найдите нужный учебный материал у нас!
Ответы на популярные вопросы
Да! Наши авторы собирают и выкладывают те работы, которые сдаются в Вашем учебном заведении ежегодно и уже проверены преподавателями.
Да! У нас любой человек может выложить любую учебную работу и зарабатывать на её продажах! Но каждый учебный материал публикуется только после тщательной проверки администрацией.
Вернём деньги! А если быть более точными, то автору даётся немного времени на исправление, а если не исправит или выйдет время, то вернём деньги в полном объёме!
Да! На равне с готовыми студенческими работами у нас продаются услуги. Цены на услуги видны сразу, то есть Вам нужно только указать параметры и сразу можно оплачивать.
Отзывы студентов
Ставлю 10/10
Все нравится, очень удобный сайт, помогает в учебе. Кроме этого, можно заработать самому, выставляя готовые учебные материалы на продажу здесь. Рейтинги и отзывы на преподавателей очень помогают сориентироваться в начале нового семестра. Спасибо за такую функцию. Ставлю максимальную оценку.
Лучшая платформа для успешной сдачи сессии
Познакомился со СтудИзбой благодаря своему другу, очень нравится интерфейс, количество доступных файлов, цена, в общем, все прекрасно. Даже сам продаю какие-то свои работы.
Студизба ван лав ❤
Очень офигенный сайт для студентов. Много полезных учебных материалов. Пользуюсь студизбой с октября 2021 года. Серьёзных нареканий нет. Хотелось бы, что бы ввели подписочную модель и сделали материалы дешевле 300 рублей в рамках подписки бесплатными.
Отличный сайт
Лично меня всё устраивает - и покупка, и продажа; и цены, и возможность предпросмотра куска файла, и обилие бесплатных файлов (в подборках по авторам, читай, ВУЗам и факультетам). Есть определённые баги, но всё решаемо, да и администраторы реагируют в течение суток.
Маленький отзыв о большом помощнике!
Студизба спасает в те моменты, когда сроки горят, а работ накопилось достаточно. Довольно удобный сайт с простой навигацией и огромным количеством материалов.
Студ. Изба как крупнейший сборник работ для студентов
Тут дофига бывает всего полезного. Печально, что бывают предметы по которым даже одного бесплатного решения нет, но это скорее вопрос к студентам. В остальном всё здорово.
Спасательный островок
Если уже не успеваешь разобраться или застрял на каком-то задание поможет тебе быстро и недорого решить твою проблему.
Всё и так отлично
Всё очень удобно. Особенно круто, что есть система бонусов и можно выводить остатки денег. Очень много качественных бесплатных файлов.
Отзыв о системе "Студизба"
Отличная платформа для распространения работ, востребованных студентами. Хорошо налаженная и качественная работа сайта, огромная база заданий и аудитория.
Отличный помощник
Отличный сайт с кучей полезных файлов, позволяющий найти много методичек / учебников / отзывов о вузах и преподователях.
Отлично помогает студентам в любой момент для решения трудных и незамедлительных задач
Хотелось бы больше конкретной информации о преподавателях. А так в принципе хороший сайт, всегда им пользуюсь и ни разу не было желания прекратить. Хороший сайт для помощи студентам, удобный и приятный интерфейс. Из недостатков можно выделить только отсутствия небольшого количества файлов.
Спасибо за шикарный сайт
Великолепный сайт на котором студент за не большие деньги может найти помощь с дз, проектами курсовыми, лабораторными, а также узнать отзывы на преподавателей и бесплатно скачать пособия.
Популярные преподаватели
Добавляйте материалы
и зарабатывайте!
Продажи идут автоматически
7029
Авторов
на СтудИзбе
260
Средний доход
с одного платного файла
Обучение Подробнее