Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Tema_1._Strukturi_ta_ob_jednannja.doc
Скачиваний:
0
Добавлен:
01.05.2025
Размер:
202.15 Кб
Скачать

Масиви структур

Розглянемо програму, що визначає число входжень кожного ключового слова в текст Сі-програми. Нам потрібно вміти зберігати ключові слова у вигляді масиву рядків і лічильники ключових слів у вигляді масиву цілих. Один з можливих варіантів - це мати два паралельних масиву:

char * keyword [NKEYS]; int keycount [NKEYS];

Однак саме той факт, що вони є паралельними, підказує нам іншу організацію зберігання - через масив структур. Кожне ключове слово можна описати парою характеристик

char * word; int count; Такі пари складають масив. Оголошення struct key { char * word; int count; } Keytab [NKEYS];

оголошує структуру типу key і визначає масив keytab, кожен елемент якого є структурою цього типу і якому десь буде виділена пам'ять. Це ж можна записати й по-іншому:

struct key { char * word; int count; }; key keytab [NKEYS];

Так як keytab містить постійний набір імен, його найлегше зробити зовнішнім масивом і ініціалізувати один раз на момент визначення. Ініціалізація структур аналогічна раніше демонстрованих ініціалізації - за визначенням слід список ініціалізаторов, укладений у фігурні дужки:

struct key { char * word; int count; } Keytab [] = { "Auto", 0, "Break", 0, "Case", 0, "Char", 0, "Const", 0, "Continue", 0, "Default", 0, /*...*/ "Unsigned", 0, "Void", 0, "Volatile", 0, "While", 0 };

Ініціалізатор задаються парами, щоб відповідати конфігурації структури. Строго кажучи, пару ініціалізаторов для кожної окремої структури варто було б укласти у фігурні дужки, як, наприклад, в

{"Auto", 0}, {"Break", 0}, {"Case", 0}, ...

Однак коли ініціалізатор - прості константи або рядки символів і всі вони є в наявності, у внутрішніх дужках немає необхідності. Кількість елементів масиву keytab буде обчислено за кількістю ініціалізаторов, оскільки вони представлені повністю, а всередині квадратних дужок "[]" нічого не задано.

Програма підрахунку ключових слів починається з визначення keytab. Програма main читає введення, багаторазово звертаючись до функції getword і отримуючи на кожному її виклику чергове слово. Кожне слово шукається в keytab. Для цього використовується функція бінарного пошуку. Список ключових слів повинен бути впорядкований в алфавітному порядку.

# Include <stdio.h> # Include <ctype.h> # Include <string.h> # Define MAXWORD 100 int 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-1] * / 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; else return 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])

Перевага такого роду записів у тому, що їх не треба коppектіровать при зміні типу. Оскільки препроцесор не звертає уваги на імена типів, оператор 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. По завершенні набору літер-цифр виявляється, що getword взяла зайвий символ. Звернення до ungetch дозволяє повернути його назад у вхідний потік. У getword використовуються також isspace - для пропуску символів-роздільників, isalpha - для ідентифікації букв і isalnum - для розпізнавання букв-цифр. Всі вони описані в стандартному заголовному файлі <ctype.h>.

 

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]