Главная Случайная страница


Полезное:

Как сделать разговор полезным и приятным Как сделать объемную звезду своими руками Как сделать то, что делать не хочется? Как сделать погремушку Как сделать так чтобы женщины сами знакомились с вами Как сделать идею коммерческой Как сделать хорошую растяжку ног? Как сделать наш разум здоровым? Как сделать, чтобы люди обманывали меньше Вопрос 4. Как сделать так, чтобы вас уважали и ценили? Как сделать лучше себе и другим людям Как сделать свидание интересным?


Категории:

АрхитектураАстрономияБиологияГеографияГеологияИнформатикаИскусствоИсторияКулинарияКультураМаркетингМатематикаМедицинаМенеджментОхрана трудаПравоПроизводствоПсихологияРелигияСоциологияСпортТехникаФизикаФилософияХимияЭкологияЭкономикаЭлектроника






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





 

 

Структуры особенно подходят для управления массивами

связанных переменных. Рассмотрим, например, программу подс-

чета числа вхождений каждого ключевого слова языка "C". Нам

нужен массив символьных строк для хранения имен и массив це-

лых для подсчета. одна из возможностей состоит в использова-

нии двух параллельных массивов KEYWORD и KEYCOUNT:

 

CHAR *KEYWORD [NKEYS];

INT KEYCOUNT [NKEYS];

 

Но сам факт, что массивы параллельны, указывает на возмож-

ность другой организации. Каждое ключевое слово здесь по су-

ществу является парой:

 

CHAR *KEYWORD;

INT KEYCOUNT;

 

и, следовательно, имеется массив пар. Описание структуры

 

STRUCT KEY \(

CHAR *KEYWORD;

INT KEYCOUNT;

\) KEYTAB [NKEYS];

 

оперделяет массив KEYTAB структур такого типа и отводит для

них память. Каждый элемент массива является структурой. Это

можно было бы записать и так:

 

STRUCT KEY \(

CHAR *KEYWORD;

INT KEYCOUNT;

\);

STRUCT KEY KEYTAB [NKEYS];

 

Так как структура KEYTAB фактически содержит постоянный

набор имен, то легче всего инициализировать ее один раз и

для всех членов при определении. Инициализация структур

вполне аналогична предыдущим инициализациям - за определени-

ем следует заключенный в фигурные скобки список инициализа-

торов:

 

STRUCT KEY \(

CHAR *KEYWORD;

INT KEYCOUNT;

\) KEYTAB[] =\(

"BREAK", 0,

"CASE", 0,

"CHAR", 0,

"CONTINUE", 0,

"DEFAULT", 0,

/*... */

"UNSIGNED", 0,

"WHILE", 0

\);

 

Инициализаторы перечисляются парами соответственно членам

структуры. Было бы более точно заключать в фигурные скобки

инициализаторы для каждой "строки" или структуры следующим

образом:

 

\("BREAK", 0 \),

\("CASE", 0 \),

...

 

Но когда инициализаторы являются простыми переменными или

символьными строками и все они присутствуют, то во внутрен-

них фигурных скобках нет необходимости. Как обычно, компиля-

тор сам вычислит число элементов массива KEYTAB, если иници-

ализаторы присутствуют, а скобки [] оставлены пустыми.

Программа подсчета ключевых слов начинается с определе-

ния массива KEYTAB. ведущая программа читает свой файл вво-

да, последовательно обращаясь к функции GETWORD, которая из-

влекает из ввода по одному слову за обращение. Каждое слово

ищется в массиве KEYTAB с помощью варианта функции бинарного

поиска, написанной нами в главе 3. (Конечно, чтобы эта функ-

ция работала, список ключевых слов должен быть расположен в

порядке возрастания).

 

#DEFINE MAXWORD 20

 

MAIN() /* COUNT "C" KEYWORDS */

\(

INT N, T;

CHAR WORD[MAXWORD];

 

WHILE ((T = GETWORD(WORD,MAXWORD))!= EOF)

IF (T == LETTER)

IF((N = BINARY(WORD,KEYTAB,NKEYS)) >= 0)

KEYTAB[N].KEYCOUNT++;

FOR (N =0; N < NKEYS; N++)

IF (KEYTAB[N].KEYCOUNT > 0)

PRINTF("%4D %S\N",

KEYTAB[N].KEYCOUNT, KEYTAB[N].KEYWORD);

\)

BINARY(WORD, TAB, N) /* FIND WORD IN TAB[0]...TAB[N-1] */

CHAR *WORD;

STRUCT KEY TAB[];

INT N;

