В языке "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.