Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

книги / Программирование на языке Си

..pdf
Скачиваний:
15
Добавлен:
12.11.2023
Размер:
17.16 Mб
Скачать

62

Программирование на языке Си

операнд_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.

Соседние файлы в папке книги