Главная · Поиск книг · Поступления книг · Top 40 · Форумы · Ссылки · Читатели

Настройка текста
Перенос строк


    Прохождения игр    
Demon's Souls |#13| Storm King
Demon's Souls |#12| Old Monk & Old Hero
Demon's Souls |#11| Мaneater part 2
Demon's Souls |#10| Мaneater (part 1)

Другие игры...


liveinternet.ru: показано число просмотров за 24 часа, посетителей за 24 часа и за сегодня
Rambler's Top100
Образование - Керниган, Ричи Весь текст 454.51 Kb

Язык Си

Предыдущая страница Следующая страница
1 ... 15 16 17 18 19 20 21  22 23 24 25 26 27 28 ... 39
ка работающего: "служащий" описывается набором атрибутов та-
ких, как фамилия, имя, отчество (ф.и.о.), адрес, код соци-
ального обеспечения, зарплата и т.д. Некоторые из этих атри-
бутов сами могут оказаться структурами: ф.и.о. Имеет нес-
колько компонент, как и адрес, и даже зарплата.
    Структуры оказываются полезными при организации сложных
данных особенно в больших программах, поскольку во многих
ситуациях они позволяют сгруппировать связанные данные таким
образом, что с ними можно обращаться, как с одним целым, а
не как с отдельными объектами. В этой главе мы постараемся
продемонстрировать то, как используются структуры. Програм-
мы, которые мы для этого будем использовать, больше, чем
многие другие в этой книге, но все же достаточно умеренных
размеров.

     6.1. Основные сведения

    Давайте снова обратимся к процедурам преобразования даты
из главы 5. Дата состоит из нескольких частей таких, как
день, месяц, и год, и, возможно, день года и имя месяца. Эти
пять переменных можно объеденить в одну структуру вида:

 STRUCT DATE \(
 INT  DAY;
 INT  MONTH;
 INT  YEAR;
 INT  YEARDAY;
 CHAR MON_NAME[4];
 \);

    Описание структуры, состоящее из заключенного в фигурные
скобки списка описаний, начинается с ключевого слова STRUCT.
За словом STRUCT может следовать необязательное имя, называ-
емое ярлыком структуры (здесь это DATе). Такой ярлык именует
структуры этого вида и может использоваться в дальнейшем как
сокращенная запись подробного описания.
    Элементы или переменные, упомянутые в структуре, называ-
ются членами. Ярлыки и члены структур могут иметь такие же
имена, что и обычные переменные (т.е. Не являющиеся членами
структур), поскольку их имена всегда можно различить по кон-
тексту. Конечно, обычно одинаковые имена присваивают только
тесно связанным объектам.

    Точно так же, как в случае любого другого базисного ти-
па, за правой фигурной скобкой, закрывающей список членов,
может следовать список переменных.
Оператор

   STRUCT   \( ...\) X,Y,Z;

синтаксически аналогичен

   INT X,Y,Z;

в том смысле, что каждый из операторов описывает X , Y и Z в
качестве переменных соотвествующих типов и приводит к выде-
лению для них памяти.
    Описание структуры, за которым не следует списка пере-
менных, не приводит к выделению какой-либо памяти; оно толь-
ко определяет шаблон или форму структуры. Однако, если такое
описание снабжено ярлыком, то этот ярлык может быть исполь-
зован позднее при определении фактических экземпляров струк-
тур. Например, если дано приведенное выше описание DATE, то

   STRUCT  DATE D;

определяет переменную D в качестве структуры типа DATE.
Внешнюю или статическую структуру можно инициализировать,
поместив вслед за ее определением список инициализаторов для
ее компонент:

 STRUCT DATE D=\( 4, 7, 1776, 186, "JUL"\);

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

  имя структуры . Член
  --------------------
Операция указания члена структуры "." связывает имя структу-
ры и имя члена. В качестве примера определим LEAP (признак
високосности года) на основе даты, находящейся в структуре
D,

LEAP = D.YEAR % 4 == 0 && D.YEAR % 100 != 0
   \!\! D.YEAR % 400 == 0;

или проверим имя месяца

 IF (STRCMP(D.MON_NAME, "AUG") == 0) ...

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

 D.MON_NAME[0] = LOWER(D.MON_NAME[0]);

    Структуры могут быть вложенными; учетная карточка служа-
щего может фактически выглядеть так:

 STRUCT  PERSON  \(
    CHAR NAME[NAMESIZE];
    CHAR ADDRESS[ADRSIZE];
    LONG ZIPCODE;   /* почтовый индекс */
    LONG SS_NUMBER; /* код соц. Обеспечения */
    DOUBLE SALARY;  /* зарплата */
    STRUCT DATE BIRTHDATE; /* дата рождения */
    STRUCT DATE HIREDATE; /* дата поступления
     на работу */
 \);

Структура PERSON содержит две структуры типа DATE . Если мы
определим EMP как

 STRUCT PERSON EMP;

то

 EMP.BIRTHDATE.MONTH

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

     6.2. Структуры и функции

    В языке "C" существует ряд ограничений на использование
