Язык С

       

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


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




    Содержание раздела