ке на внешние переменные очень аккуратно используем слова
описание и определение. "Определение" относится к тому мес-
ту, где переменная фактически заводится и ей выделяется па-
мять; "описание" относится к тем местам, где указывается
природа переменной, но никакой памяти не отводится.
Между прочим, существует тенденция объявлять все, что ни
попадется, внешними переменными, поскольку кажется, что это
упрощает связи, - списки аргументов становятся короче и пе-
ременные всегда присутствуют, когда бы вам они ни понадоби-
лись. Но внешние переменные присутствуют и тогда, когда вы в
них не нуждаетесь. Такой стиль программирования чреват опас-
ностью, так как он приводит к программам, связи данных внут-
ри которых не вполне очевидны. Переменные при этом могут из-
меняться неожиданным и даже неумышленным образом, а програм-
мы становится трудно модифицировать, когда возникает такая
необходимость. Вторая версия программы поиска самой длинной
строки уступает первой отчасти по этим причинам, а отчасти
потому, что она лишила универсальности две весьма полезные
функции, введя в них имена переменных, с которыми они будут
манипулировать.
Упражнение 1-18
---------------
Проверка в операторе FOR функции GETLINE довольно неук-
люжа. Перепишите программу таким образом, чтобы сделать эту
проверку более ясной, но сохраните при этом то же самое по-
ведение в конце файла и при переполнении буфера. Является ли
это поведение самым разумным?
1.11. Резюме
На данном этапе мы обсудили то, что можно бы назвать
традиционным ядром языка "C". Имея эту горсть строительных
блоков, можно писать полезные программы весьма значительного
размера, и было бы вероятно неплохой идеей, если бы вы за-
держались здесь на какое-то время и поступили таким образом:
следующие ниже упражнения предлагают вам ряд программ нес-
колько большей сложности, чем те, которые были приведены в
этой главе.
После того как вы овладеете этой частью "C", приступайте
к чтению следующих нескольких глав. Усилия, которые вы при
этом затратите, полностью окупятся, потому что в этих главах
обсуждаются именно те стороны "C", где мощь и выразитель-
ность языка начинает становиться очевидной.
Упражнение 1-19
---------------
Напишите программу DETAB, которая заменяет табуляции во
вводе на нужное число пробелов так, чтобы промежуток дости-
гал следующей табуляционной остановки. Предположите фиксиро-
ванный набор табуляционных остановок, например, через каждые
N позиций.
Упражнение 1-20
----------------
Напишите программу ENTAB, которая заменяет строки пробе-
лов минимальным числом табуляций и пробелов, достигая при
этом тех же самых промежутков. Используйте те же табуляцион-
ные остановки, как и в DETAB.
Упражнение 1-21
----------------
Напишите программу для "сгибания" длинных вводимых строк
после последнего отличного от пробела символа, стоящего до
столбца N ввода, где N - параметр. убедитесь, что ваша прог-
рамма делает что-то разумное с очень длинными строками и в
случае, когда перед указанным столбцом нет ни табуляций, ни
пробелов.
Упражнение 1-22
----------------
Напишите программу удаления из "C"-программы всех ком-
ментариев. Не забывайте аккуратно обращаться с "закавыченны-
ми" строками и символьными константами.
Упражнение 1-23
----------------
Напишите программу проверки "C"-программы на элементар-
ные синтаксические ошибки, такие как несоответствие круглых,
квадратных и фигурных скобок. Не забудьте о кавычках, как
одиночных, так и двойных, и о комментариях. (Эта программа
весьма сложна, если вы будете писать ее для самого общего
случая).
* 2. Типы, операции и выражения *
Переменные и константы являются основными объектами, с
которыми оперирует программа. Описания перечисляют перемен-
ные, которые будут использоваться, указывают их тип и, воз-
можно, их начальные значения. Операции определяют, что с ни-
ми будет сделано. выражения объединяют переменные и констан-
ты для получения новых значений. Все это - темы настоящей
главы.
2.1. Имена переменных
Хотя мы этого сразу прямо не сказали, существуют некото-
рые ограничения на имена переменных и символических конс-
тант. Имена составляются из букв и цифр; первый символ дол-
жен быть буквой. Подчеркивание "_" тоже считается буквой;
это полезно для удобочитаемости длинных имен переменных.
Прописные и строчные буквы различаются; традиционная практи-
ка в "с" - использовать строчные буквы для имен переменных,
а прописные - для символических констант.
Играют роль только первые восемь символов внутреннего
имени, хотя использовать можно и больше. Для внешних имен,
таких как имена функций и внешних переменных, это число мо-
жет оказаться меньше восьми, так как внешние имена использу-
ются различными ассемблерами и загрузчиками. Детали приво-
дятся в приложении а. Кроме того, такие ключевые слова как
IF, ELSE, INT, FLOAT и т.д., зарезервированы: вы не можете
использовать их в качестве имен переменных. (Они пишутся
строчными буквами).
Конечно, разумно выбирать имена переменных таким обра-
зом, чтобы они означали нечто, относящееся к назначению пе-
ременных, и чтобы было менее вероятно спутать их при написа-
нии.
2.2. Типы и размеры данных
Языке "C" имеется только несколько основных типов дан-
ных:
CHAR один байт, в котором может находиться один символ из
внутреннего набора символов.
INT Целое, обычно соответствующее естественному размеру це-
лых в используемой машине.
FLOAT С плавающей точкой одинарной точности.
DOUBLE С плавающей точкой двойной точности.
Кроме того имеется ряд квалификаторов, которые можно ис-
пользовать с типом INT: SHORT (короткое), LONG (длинное) и
UNSIGNED (без знака). Квалификаторы SHORT и LONG указывают
на различные размеры целых. Числа без знака подчиняются за-
конам арифметики по модулю 2 в степени N, где N - число би-
тов в INT; числа без знаков всегда положительны. Описания с
квалификаторами имеют вид:
SHORT INT X;
LONG INT Y;
UNSIGNED INT Z;
Cлово INT в таких ситуациях может быть опущено, что
обычно и делается.
Количество битов, отводимых под эти объекты зависит от
имеющейся машины; в таблице ниже приведены некоторые харак-
терные значения.
Таблица 1
---------------------------------------------------------
!
DEC PDP-11 HONEYWELL IBM 370 INTERDATA !
6000 8/32 !
!
ASCII ASCII EBCDIC ASCII !
!
CHAR 8-BITS 9-BITS 8-BITS 8-BITS !
INT 16 36 32 32 !
SHORT 16 36 16 16 !
LONG 32 36 32 32 !
FLOAT 32 36 32 32 !
DOUBLE 64 72 64 64 !
!
---------------------------------------------------------
Цель состоит в том, чтобы SHORT и LONG давали возмож-
ность в зависимости от практических нужд использовать раз-
личные длины целых; тип INT отражает наиболее "естественный"
размер конкретной машины. Как вы видите, каждый компилятор
свободно интерпретирует SHORT и LONG в соответствии со свои-
ми аппаратными средствами. Все, на что вы можете твердо по-
лагаться, это то, что SHORT не длиннее, чем LONG.
2.3. Константы
Константы типа INT и FLOAT мы уже рассмотрели. Отметим
еще только, что как обычная
123.456е-7,
так и "научная" запись
0.12е3
для FLOAT является законной.
Каждая константа с плавающей точкой считается имеющей
тип DOUBLE, так что обозначение "E" служит как для FLOAT,
так и для DOUBLE.
Длинные константы записываются в виде 123L. Обычная це-
лая константа, которая слишком длинна для типа INT, рассмат-
ривается как LONG.
Существует система обозначений для восьмеричных и шест-
надцатеричных констант: лидирующий 0(нуль) в константе типа
INT указывает на восьмеричную константу, а стоящие впереди
0X соответствуют шестнадцатеричной константе. Например, де-
сятичное число 31 можно записать как 037 в восьмеричной фор-
ме и как 0X1F в шестнадцатеричной. Шестнадцатеричные и вось-
меричные константы могут также заканчиваться буквой L, что
делает их относящимися к типу LONG.
2.3.1. Символьная константа
Символьная константа - это один символ, заключенный в
одинарные кавычки, как, например, 'х'. Значением символьной
константы является численное значение этого символа во внут-
реннем машинном наборе символов. Например, в наборе символов
ASCII символьный нуль, или '0', имеет значение 48, а в коде
EBCDIC - 240, и оба эти значения совершенно отличны от числа
0. Написание '0' вместо численного значения, такого как 48
или 240, делает программу не зависящей от конкретного чис-
ленного представления этого символа в данной машине. Сим-
вольные константы точно так же участвуют в численных опера-
циях, как и любые другие числа, хотя наиболее часто они ис-
пользуются в сравнении с другими символами. Правила преобра-
зования будут изложены позднее.
Некоторые неграфические символы могут быть представлены
как символьные константы с помощью условных последователь-
ностей, как, например, \N (новая строка), \T (табуляция), \0
(нулевой символ), \\ (обратная косая черта), \' (одинарная
кавычка) и т.д. Хотя они выглядят как два символа, на самом
деле являются одним. Кроме того, можно сгенерировать произ-
вольную последовательность двоичных знаков размером в байт,
если написать
'\DDD'
где DDD - от одной до трех восьмеричных цифр, как в
#DEFINE FORMFEED '\014' /* FORM FEED */
Символьная константа '\0', изображающая символ со значе-
нием 0, часто записывается вместо целой константы 0 , чтобы
подчеркнуть символьную природу некоторого выражения.
2.3.2. Константное выражение
Константное выражение - это выражение, состоящее из од-
них констант. Такие выражения обрабатываются во время компи-
ляции, а не при прогоне программы, и соответственно могут
быть использованы в любом месте, где можно использовать кон-
станту, как, например в
#DEFINE MAXLINE 1000
CHAR LINE[MAXLINE+1];
или
SECONDS = 60 * 60 * HOURS;
2.3.3. Строчная константа
Строчная константа - это последовательность, состоящая
из нуля или более символов, заключенных в двойные кавычки,
как, например,
"I AM A STRING" /* я - строка */
или
"" /* NULL STRING */ /* нуль-строка */
Кавычки не являются частью строки, а служат только для
ее ограничения. те же самые условные последовательности, ко-
торые использовались в символьных константах, применяются и
в строках; символ двойной кавычки изображается как \".
С технической точки зрения строка представляет собой
массив, элементами которого являются отдельные символы. Что-
бы программам было удобно определять конец строки, компиля-
тор автоматически помещает в конец каждой строки нуль-символ
\0. Такое представление означает, что не накладывается конк-
ретного ограничения на то, какую длину может иметь строка, и
чтобы определить эту длину, программы должны просматривать
строку полностью. При этом для физического хранения строки
требуется на одну ячейку памяти больше, чем число заключен-
ных в кавычки символов. Следующая функция STRLEN(S) вычисля-
ет длину символьной строки S не считая конечный символ \0.
STRLEN(S) /* RETURN LENGTH OF S */
CHAR S[];
{
INT I;
I = 0;
WHILE (S[I] != '\0')
++I;
RETURN(I);
}
Будьте внимательны и не путайте символьную константу со
строкой, содержащей один символ: 'X' - это не то же самое,
что "X". Первое - это отдельный символ, использованный с
целью получения численного значения, соответствующего букве
х в машинном наборе символов. Второе - символьная строка,