книги / Программирование на языке Си
..pdf62 |
Программирование на языке Си |
операнд_1 ? операнд 2 : операндЗ
Все три операнда - выражения. Операнд_1 - это арифмети ческое выражение и чаще всего - отношение либо логическое выражение. Типы операнда_2 и операндаЗ могут быть разны ми (но они должны быть одного типа или должны автоматиче ски приводиться к одному типу).
Первый операнд является условием, в зависимости от кото рого вычисляется значение выражения в целом. Если значение первого операнда отлично от нуля (условие истинно), то вычис ляется значение операнда_2, и оно становится результатом. Если значение первого операнда равно 0 (т.е. условие ложно), то вычисляется значение операнда З, и оно становится резуль татом.
Примеры применения условного выражения мы уже приво дили в § 1.4.
Глава 2 ВВЕДЕНИЕ
В ПРОГРАММИРОВАНИЕ НА ЯЗЫКЕ Си
2.1.С труктура и ком поненты простой програм м ы
Впервой главе мы рассмотрели лексемы языка, способы оп ределения констант и переменных, правила записи и вычисле ния выражений. Несколько слов было сказано об операции присваивания, об операторе присваивания и о том, что каждое выражение превращается в оператор, если в конце выражения находится разделитель "точка с запятой". В этой главе перейдем собственно к программированию, т.е. рассмотрим операторы, введем элементарные средства ввода-вывода, опишем структуру однофайловой программы и на несложных примерах вычисли тельного характера продемонстрируем особенности программи рования на языке Си.
Текст программы и препроцессор. Каждая программа на языке Си есть последовательность препроцессорных директив, описаний и определений глобальных объектов и функций. Препроцессорные директивы (в гл. 1 мы рассмотрели директивы #include и #define) управляют преобразованием текста прог раммы до ее компиляции. Определения вводят функции и объ екты. Объекты необходимы для представления в программе об рабатываемых данных. Функции определяют потенциально возможные действия программы. Описания уведомляют компи лятор о свойствах и именах тех объектов и функций, которые определены в других частях программы (например, ниже по ее тексту или в другом файле).
Программа на языке Си должна быть оформлена в виде од ного или нескольких текстовых файлов. Текстовый файл разбит на строки. В конце каждой строки есть признак ее окончания (плюс управляющий символ перехода к началу новой строки). Просматривая текстовый файл на экране дисплея, мы видим по
64 |
Программирование на языке Си |
следовательность строк, причем признаки окончания строк не видимы, но по ним производится разбивка текста редактором.
Определения и описания программы на языке Си могут раз мещаться в строках текстового файла достаточно произвольно (в свободном формате.) Для препроцессорных директив суще ствуют ограничения. Во-первых, препроцессорная директива обычно размещается в одной строке, т.е. признаком ее оконча ния является признак конца строки текста программы. Вовторых, символ вводящий каждую директиву препроцессора, должен быть первым отличным от пробела символом в строке с препроцессорной директивой.
Подробному изучению возможностей препроцессора и всех его директив будет посвящена глава 3. Сейчас достаточно рас смотреть только основные принципы работы препроцессора и изложить общую схему подготовки исполняемого модуля про граммы, написанной на языке Си. Исходная программа, подго товленная на языке Си в виде текстового файла, проходит три обязательных этапа обработки (рис. 2.1):
•препроцессорное преобразование текста;
•компиляция;
•компоновка (редактирование связей или сборка).
Только после успешного завершения всех перечисленных этапов формируется исполняемый машинный код программы.
Задача препроцессора - преобразование текста программы до ее компиляции. Правила препроцессорной обработки опре деляет программист с помощью директив препроцессора. Каж дая препроцессорная директива начинается с символа В этой главе нам будет достаточно двух директив: ^include и ^define.
Препроцессор "сканирует" исходный текст программы в по иске строк, начинающихся с символа Такие строки воспри нимаются препроцессором как команды (директивы), которые определяют действия по преобразованию текста. #define указы вает правила замены в тексте. Простые примеры использования этой директивы для задания именованных констант были при ведены в § 1.3. Директива ^include определяет, какие текстовые файлы нужно включить в этом месте текста программы.
Глава 2. Введение в программирование на языке Си |
65 |
Рис. 2.1. Схема подготовки исполняемой программы
Директива ^include <...> предназначена для включения в текст программы текста файла из каталога "заголовочных фай лов", поставляемых вместе со стандартными библиотеками компилятора. Каждая библиотечная функция, определенная стандартом языка Си, имеет соответствующее описание (прототип библиотечной функции плюс определения типов, пе ременных, макроопределений и констант) в одном из заголо вочных файлов. Список заголовочных файлов для стандартных библиотек определен стандартом языка.
Важно понимать, что употребление в программе препроцессорной директивы
5 -5 1 2 4
66 |
Программирование на языке Си |
#include < имя заголовочного |
файла > |
не подключает к программе соответствующую стандартную библиотеку. Препроцессорная обработка выполняется на уровне исходного текста программы. Директива #include только позво ляет вставить в текст программы описания из указанного заго ловочного файла. Подключение к программе кодов библио течных функций (см. рис. 2.1) осуществляется только на этапе редактирования связей (этап компоновки), т.е. после компиля ции, когда уже получен машинный код программы. Доступ к кодам библиотечных функций нужен только на этапе компо новки. Именно поэтому компилировать программу и устранять синтаксические ошибки в ее тексте можно без стандартной биб лиотеки, но обязательно с заголовочными файлами.
Здесь следует отметить еще одну важную особенность. Хотя в заголовочных файлах содержатся описания всех стандартных функций, в код программы включаются только те функции, ко торые используются в программе. Выбор нужных функций вы полняет компоновщик на этапе, называемом "редактирование связей".
Термин "заголовочный файл" (header file) в применении к файлам, содержащим описания библиотечных функций стан дартных библиотек, не случаен. Он предполагает включение этих файлов именно в начало программы. Мы Настоятельно ре комендуем, чтобы до обращения к любой функции она была определена или описана в том же файле, где помещен текст программы. Описание или определения функций должны быть "выше" по тексту, чем вызовы функций. Именно поэтому заго ловочные файлы нужно помещать в начале текста программы, т.е. заведомо раньше обращений к соответствующим библио течным функциям.
Хотя заголовочный файл может быть включен в програм му не в ее начале, а непосредственно перед обращением к нуж ной библиотечной функции, такое размещение директив #include <...> не рекомендуется.
Структура программы. После выполнения препроцессорной обработки в тексте программы не остается ни одной пре
Глава 2. Введение в программирование на языке Си |
67 |
процессорной директивы. Теперь программа представляет со бой набор описаний и определений. Если не рассматривать (в этой главе) определений глобальных объектов и описаний, то программа будет набором определений функций.
Среди этих функций всегда должна присутствовать функция с фиксированным именем main. Именно эта функция является главной функцией программы, без которой программа не может быть выполнена. Имя этой главной функции для всех программ одинаково (всегда main) и не может выбираться произвольно. Таким образом, исходный текст программы в простом случае (когда программа состоит только из одной функции) имеет та кой вид:
директивы препроцессора void m ain()
{
определения объектов; исполняемые операторы;
>
Две директивы препроцессора ^define и ^include мы уже ввели. Для целей этой главы их вполне достаточно. Напомним только, что директивы препроцессора могут размещаться не только в начале программы. Они при необходимости могут быть помещены в любом месте текста программы. Однако заго ловочные файлы, с которыми всегда приходится иметь дело, рекомендуется помещать в начале текста программы. Именно эта особенность отмечена в предложенном формате программы. Теперь можно писать несложные программы на языке Си.
Перед именем каждой функции программы следует поме щать сведения о типе возвращаемого функцией значения (тип результата). Если функция ничего не возвращает, то указывает ся тип void. Функция m ain() является той функцией програм мы, которая запускается на исполнение по командам операционной системы. Возвращаемое функцией m ain() значе ние также передается операционный системе. Если программист не предполагает, что операционная система будет анализиро- 5*
68 |
Программирование на языке Си |
вать результат выполнения его программы, то проще всего ука зать, что возвращаемое значение отсутствует, т.е. имеет тип void. Если сведения о типе результата отсутствуют, то считается по умолчанию, что функция main возвращает целочисленное значение типа int.
Каждая функция (в том числе и main) в языке Си должна иметь набор параметров. Этот набор может быть пустым, тогда в скобках после имени функции помещается служебное слово void либо скобки остаются пустыми. В отличие от обычных функций главная функция m ain() может использоваться как с параметрами, так и без них. Состав списка параметров функции m ain() и их назначение будут рассмотрены в главе 5. Сейчас только отметим, что параметры функции m ain() позволяют ор ганизовать передачу данных из среды выполнения в исполняе мую программу, минуя средства, предоставляемые стандартной библиотекой ввода-вывода.
Вслед за заголовком void m ain() размещается тело функции. Тело функции - это блок, последовательность определений, описаний и исполняемых операторов, заключенная в фигурные скобки. Определения и описания в блоке будем размещать до исполняемых операторов. Каждое определение, описание и ка ждый оператор завершается символом (точка с запятой).
Определения вводят объекты, необходимые для представле ния в программе обрабатываемых данных. Примером таких объектов служат именованные константы и переменные разных типов. Описания уведомляют компилятор о свойствах и именах объектов и функций, определенных в других частях программы. Операторы определяют действия программы на каждом шаге ее выполнения.
Чтобы привести пример простейшей осмысленной програм мы на языке Си, необходимо ввести оператор, обеспечивающий вывод данных из ЭВМ, например на экран дисплея. К сожале нию (или как особенность языка), такого оператора в языке Си НЕТ! Все возможности обмена данными с внешним миром про грамма на языке Си реализует с помощью библиотечных функ ций ввода-вывода.
Глава 2. Введение в программирование на языке Си |
69 |
Для подключения к программе описаний средств вводавывода из стандартной библиотеки компилятора используется директива ^include <stdio.h>.
Название заголовочного файла stdio.h является аббревиату рой: std - standard (стандартный), / - input (ввод), о - output (вывод), h - head (заголовок).
Функция форматированного вывода. Достаточно часто для вывода информации из ЭВМ в программах используется функция printf( ). Она переводит данные из внутреннего кода в символьное представление и выводит полученные изображения символов результатов на экран дисплея. При этом у программи ста имеется возможность форматировать данные, т.е. влиять на их представление на экране дисплея.
Возможность форматирования условно отмечена в самом имени функции с помощью литеры f в конце ее названия (print formatted).
Оператор вызова функции printf( ) можно представить так:
printf (форматная строка, список аргументов)',
Форматная строка ограничена двойными кавычками (см. строковые константы, §1.2) и может включать произвольный текст, управляющие символы и спецификации преобразования данных. Список аргументов (с предшествующей запятой) мо жет отсутствовать. Именно такой вариант использован в клас сической первой программе на языке Си [1, 2]:
#include <stdio.h> void main( )
{
printf ("\n Здравствуй, Мир!\п");
>
Директива ^include <stdio.h> включает в текст программы описание (прототип) библиотечной функции printf(). (Если удалить из текста программы эту препроцессорную директиву, то появятся сообщения об ошибках и исполнимый код про граммы не будет создан. Среди параметров функции printf() есть в этом примере только форматная строка (список аргумен-
70 |
Программирование на языке Си |
тов отсутствует). В форматной строке два управляющих симво ла V - "перевод строки". Между ними текст, который выво дится на экран дисплея:
Здравствуй, Мир!
Первый символ '\п' обеспечивает вывод этой фразы с начала новой строки. Второй управляющий символ '\п' переведет кур сор к началу следующей строки, где и начнется вывод других сообщений (не связанных с программой) на экран дисплея.
Итак, произвольный текст (не спецификации преобразования и не управляющие символы) непосредственно без изменений выводится на экран. Управляющие символы (перевод строки, табуляция и т.д.) позволяют влиять на размещение выводимой информации на экране дисплея.
Спецификации преобразования данных предназначены для управления формой внешнего представления значений аргумен тов функции printf(). Обобщенный формат спецификации пре образования имеет вид: %флажки ширина поля.точность модификатор спецификатор
Среди элементов спецификации преобразования обязатель ными являются только два - символ '% ' и спецификатор.
В задачах вычислительного характера этой главы будем ис пользовать спецификаторы:
d - для целых десятичных чисел (тип int);
и - для целых десятичных чисел без знака (тип unsigned);
f - для вещественных чисел в форме с фиксированной точкой (типы float и double);
е - для вещественных чисел в форме с плавающей точкой (с мантиссой и порядком) - для типов double и float.
В список аргументов функции printf() включают объекты, значения которых должны быть выведены из программы. Это выражения и их частные случаи - переменные и константы. Ко личество аргументов и их типы должны соответствовать после довательности спецификаций преобразования в форматной строке. Например, если вещественная переменная summa имеет значение 2102.3, то при таком вызове функции
Глава 2. Введение в программирование на языке Си |
71 |
pr±ntf("\n summa=%f", summa);
на экран с новой строки будет выведено:
summa=2102.3
После выполнения операторов
float о , в ; int к;
о=48.3; к=-83; в=1б.ЗЗ;
printf ("\nc=%f\tk=%d\te=%e", с, к, в);
на экране получится такая строка:
0=48.299999 к=-83 в=1.б3300в+01
Здесь обратите внимание на управляющий символ V (табуляция). С его помощью выводимые значения в строке ре зультата отделены друг от друга.
Для вывода числовых значений в спецификации преобразо вания весьма полезны "ширина поля" и "точность".
Ширина_поля - целое положительное число, определяющее длину (в позициях на экране) представления выводимого значе ния.
Точность - целое положительное число, определяющее ко личество цифр в дробной части внешнего представления веще ственного числа (с фиксированной точкой) или его мантиссы (при использовании формы с плавающей точкой).
Пример с теми же переменными:
printf ("\nc=%5.2\tk=%5d\te=%8.2f\te=%ll.4е", о, к, в, в);
Результат на экране:
с=48.30 к= -83 е= 16.33 е= 1.6330в+01
В качестве модификаторов в спецификации преобразования используются символы:
h - для вывода значений типа short int; I - для вывода значений типа long;
L - для вывода значений типа long double.