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

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

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

22

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

.Таким образом, количество байтов, выделяемое в памяти ЭВМ для представления значения строки, ровно на 1 больше, чем число символов в записи этой строковой константы:

"Эта строка занимает в памяти ЭВМ 43 байта." "Строка в 18 байт."

При работе с символьной информацией нужно помнить, что длина константы 'Р равна 1 байту, а длина строки "F" равна 2 байтам.

При записи строковых констант возможно размещение одной константы в нескольких строках текстового файла с програм­ мой. Для этого используется следующее правило.

Если в последовательности символов (литер) константы встречается литера 'V, за которой до признака '\п* конца строки текстового файла размещены только пробелы, то эти пробелы вместе с символом 'V и окончанием *\п' удаляются, и продолже­ нием строковой константы считается следующая строка текста. Например, следующий текст представляет одну строковую константу:

"Шалтай-Болтай \ сидел на стене."

В программе эта константа будет эквивалентна такой:

"Шалтай-Болтай

сидел.на стене."

Начальные (левые) пробелы в продолжении константы на новой строке не удаляются, а считаются входящими в строко­ вую константу.

Две строковые константы, между которыми нет других раз­ делителей, кроме обобщенных пробельных символов (пробел, табуляция, конец строки и т.д.); воспринимаются как одна стро­ ковая константа. Таким образом,

"Шалтай-Болтай" " свалился во сне."

воспринимается как одна константа:

"Шалтай-Болтай свалился во сне."

Глава 1. Базовые понятия языка

23

Тем же правилам подчиняются и строковые константы, раз­ мещенные на разных строках. Как одна строка будет воспринята последовательность

"Вся королевская " "конница, "

"вся' королевская " "рать"

Эти четыре строковые константы эквивалентны одной:

"Вся королевская конница, вся королевская рать”

Обратите внимание, что в результирующую строку здесь не включаются начальные пробелы перед каждой константойпродолжением.

1.3. П ерем енны е и им енованны е константы

Переменная как объект. Одним из основных понятий языка Си является объект - именованная область памяти. Частный случай объекта - переменная. Отличительная особенность пе­ ременной состоит в возможности связывать с ее именем различи ные значения, .совокупность которых определяется типом переменной. При задании значения переменной в соответст­ вующую ей область памяти помещается код этого значения. Доступ к значению переменной наиболее естественно обеспечи­ вает ее имя, а доступ к участку памяти возможен только по его адресу. О взаимосвязях имен и адресов будет подробно гово­ риться в главе, посвященной указателям и работе с памятью ЭВМ. Для целей первых глав будет вполне достаточно интер­ претировать понятие переменной как пару "имя - значение".

Определение переменных. Каждая переменная перед ее .ис­ пользованием в программе должна быть определена, т.е. для переменной должна быть выделена память. Размер участка па­ мяти, выделяемой длй переменной, и интерпретация содержи­ мого зависят от типа, указанного в определении переменной.

24

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

В соответствии с типами значений, допустимых в языке Си, рассмотрим символьные, целые и, вещественные переменные автоматической памяти. О классах памяти (один из которых класс автоматической памяти) будем подробно говорить позже. Сейчас достаточно ввести только переменные автоматической памяти, которые существуют в том блоке, где они определены. В наиболее распространенном случае таким блоком является текст основной (main) функции программьГ.

Простейшая форма определения переменных:

тип списокименпеременных;

где имена переме:нных - это выбранные программистом иден­ тификаторы, которые в списке разделяются запятыми; тип - один из уже упоминаемых (в связи с константами) типов.

Определены целочисленные типы (перечислены в порядке неубывания длины внутреннего представления):

char - целый длиной не менее 8 бит;

short int - короткий целый (допустима аббревиатура

int

short);

-целый;

long

- длинный целый.

Каждый из целочисленных типов может быть определен ли­ бо как знаковый signed либо как беззнаковый unsigned (по умолчанию signed).

Различие между этими двумя типами - в правилах интерпре­ тации старшего бита внутреннего представления. Спецификатор signed требует, чтобы старший бит внутреннего представления воспринимался как знаковый; unsigned означает, что старший бит внутреннего представления входит в код представляемого числового значения, которое считается в этом случае беззнако­ вым. Выбор знакового или беззнакового представления опреде­ ляет предельные значения, которые можно представить с помощью описанной переменной. Например, на IBM PC пере­ менная типа unsigned int позволяет представить числа от 0 до 65535, а переменной типа signed int (или просто int) соответст­

Глава 1. Базовые понятия языка

25

вуют значения в диапазоне от -32768 до +32767. Чтобы глубже понять различие между целой величиной и целой величиной без знака, следует обратить внимание на результат выполнения унарной операции (минус) над целой величиной и целой ве­ личиной без знака. Для целой величины результат очевиден и тривиален. Результатом при использовании целой величины без знака является

2П - (значение величины без знака),

где п - количество разрядов, отведенное для представления ве­ личины без знака.