\(

INT LOW, HIGH, MID, COND;

 

LOW = 0;

HIGH = N - 1;

WHILE (LOW <= HIGH) \(

MID = (LOW+HIGH) / 2;

IF((COND = STRCMP(WORD, TAB[MID].KEYWORD)) < 0)

HIGH = MID - 1;

ELSE IF (COND > 0)

LOW = MID + 1;

ELSE

RETURN (MID);

\)

RETURN(-1);

\)

Мы вскоре приведем функцию GETWORD; пока достаточно сказать,

что она возвращает LETTER каждый раз, как она находит слово,

и копирует это слово в свой первый аргумент.

 

Величина NKEYS - это количество ключевых слов в массиве

KEYTAB. Хотя мы можем сосчитать это число вручную, гораздо

легче и надежнее поручить это машине, особенно в том случае,

если список ключевых слов подвержен изменениям. Одной из

возможностей было бы закончить список инициализаторов указа-

нием на нуль и затем пройти в цикле сквозь массив KEYTAB,

пока не найдется конец.

Но, поскольку размер этого массива полностью определен к

моменту компиляции, здесь имеется более простая возможность.

Число элементов просто есть

 

SIZE OF KEYTAB / SIZE OF STRUCT KEY

 

дело в том, что в языке "C" предусмотрена унарная операция

SIZEOF, выполняемая во время компиляции, которая позволяет

вычислить размер любого объекта. Выражение


 

SIZEOF(OBJECT)

 

выдает целое, равное размеру указанного объекта. (Размер оп-

ределяется в неспецифицированных единицах, называемых "бай-

тами", которые имеют тот же размер, что и переменные типа

CHAR). Объект может быть фактической переменной, массивом и

структурой, или именем основного типа, как INT или DOUBLE,

или именем производного типа, как структура. В нашем случае

число ключевых слов равно размеру массива, деленному на раз-

мер одного элемента массива. Это вычисление используется в

утверждении #DEFINE для установления значения NKEYS:

 

#DEFINE NKEYS (SIZEOF(KEYTAB) / SIZEOF(STRUCT KEY))

 

Теперь перейдем к функции GETWORD. Мы фактически написа-

ли более общий вариант функции GETWORD, чем необходимо для

этой программы, но он не на много более сложен. Функция

GETWORD возвращает следующее "слово" из ввода, где словом

считается либо строка букв и цифр, начинающихся с буквы, ли-

бо отдельный символ. Тип объекта возвращается в качетве зна-

чения функции; это - LETTER, если найдено слово, EOF для

конца файла и сам символ, если он не буквенный.

 

GETWORD(W, LIM) /* GET NEXT WORD FROM INPUT */

CHAR *W;

INT LIM;

\(

INT C, T;

IF (TYPE(C=*W++=GETCH())!=LETTER) \(

*W='\0';

RETURN(C);

\)

 

WHILE (--LIM > 0) \(

T = TYPE(C = *W++ = GETCH());

IF (T! = LETTER && T! = DIGIT) \(

UNGETCH(C);

BREAK;

\)

\)

*(W-1) - '\0';

RETURN(LETTER);

\)

 

Функция GETWORD использует функции GETCH и UNGETCH, которые

мы написали в главе 4: когда набор алфавитных символов пре-

рывается, функция GETWORD получает один лишний символ. В ре-

зультате вызова UNGETCH этот символ помещается назад во ввод

для следующего обращения.

Функция GETWORD обращается к функции TYPE для определе-

ния типа каждого отдельного символа из файла ввода. Вот ва-

риант, справедливый только для алфавита ASCII.

 

TYPE(C) /* RETURN TYPE OF ASCII CHARACTER */

INT C;

\(

IF (C>= 'A' && C<= 'Z' \!\! C>= 'A' && C<= 'Z')

RETURN(LETTER);

ELSE IF (C>= '0' && C<= '9')

RETURN(DIGIT);

ELSE

RETURN(C);

\)

 

 

Символические константы LETTER и DIGIT могут иметь любые

значения, лишь бы они не вступали в конфликт с символами,

отличными от буквенно-цифровых, и с EOF; очевидно возможен

следующий выбор

 

#DEFINE LETTER 'A'

#DEFINE DIGIT '0'

 

функция GETWORD могла бы работать быстрее, если бы обращения

к функции TYPE были заменены обращениями к соответствующему

массиву TYPE[ ]. В стандартной библиотеке языка "C" предус-

мотрены макросы ISALPHA и ISDIGIT, действующие необходимым

образом.

 







Date: 2015-09-17; view: 321; Нарушение авторских прав



mydocx.ru - 2015-2024 year. (0.014 sec.) Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав - Пожаловаться на публикацию