структур. Обязательные правила заключаются в том, что единс-
твенные операции, которые вы можете проводить со структура-
ми, состоят в определении ее адреса с помощью операции & и
доступе к одному из ее членов. Это влечет за собой то, что
структуры нельзя присваивать или копировать как целое, и что
они не могут быть переданы функциям или возвращены ими. (В
последующих версиях эти ограничения будут сняты). На указа-
тели структур эти ограничения однако не накладываются, так
что структуры и функции все же могут с удобством работать
совместно. И наконец, автоматические структуры, как и авто-
матические массивы, не могут быть инициализированы; инициа-
лизация возможна только в случае внешних или статических
структур.
    Давайте разберем некоторые из этих вопросов, переписав с
этой целью функции перобразования даты из предыдущей главы
так, чтобы они использовали структуры. Так как правила зап-
рещают непосредственную передачу структуры функции, то мы
должны либо передавать отдельно компоненты, либо передать
указатель всей структуры. Первая возможность демонстрируется
на примере функции DAY_OF_YEAR, как мы ее написали в главе
5:

 D.YEARDAY = DAY_OF_YEAR(D.YEAR, D.MONTH, D.DAY);

другой способ состоит в передаче указателя. если мы опишем
HIREDATE как

 STRUCT  DATE HIREDATE;

и перепишем DAY_OF_YEAR нужным образом, мы сможем тогда на-
писать

 HIREDATE YEARDAY = DAY_OF_YEAR(&HIREDATE);

передавая указатель на HIREDATE функции DAY_OF_YEAR . Функ-
ция должна быть модифицирована, потому что ее аргумент те-
перь является указателем, а не списком переменных.

   DAY_OF_YEAR(PD) /* SET DAY OF YEAR FROM MONTH, DAY */
   STRUCT DATE *PD;
   \(
INT I, DAY, LEAP;

DAY = PD->DAY;
LEAP = PD->YEAR % 4 == 0 && PD->YEAR % 100 != 0
   \!\! PD->YEAR % 400 == 0;
FOR (I =1;  I < PD->MONTH; I++)
   DAY += DAY_TAB[LEAP][I];
RETURN(DAY);
    \)

Описание

STRUCT DATE *PD;

говорит, что PD является указателем структуры типа DATE.
Запись, показанная на примере

PD->YEAR

является новой. Если P - указатель на структуру, то
               P-> член структуры
               ------------------
обращается к конкретному члену. (Операция -> - это знак ми-
нус, за которым следует знак ">".)
    Так как PD указывает на структуру, то к члену YEAR можно
обратиться и следующим образом

 (*PD).YEAR

но указатели структур используются настолько часто, что за-
пись -> оказывается удобным сокращением. Круглые скобки в
(*PD).YEAR необходимы, потому что операция указания члена

стуктуры старше , чем * . Обе операции, "->" и ".", ассоции-
руются слева направо, так что конструкции слева и справа
зквивалентны

 P->Q->MEMB    (P->Q)->MEMB
 EMP.BIRTHDATE.MONTH    (EMP.BIRTHDATE).MONTH

Для полноты ниже приводится другая функция, MONTH_DAY, пере-
писанная с использованием структур.

   MONTH_DAY(PD) /* SET MONTH AND DAY FROM DAY OF YEAR */
   STRUCT DATE *PD;
   \(
 INT I, LEAP;

 LEAP = PD->YEAR % 4 == 0 && PD->YEAR % 100 != 0
    \!\! PD->YEAR % 400 == 0;
 PD->DAY = PD->YEARDAY;
 FOR (I = 1; PD->DAY > DAY_TAB[LEAP][I]; I++)
    PD->DAY -= DAY_TAB[LEAP][I];
 PD->MONTH = I;
    \)

    Операции работы со структурами "->" и "." наряду со ()
для списка аргументов и [] для индексов находятся на самом
верху иерархии страшинства операций и, следовательно, связы-
ваются очень крепко. Если, например, имеется описание

 STRUCT \(
    INT X;
    INT *Y;
 \) *P;

то выражение

 ++P->X

увеличивает х, а не р, так как оно эквивалентно выражению
++(P->х). Для изменения порядка выполнения операций можно
использовать круглые скобки: (++P)->х увеличивает P до дос-
тупа к х, а (P++)->X увеличивает P после. (круглые скобки в
последнем случае необязательны. Почему ?)
    Совершенно аналогично *P->Y извлекает то, на что указы-
вает Y; *P->Y++ увеличивает Y после обработки того, на что
он указывает (точно так же, как и *S++); (*P->Y)++ увеличи-
вает то, на что указывает Y; *P++->Y увеличивает P после вы-
борки того, на что указывает Y.

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

    Структуры особенно подходят для управления массивами
связанных переменных. Рассмотрим, например, программу подс-
чета числа вхождений каждого ключевого слова языка "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 . Хотя мы можем сосчитать это число вручную, гораздо
легче и надежнее поручить это машине, особенно в том случае,
если список ключевых слов подвержен изменениям. Одной из
Предыдущая страница Следующая страница
1 ... 15 16 17 18 19 20 21  22 23 24 25 26 27 28 ... 39
Ваша оценка:
Комментарий:
  Подпись:
(Чтобы комментарии всегда подписывались Вашим именем, можете зарегистрироваться в Клубе читателей)
  Сайт:
 
Комментарии (1)

Реклама