Например, если переменная к типа int равна 16, то значени­ ем -к будет -16. Если переменная Ь типа unsigned int равна 16, то значением -Ь на IBM PC является 65520.

По умолчанию, при отсутствии в качестве префикса клю­ чевого слова unsigned любой целый тип считается знаковым (signed). Таким образом, употребление совместно со служеб­ ными словами char, short, int, long префикса signed излишне. Допустимо отдельное использование обозначений (специфи­ каторов) "знаковости". При этом

signed эквивалентно signed int; i> unsigned эквивалентно unsigned int.

Примеры определений целочисленных переменных:

char symbol, сс; unsigned char code; int number, row;1

unsigned long 1ong_number;

Обратите внимание на необходимость символа "точка с запя­ той" в конце каждого определения.

Стандартом языка введены следующие вещественные типы: float - вещественный одинарной точности;

double - вещественный удвоенной точности; long double- вещественный максимальной точности.

Значения всех вещественных типов в ЭВМ представляются с "плавающей точкой", т.е. с мантиссой и порядком, как было

26

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

рассмотрено при определении констант (§1.2). Примеры опре­ делений вещественных переменных:

float х, X, ссЗ, pot_8 ; double a, Stop, В4;

Предельные значения переменных. Предельные значения констант (и соответствующих переменных) разработчики ком­ пиляторов вправе выбирать самостоятельно исходя из аппарат­ ных возможностей компьютера. Однако при такой свободе выбора стандарт языка требует, чтобы для значений типа short

иint было отведено не менее 16 бит, для long - не менее 32 бит. При этом размер long должен быть не менее размера int, a int - не менее short. Предельные значения арифметических констант

ипеременных для большинства компиляторов, реализованных на IBM PC, приведены в табл. 1.3.

Предельные значения вещественных переменных совпадают

спредельными значениями соответствующих констант (см., на­ пример, табл. 1.2).

 

 

 

Т аблица 1.3

 

Основные типы данных

Тип данных

Размер, бит

Диапазон значений

Unsigned char

8

 

0... 255

char

8

 

-128... 127

enum

16

 

-32768... 32767

unsigned int

16

 

0... 65535

short int (short)

16

 

-32768... 32767

unsigned short

16

 

0... 65535

int

16

 

-32768... 32767

unsigned long

32

 

0... 4294967295

long

32

 

-2147483648 ...2147483647

float

32

,

3.4Е-38... 3.4Е+38

donble

64

 

1.7Е-308... 1.7Е+308

long donble

80

 

3.4Е-4932... 1.1Е+4932

Глава 1. Базовые понятия языка

27

Предельные значения целочисленных переменных совпада­ ют с предельными значениями соответствующих констант (см. табл. 1.1). Табл. 1.3 содержит и предельные значения для тех типов, которые не включены в табл. 1.1.

Требования стандарта отображают таблицы Приложения 2.

Инициализация переменных. В соответствии с синтакси­ сов языка переменные автоматической памяти после определе­ ния по умолчанию имеют неопределенные значения. Надеяться на то, что они равны, например, 0, нельзя. Однако переменным можно присваивать начальные значения, явно указывая их в оп­ ределениях:

тип имя_ переменной=начальное значение;

Этот прием назван инициализацией. В отличие от присваи­ вания, которое, осуществляется в процессе выполнения про­ граммы, инициализация выполняется при выделении для переменной участка памяти. Примеры определений с инициали­ зацией:

float pi=3.1415, сс=1.23; unsigned int year=1997;

Именованные константы. В языке Си, кроме переменных, могут быть определены константы, имеющие фиксированные названия (имена). В качестве имен констант используются про­ извольно выбираемые программистом идентификаторы, не сов­ падающие с ключевыми словами и с другими именами объектов. Традиционно принято, что для обозначений констант выбирают идентификаторы из больших букв латинского алфа­ вита и символов подчеркивания. Такое соглашение позволяет при просмотре большого текста программы на языке Си легко отличать имена переменных от названий констант.

Первая возможность определения именованных констант была проиллюстрирована в §1.2, посвященном константам. Это перечисляемые константы, вводимые с использованием слу­ жебного слова enum.

Вторую возможность вводить именованные константы обес­ печивают определения такого вида:

28

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

const тип имя_константы=значение константы;

Здесь const - квалификатор типа, указывающий, что опреде­ ляемый объект имеет постоянное значение, т.е. доступен только для чтения; тип - один из типов объектов; имя константы - идентификатор; значение константы должно соответствовать •?е типу. Примеры:

const double Ё=2.718282; const long №99999999; const F=765;

В последнем определении тип константы не указан, по умол­ чанию ей приписывается тип int.

Третью возможность вводить именованные константы обес­ печивает препроцессорная директива

#define имя константы значение константы

Обратите внимание на отсутствие символа "точка с запятой" в конце директивы. Подробному рассмотрению директивы #define будут посвящены два параграфа главы 3. Здесь мы только упоминаем о возможности с ее помощью определять именованные константы. Кроме того, отметим, что в конкрет­ ные реализации компиляторов с помощью директив #define включают целый, набор именованных констант с фиксирован­ ными именами (см. главу 3 и Приложение 2).

