Переменные в MAIN(LINE, SAVE и т.д.) являются внутренни-ми или локальными по отношению к функции MAIN, потому чтоони описаны внутри MAIN и никакая другая функция не имеет кним прямого доступа. Это же верно и относительно переменныхв других функциях; например, переменная I в функции GETLINEникак не связана с I в COPY. Каждая локальная переменная су-ществует только тогда, когда произошло обращение к соответс-твующей функции, и исчезает, как только закончится выполне-ние этой функции. По этой причине такие переменные, следуятерминологии других языков, обычно называют автоматическими.Мы впредь будем использовать термин автоматические при ссыл-ке на эти динамические локальные переменные. /в главе 4 об-суждается класс статической памяти, когда локальные перемен-ные все же оказываются в состоянии сохранить свои значениямежду обращениями к функциям/. Поскольку автоматические переменные появляются и исчеза-ют вместе с обращением к функции, они не сохраняют своихзначений в промежутке от одного вызова до другого, в силучего им при каждом входе нужно явно присваивать значения.Если этого не сделать, то они будут содержать мусор. В качестве альтернативы к автоматическим переменным мож-но определить переменные, которые будут внешними для всехфункций, т.е. Глобальными переменными, к которым может обра-титься по имени любая функция, которая пожелает это сделать.(этот механизм весьма сходен с "COMMON" в фортране и"EXTERNAL" в PL/1). Так как внешние переменные доступны всю-ду, их можно использовать вместо списка аргументов для пере-дачи данных между функциями. Кроме того, поскольку внешниепеременные существуют постоянно, а не появляются и исчезаютвместе с вызываемыми функциями, они сохраняют свои значенияи после того, как функции, присвоившие им эти значения, за-вершат свою работу. Внешняя переменная должна быть определена вне всех функ-ций; при этом ей выделяется фактическое место в памяти. Та-кая переменная должна быть также описана в каждой функции,которая собирается ее использовать; это можно сделать либоявным описанием EXTERN, либо неявным по контексту. Чтобысделать обсуждение более конкретным, давайте перепишем прог-рамму поиска самой длинной строки, сделав LINE, SAVE и MAXвнешними переменными. Это потребует изменения описаний и телвсех трех функций, а также обращений к ним. #DEFINE MAXLINE 1000 /* MAX. INPUT LINE SIZE*/ CHAR LINE[MAXLINE]; /* INPUT LINE */CHAR SAVE[MAXLINE];/* LONGEST LINE SAVED HERE*/INT MAX;/*LENGTH OF LONGEST LINE SEEN SO FAR*/MAIN() /*FIND LONGEST LINE; SPECIALIZED VERSION*/{ INT LEN; EXTERN INT MAX; EXTERN CHAR SAVE[]; MAX = 0; WHILE ( (LEN = GETLINE()) > 0 ) IF ( LEN > MAX ) { MAX = LEN; COPY(); }IF ( MAX > 0 ) /* THERE WAS A LINE */ PRINTF( "%S", SAVE );} GETLINE() /* SPECIALIZED VERSION */{ INT C, I; EXTERN CHAR LINE[]; FOR (I = 0; I < MAXLINE-1 && (C=GETCHAR()) !=EOF && C!='\N'; ++I) LINE[I] = C; ++I; } LINE[I] = '\0' RETURN(I) } COPY() /* SPECIALIZED VERSION */ { INT I; EXTERN CHAR LINE[], SAVE[]; I = 0; WHILE ((SAVE[I] = LINE[I]) !='\0') ++I; } Внешние переменные для функций MAIN, GETLINE и COPY оп-ределены в первых строчках приведенного выше примера, кото-рыми указывается их тип и вызывается отведение для них памя-ти. синтаксически внешние описания точно такие же, как опи-сания, которые мы использовали ранее, но так как они распо-ложены вне функций, соответствующие переменные являютсявнешними. Чтобы функция могла использовать внешнюю переме-ную, ей надо сообщить ее имя. Один способ сделать это -включить в функцию описание EXTERN; это описание отличаетсяот предыдущих только добавлением ключевого слова EXTERN. В определенных ситуациях описание EXTERN может быть опу-щено: если внешнее определение переменной находится в том жеисходном файле, раньше ее использования в некоторой конкрет-ной функции, то не обязательно включать описание EXTERN дляэтой переменной в саму функцию. Описания EXTERN в функцияхMAIN, GETLINE и COPY являются, таким образом, излишними.Фактически, обычная практика заключается в помещении опреде-лений всех внешних переменных в начале исходного файла ипоследующем опускании всех описаний EXTERN. Если программа находится в нескольких исходных файлах, инекоторая переменная определена, скажем в файле 1, а исполь-зуется в файле 2, то чтобы связать эти два вхождения пере-менной, необходимо в файле 2 использовать описание EXTERN.Этот вопрос подробно обсуждается в главе 4. Вы должно быть заметили, что мы в этом разделе при ссыл-ке на внешние переменные очень аккуратно используем словаописание и определение. "Определение" относится к тому мес-ту, где переменная фактически заводится и ей выделяется па-мять; "описание" относится к тем местам, где указываетсяприрода переменной, но никакой памяти не отводится. Между прочим, существует тенденция объявлять все, что нипопадется, внешними переменными, поскольку кажется, что этоупрощает связи, - списки аргументов становятся короче и пе-ременные всегда присутствуют, когда бы вам они ни понадоби-лись. Но внешние переменные присутствуют и тогда, когда вы вних не нуждаетесь. Такой стиль программирования чреват опас-ностью, так как он приводит к программам, связи данных внут-ри которых не вполне очевидны. Переменные при этом могут из-меняться неожиданным и даже неумышленным образом, а програм-мы становится трудно модифицировать, когда возникает такаянеобходимость. Вторая версия программы поиска самой длиннойстроки уступает первой отчасти по этим причинам, а отчастипотому, что она лишила универсальности две весьма полезныефункции, введя в них имена переменных, с которыми они будутманипулировать. Упражнение 1-18 --------------- Проверка в операторе FOR функции GETLINE довольно неук-люжа. Перепишите программу таким образом, чтобы сделать этупроверку более ясной, но сохраните при этом то же самое по-ведение в конце файла и при переполнении буфера. Является лиэто поведение самым разумным?
Резюме
На данном этапе мы обсудили то, что можно бы назватьтрадиционным ядром языка "C". Имея эту горсть строительныхблоков, можно писать полезные программы весьма значительногоразмера, и было бы вероятно неплохой идеей, если бы вы за-держались здесь на какое-то время и поступили таким образом:следующие ниже упражнения предлагают вам ряд программ нес-колько большей сложности, чем те, которые были приведены вэтой главе. После того как вы овладеете этой частью "C", приступайтек чтению следующих нескольких глав. Усилия, которые вы приэтом затратите, полностью окупятся, потому что в этих главахобсуждаются именно те стороны "C", где мощь и выразитель-ность языка начинает становиться очевидной. Упражнение 1-19 --------------- Напишите программу DETAB, которая заменяет табуляции вовводе на нужное число пробелов так, чтобы промежуток дости-гал следующей табуляционной остановки. Предположите фиксиро-ванный набор табуляционных остановок, например, через каждыеN позиций. Упражнение 1-20 ---------------- Напишите программу ENTAB, которая заменяет строки пробе-лов минимальным числом табуляций и пробелов, достигая приэтом тех же самых промежутков. Используйте те же табуляцион-ные остановки, как и в DETAB. Упражнение 1-21 ---------------- Напишите программу для "сгибания" длинных вводимых строкпосле последнего отличного от пробела символа, стоящего достолбца N ввода, где N - параметр. убедитесь, что ваша прог-рамма делает что-то разумное с очень длинными строками и вслучае, когда перед указанным столбцом нет ни табуляций, нипробелов. Упражнение 1-22 ---------------- Напишите программу удаления из "C"-программы всех ком-ментариев. Не забывайте аккуратно обращаться с "закавыченны-ми" строками и символьными константами. Упражнение 1-23 ---------------- Напишите программу проверки "C"-программы на элементар-ные синтаксические ошибки, такие как несоответствие круглых,квадратных и фигурных скобок. Не забудьте о кавычках, какодиночных, так и двойных, и о комментариях. (Эта программавесьма сложна, если вы будете писать ее для самого общегослучая).
* 2. Типы, операции и выражения *
Переменные и константы являются основными объектами, скоторыми оперирует программа. Описания перечисляют перемен-ные, которые будут использоваться, указывают их тип и, воз-можно, их начальные значения. Операции определяют, что с ни-ми будет сделано. выражения объединяют переменные и констан-ты для получения новых значений. Все это - темы настоящейглавы.