Одним способом обмена данными между функциями является передача посредством аргументов. Круглые скобки, следующие за именем функции, заключают в себе список аргументов; здесь ма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;
FLOAT FAHR, CELSIUS;
LOWER = 0; /* LOWER LIMIT OF TEMPERATURE TABLE */ UPPER =300; /* UPPER LIMIT */ STEP = 20; /* STEP SIZE */ FAHR = LOWER;
WHILE (FAHR <= UPPER) { CELSIUS = (5.0/9.0) * (FAHR -32.0);
PRINTF(“%4.0F %6.1F\N”, FAHR, CELSIUS);
FAHR = FAHR + STEP;
}
}
Первые две строки /* PRINT FAHRENHEIT-CELSIUS TABLE FOR F = 0, 20, ..., 300 */ являются комментарием, который в данном случае кратко поясняет, что делает программа. Любые символы между /* и */ игнорируются компилятором; можно свободно пользоваться комментариями для облегчения понимания программы. Комментарии могут появляться в любом месте, где возможен пробел или переход на новую строку.
В языке “C” все переменные должны быть описаны до их использования, обычно это делается в начале функции до первого выполняемого оператора. Если вы забудете вставить описание, то получите диагностическое сообщение от компилятора. Описание состоит из типа и списка переменных, имеющих этот тип, как в
INT LOWER, UPPER, STEP;
FLOAT FAHR, CELSIUS;
Тип INT означает, что все переменные списка целые; тип FLOAT предназначен для чисел с плавающей точкой, т.е. для чисел, которые могут иметь дробную часть. Точность как INT , TAK и FLOAT зависит от конкретной машины, на которой вы работаете. На PDP-11, например, тип INT соответствует 16-битовому числу со знаком, т.е. числу, лежащему между -32768 и +32767. Число типа FLOAT - это 32-битовое число, имеющее около семи значащих цифр и лежащее в диапазоне от 10е-38 до 10е+38. В главе 2 приводится список размеров для других машин.
В языке “C” предусмотрено несколько других основных типов данных, кроме INT и FLOAT:
CHAR символ - один байт
SHORT короткое целое
LONG длинное целое DOUBLE плавающее с двойной точностью Размеры этих объектов тоже машинно-независимы; детали приведены в главе 2. Имеются также массивы, структуры и объединения этих основных типов, указатели на них и функции,которые их возвращают; со всеми ними мы встретимся в свое время.
Фактически вычисления в программе перевода температур начинаются с операторов присваивания LOWER = 0;
UPPER =300;
STEP = 20;
FAHR =LOWER;
которые придают переменным их начальные значения. каждый отдельный оператор заканчивается точкой с запятой.
Каждая строка таблицы вычисляется одинаковым образом, так что мы используем цикл, повторяющийся один раз на строку. В этом назначение оператора WHILE: WHILE (FAHR <= UPPER) {
....
}
проверяется условие в круглых скобках. Если оно истинно (FAHR меньше или равно UPPER), то выполняется тело цикла (все операторы, заключенные в фигурные скобки { и } ). Затем вновь проверяется это условие и, если оно истинно, опять выполняется тело цикла. Если же условие не выполняется ( FAHR превосходит UPPER ), цикл заканчивается и происходит переход к выполнению оператора, следующего за оператором цикла. Так как в настоящей программе нет никаких последующих операторов, то выполнение программы завершается.
Тело оператора WHILE может состоять из одного или более операторов, заключенных в фигурные скобки, как в программе перевода температур, или из одного оператора без скобок, как, например, в
WHILE (I < J) I = 2 * I;
В обоих случаях операторы, управляемые оператором WHILE, сдвинуты на одну табуляцию, чтобы вы могли с первого взгляда видеть, какие операторы находятся внутри цикла. Такой сдвиг подчеркивает логическую структуру программы. Хотя в языке “C” допускается совершенно произвольное расположение операторов в строке, подходящий сдвиг и использование пробелов значительно облегчают чтение программ. Мы рекомендуем писать только один оператор на строке и (обычно) оставлять пробелы вокруг операторов. Расположение фигурных скобок менее существенно; мы выбрали один из нескольких популярных стилей. Выберите подходящий для вас стиль и затем используйте его последовательно.
Основная часть работы выполняется в теле цикла. Температура по Цельсию вычисляется и присваивается переменной CELAIUS оператором
CELSIUS = (5.0/9.0) * (FAHR-32.0);
причина использования выражения 5.0/9.0 вместо выглядящего проще 5/9 заключается в том, что в языке “C”, как и во многих других языках, при делении целых происходит усечение, состоящее в отбрасывании дробной части результата. Таким образом, результат операции 5/9 равен нулю, и, конечно, в этом случае все температуры оказались бы равными нулю. Десятичная точка в константе указывает, что она имеет тип с плавающей точкой, так что, как мы и хотели, 5.0/9.0 равно 0.5555... .
Мы также писали 32.0 вместо 32 , несмотря на то, что так как переменная FAHR имеет тип FLOAT , целое 32 автоматически бы преобразовалось к типу FLOAT ( в 32.0) перед вычитанием.
С точки зрения стиля разумно писать плавающие константы с явной десятичной точкой даже тогда, когда они имеют целые значения; это подчеркивает их плавающую природу для просматривающего программу и обеспечивает то, что компилятор будет смотреть на вещи так же, как и Вы.
Подробные правила о том, в каком случае целые преобразуются к типу с плаваюшей точкой, приведены в главе 2. Сейчас же отметим, что присваивание
FAHR = LOWER;
проверка WHILE (FAHR <= UPPER) работают, как ожидается, - перед выполнением операций целые преобразуются в плавающую форму.
Этот же пример сообщает чуть больше о том, как работает PRINTF. Функция PRINTF фактически является универсальной функцией форматных преобразований, которая будет полностью описана в главе 7. Ее первым аргументом является строка символов, которая должна быть напечатана, причем каждый знак % указывает, куда должен подставляться каждый из остальных аргументов /второй, третий, .../ и в какой форме он должен печататься. Например, в операторе
PRINTF(“%4.0F %6.1F\N”, FAHR, CELSIUS);
спецификация преобразования %4.0F говорит, что число с плавающей точкой должно быть напечатано в поле шириной по крайней мере в четыре символа без цифр после десятичной точки.
спецификация %6.1F описывает другое число, которое должно занимать по крайней мере шесть позиций с одной цифрой после десятичной точки, аналогично спецификациям F6.1 в фортране или F(6,1) в PL/1. Различные части спецификации могут быть опущены: спецификация %6F говорит, что число будет шириной по крайней мере в шесть символов; спецификация %2 требует двух позиций после десятичной точки, но ширина при этом не ограничивается; спецификация %F говорит только о том, что нужно напечатать число с плавающей точкой. Функция PRINTF также распознает следующие спецификации: %D - для десятичного целого, %о - для восьмеричного числа, %х - для шестнадцатиричного, %с - для символа, %S - для символьной строки и %% для самого символа %.
Каждая конструкция с символом % в первом аргументе функции PRINTF сочетается с соответствующим вторым, третьим, и т.д. Аргументами; они должны согласовываться по числу и типу; в противном случае вы получите бессмысленные результаты.