программы, которые можно проконтролировать во время компиля-
ции и загрузки. Она определяет несоответствие типов, несов-
местимость аргументов, неиспользованные или очевидным обра-
зом неинициализированные переменные, потенциальные трудности
переносимости и т.д. Для программ,которые благополучно про-
ходят через LINT, гарантируется отсутствие ошибок типа при-
мерно с той же полнотой, как и для программ, написанных,
например, на АЛГОЛЕ-68. Другие возможности программы LINT
будут отмечены, когда представится соответствующий случай.
Наконец, язык "C", подобно любому другому языку, имеет
свои недостатки. Некоторые операции имеют неудачное старшин-
ство; некоторые разделы синтаксиса могли бы быть лучше; су-
шествует несколько версий языка, отличающихся небольшими де-
талями. Тем не менее язык "C" зарекомендовал себя как исклю-
чительно эффективный и выразительный язык для широкого раз-
нообразия применений программирования.
Содержание книги организовано следующим образом. Глава
1 является учебным введением в центральную часть языка "C".
Цель - позволить читателю стартовать так быстро,как только
возможно, так как мы твердо убеждены, что единственный спо-
соб изучить новый язык - писать на нем программы. При этом ,
однако, предполагается рабочее владение основными элементами
программирования; здесь не объясняется, что такое ЭВМ или
компилятор, не поясняется смысл выражений типа N=N+1. Хотя
мы и пытались, где это возможно, продемонстрировать полезную
технику программирования. Эта книга не предназначается быть
справочным руководством по структурам данных и алгоритмам;
там, где мы вынуждены были сделать выбор, мы концентрирова-
лись на языке.
В главах со 2-й по 6-ю различные аспекты "C" излагаются
более детально и несколько более формально, чем в главе 1,
хотя ударение по-прежнему делается на разборе примеров за-
конченных, полезных программ, а не на отдельных фрагментах.
В главе 2 обсуждаются основные типы данных, операторы и
выражения. В главе 3 рассматриваются управляющие операторы:
IF-ELSE ,WHILE ,FOR и т.д. Глава 4 охватывает функции и
структуру программы - внешние переменные, правила определен-
ных областей действия описания и т.д. В главе 5 обсуждаются
указатели и адресная арифметика. Глава 6 содержит подробное
описание структур и объединений.
В главе 7 описывается стандартная библиотека ввода-вы-
вода языка "C", которая обеспечивает стандартный интерфейс с
операционной системой. Эта библиотека ввода-вывода поддержи-
вается на всех машинах, на которых реализован "C", так что
программы, использующие ее для ввода, вывода и других сис-
темных функций, могут переноситься с одной системы на другую
по существу без изменений.
В главе 8 описывается интерфейс между "C" - программами
и операционной системой "UNIX". Упор делается на ввод-вывод,
систему файлов и переносимость. Хотя некоторые части этой
главы специфичны для операционной системы "UNIX", програм-
мисты, не использующие "UNIX", все же должны найти здесь по-
лезный материал, в том числе некоторое представление о том,
как реализована одна версия стандартной библиотеки и предло-
жения для достижения переносимости программы.
Приложение A содержит справочное руководство по языку
"C". Оно является "официальным" изложением синтаксиса и се-
мантики "C" и (исключая чей-либо собственный компилятор)
окончательным арбитром для всех двусмысленностей и упущений
в предыдущих главах.
Так как "C" является развивающимся языком, реализован-
ным на множестве систем, часть материла настоящей книги мо-
жет не соответствовать текущему состоянию разработки на ка-
кой-то конкретной системе. Мы старались избегать таких проб-
лем и предостерегать о возможных трудностях. В сомнительных
случаях, однако, мы обычно предпочитали описывать ситуацию
для системы "UNIX" PDP-11 , так как она является средой для
большинства программирующих на языке "C". В приложении а
также описаны расхождения в реализациях языка "C" на основ-
ных системах.
* 1. Учебное введение *
Давайте начнем с быстрого введения в язык "C". Наша
цель - продемонстрировать существенные элементы языка на ре-
альных программах, не увязая при этом в деталях, формальных
правилах и исключениях. В этой главе мы не пытаемся изложить
язык полностью или хотя бы строго (разумеется, приводимые
примеры будут корректными). Мы хотим как можно скорее довес-
ти вас до такого уровня, на котором вы были бы в состоянии
писать полезные программы, и чтобы добиться этого, мы сосре-
дотачиваемся на основном: переменных и константах, арифмети-
ке, операторах передачи управления, функциях и элементарных
сведениях о вводе и выводе. Мы совершенно намеренно оставля-
ем за пределами этой главы многие элементы языка "C", кото-
рые имеют первостепенное значение при написании больших
программ, в том числе указатели, сртуктуры, большую часть из
богатого набора операторов языка "C", несколько операторов
передачи управления и несметное количество деталей.
Такой подход имеет, конечно, свои недостатки. Самым су-
щественным является то, что полное описание любого конкрет-
ного элемента языка не излагается в одном месте, а поясне-
ния, в силу краткости, могут привести к неправильному истол-
кованию. Кроме того, из-за невозможности использовать всю
мощь языка, примеры оказываются не столь краткими и элегант-
ными, как они могли бы быть. И хотя мы старались свести эти
недостатки к минимуму, все же имейте их ввиду.
Другой недостаток состоит в том, что последующие главы
будут неизбежно повторять некоторые части этой главы. Мы на-
деемся, что такое повторение будет скорее помогать, чем раз-
дражать.
Во всяком случае, опытные программисты должны оказаться
в состоянии проэкстраполировать материал данной главы на
свои собственные программистские нужды. Начинающие же должны
в дополнение писать аналогичные маленькие самостоятельные
программы. И те, и другие могут использовать эту главу как
каркас, на который будут навешиваться более подробные описа-
ния, начинающиеся с главы 2.
1.1. Hачинаем
Единственный способ освоить новый язык
программирования - писать на нем программы. Первая програм-
ма, которая должна быть написана, - одна для всех языков:
напечатать слова : HELLO, WORLD.
Это - самый существенный барьер; чтобы преодолеть его,
вы должны суметь завести где-то текст программы, успешно его
скомпилировать, загрузить, прогнать и найти, где оказалась
ваша выдача. Если вы научились справляться с этими техничес-
кими деталями, все остальное сравнительно просто.
Программа печати "HELLO, WORLD" на языке "C" имеет вид:
MAIN ()
{
PRINTF("HELLO, WORLD\N");
}
Как пропустить эту программу - зависит от используемой
вами системы. В частности, на операционной системе "UNIX" вы
должны завести исходную программу в файле, имя которого
оканчивается на ".C" , например, HELLO.C , и затем скомпили-
ровать ее по команде
CC HELLO.C
Если вы не допустили какой-либо небрежности , такой как
пропуск символа или неправильное написание, компиляция прой-
дет без сообщений и будет создан исполняемый файл с именем
а.OUT . Прогон его по команде
A.OUT
приведет к выводу
HELLO, WORLD
На других системах эти правила будут иными; проконсуль-
тируйтесь с местным авторитетом.
Упражнение 1-1
---------------
Пропустите эту программу на вашей системе. Попробуйте
не включать различные части программы и посмотрите какие со-
общения об ошибках вы при этом получите.
Теперь некоторые пояснения к самой программе. Любая
"C"-программа, каков бы ни был ее размер, состоит из одной
или более "функций", указывающих фактические операции
компьютера, которые должны быть выполнены. Функции в языке
"C" подобны функциям и подпрограммам фортрана и процедурам
PL/1, паскаля и т.д. В нашем примере такой функцией является
MAIN. Обычно вы можете давать функциям любые имена по вашему
усмотрению, но MAIN - это особое имя; выполнение вашей прог-
раммы начинается сначала с функции MAIN. Это означает, что
каждая программа должна в каком-то месте содержать функцию с
именем MAIN. Для выполнения определенных действий функция
MAIN обычно обращается к другим функциям, часть из которых
находится в той же самой программе, а часть - в библиотеках,
содержащих ранее написанные функции.
Одним способом обмена данными между функциями является
передача посредством аргументов. Круглые скобки, следующие
за именем функции, заключают в себе список аргументов; здесь
маIN - функция без аргументов, что указывается как (). Опе-
раторы, составляющие функцию, заключаются в фигурные скобки
{ и }, которые аналогичны DO-END в PL/1 или BEGIN-END в ал-
голе, паскале и т.д. Обращение к функции осуществляется ука-
занием ее имени, за которым следует заключенный в круглые
скобки список аргументов. здесь нет никаких операторов CALL,
как в фортране или PL/1. Круглые скобки должны присутство-
вать и в том случае, когда функция не имеет аргументов.
Строка
PRINTF("HELLO, WORLD\N");
является обращением к функции, которое вызывает функцию
с именем PRINTF и аргуметом "HELLO, WORLD\N". Функция PRINTF
является библиотечной функцией, которая выдает выходные дан-
ные на терминал (если только не указано какое-то другое мес-
то назначения). В данном случае печатается строка символов,
являющаяся аргументом функции.
Последовательность из любого количества символов, зак-
люченных в удвоенные кавычки "...", называется 'символьной
строкой' или 'строчной константой'. Пока мы будем использо-
вать символьные строки только в качестве аргументов для
PRINTF и других функций.
Последовательность \N в приведенной строке является
обозначением на языке "C" для 'символа новой строки', кото-
рый служит указанием для перехода на терминале к левому краю
следующей строки. Если вы не включите \N (полезный экспери-
мент), то обнаружите, что ваша выдача не закончится перехо-
дом терминала на новую строку. Использование последователь-
ности \N - единственный способ введения символа новой строки
в аргумент функции PRINTF; если вы попробуете что-нибудь
вроде
PRINTF("HELLO, WORLD
");
то "C"-компилятор будет печатать злорадные диагностические
сообщения о недостающих кавычках.
Функция PRINTF не обеспечивает автоматического перехода
на новую строку, так что многократное обращение к ней можно
использовать для поэтапной сборки выходной строки. Наша пер-
вая программа, печатающая идентичную выдачу, с точно таким
же успехом могла бы быть написана в виде
MAIN()
{
PRINTF("HELLO, ");
PRINTF("WORLD");
PRINTF("\N");
}
Подчеркнем, что \N представляет только один символ. Ус-
ловные 'последовательности', подобные \N , дают общий и до-
пускающий расширение механизм для представления трудных для
печати или невидимых символов. Среди прочих символов в языке
"C" предусмотрены следующие: \т - для табуляции, \B - для
возврата на одну позицию, \" - для двойной кавычки и \\ для
самой обратной косой черты.
Упражнение 1-2
---------------
Проведите эксперименты для того, чтобы узнать что прои-
зойдет, если в строке, являющейся аргументом функции PRINTF
будет содержаться \X, где X - некоторый символ, не входящий
в вышеприведенный список.
1.2. Переменные и арифметика
Следующая программа печатает приведенную ниже таблицу
температур по Фаренгейту и их эквивалентов по стоградусной
шкале Цельсия, используя для перевода формулу
C = (5/9)*(F-32).
0 -17.8
20 -6.7
40 4.4
60 15.6
... ...
260 126.7
280 137.8
300 140.9
Теперь сама программа:
/* PRINT FAHRENHEIT-CELSIUS TABLE
FOR F = 0, 20, ..., 300 */
MAIN()
{
INT LOWER, UPPER, STEP;