Отличие определения именованной константы

const double Е=2.718282;

от определения препроцессорной константы с таким же значе­ нием

ffdefine EULER 2.718282

состоит внешне в том, что в определении константы Е явно за­ дается ее тип, а при препроцессорном определении константы EULER ее тип определяется "внешним видом" значения кон­ станты. Например, следующее определение

#define NEXT 'Z'

Глава 1. Базовые понятия языка

29

вводит обозначение NEXT для символьной константы 'Z'. Это соответствует такому определению:

const char NEXT = 'Z';

Однако различия между обычной именованной константой и препроцессорной константой, вводимой директивой #define, гораздо глубже и принципиальнее. До начала компиляции текст программы на языке Си обрабатывается специальным компо­ нентом транслятора - препроцессором. Если в тексте встречает­ ся директива

ffdefine EULER

2.718282

а ниже ее в тексте используется имя константы EULER, напри­

мер, в таком виде:

'

double mix = EULER; d = alfa*EULER;

то препроцессор заменит каждое обозначение EULER на ее зна­ чение и сформирует такой текст:

double mix = 2.718282; d = alfa*2.718282;

Далее текст от препроцессора поступает к компилятору, ко­ торый уже "и не вспомнит" о существовании имени EULER, ис­ пользованного в препроцессорной директиве #define. Конс­ танты, определяемые на препроцессорном уровне с помощью директивы #define, очень часто используются для задания раз­ меров массивов, что будет продемонстрировано позже.

Итак, основное отличие констант, определяемых препроцессорными директивами ^define, состоит в том, что эти константы вводятся в текст программы до этапа ее компиляции. Специаль­ ный компонент транслятора - препроцессор обрабатывает ис­ ходный текст программы, подготовленный программистом, и делает в этом тексте замены и подстановки. Пусть в исходном тексте встречается директива:

#de£ine ZERO 0.0

30

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

Это означает, что каждое последующее использование в тек­ сте программы имени ZERO будет заменяться на 0.0.

Рис. 1.1 иллюстрирует некоторые принципы работы препро­ цессора. Его основное отличие от других компонентов трансля­ тора - обработка программы выполняемся только на уровне ее текста. На входе препроцессора - текст с препроцессорными директивами, на выходе препроцессора - модифицированный текст без препроцессорных директив. Этот выходной модифи­ цированный текст изменен по сравнению с входным текстом за счет выполнения препроцессорных директив, но сами препроцессорные директивы в выходном тексте отсутствуют. Полно­ стью все препроцессорные директивы будут рассмотрены позже в главе 3. В связи с именованными константами здесь рассмат­ ривается только одна из возможностей директивы ^define - простая подстановка.

Текст до препроцессора (исходный текст программы):

«define PI 3.141593 «define ZERO 0.0

if (r>ZERO)/* Сравнение с константой ZERO ♦/ /* Длина окружности радиуса г:*/

D=2*PI*r;

Текст после препроцессора:

if (г>0.0)/* Сравнение с константой ZERO */ /♦Длина окружности радиуса г:♦/ D=2*3.141593*r;

Рис. 1.1. Обработка текста программы препроцессором

Глава 1. Базовые понятия языка

31

Имена PI и ZERO (см. рис. 1.1) после работы препроцессора заменены в тексте программы на определенные в двух директи­ вах ^define значения (3.141593 и 0.0). '

Обратите внимание, что подстановка не выполняется в ком­ ментариях и в строковых константах. В примере на рис. 1.1 идентификатор ZERO остался без изменений в комментарии (/* Сравнение с константой ZERO */).

Именно с помощью набора именованных препроцессорных констант стандарт языка Си рекомендует авторам компиляторов определять предельные значения всех основных типов данных. Для этого в языке определен набор фиксированных имен, каж­ дое из которых является именем одной из констант, опреде­ ляющих то или иное предельное значение. Например:

FLT MAX

- максимальное число с плавающей точкой

 

типа float;

C H A R B IT - количество битов в байте;

ШТ_МЕЧ

- минимальное значение для данных типа in t

Общий список стандартных препроцессорных именованных констант для арифметических данных дан в Приложении 2.

Чтобы использовать в программе указанные именованные препроцессорные константы, недостаточно записать их имена в программе. Предварительно в текст программы необходимо включить препроцессорную директиву такого вида:

^include <имя_заголовочного_файпа>

где в качестве имени_заголовочного_файла подставляются:

limits.h

-

для данных целых типов;'

floath

-

для вещественных данных.

В заголовочный файл Iimits.h авторы компилятора помести­ ли набор препроцессорных директив, среди которых есть такие (приведены значения в шестнадцатеричном виде для Turbo С):

#define CHAR_BIT 8 ♦define SHRT_MAX 0x7FFF

♦define LONG MAX 0x7FFFFFFFL

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