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

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

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

42

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

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

Круглые скобки обязательны в обращении к функции:

имя_функции(список_аргументов)

где операндами служат имяфункции и список аргументов. Ре­ зультат вызова определяется (вычисляется) в теле функции, структуру которого задает ее определение.

В выражении

имя_массива[индекс]

операндами для операции [ ] служат имя массива и индекс. Подробнее с индексированными переменными мы познакомим­ ся на примерах в главе 2 и более подробно в следующих главах.

Условная трехместная операция (ранг 13). В отличие от унарных и бинарных операций условная тернарная операция

используется с тремя операндами. В изображении условной операции применяются два символа '?' и и три выраженияоперанда:

выраж ение1 ? выражение_ 2 : выражениеЗ

Первым вычисляется значение выражения ! . Если оно ис­ тинно, т.е. не равно нулю, то вычисляется значение выраже­ ния_2, которое становится результатом. Если при вычислении выражения ! получится 0, то в качестве результата берется значение выраженияЗ. Классический пример:

х < 0 ? -х : х;

Выражение возвращает абсолютную величину переменной х.

Операция явного преобразования типа. Операция преобра­ зования (приведения) типа (ранг 2) имеет следующий формат:

(имя_типа) операнд

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

43

Такое выражение позволяет преобразовывать значение опе­ ранда к заданному типу. В качестве операнда используется унарное выражение, которое в простейшем случае может быть переменной, константой или любым выражением, заключенным в круглые скобки. Например, преобразования (Iong)8 (вну­ треннее представление результата имеет длину 4 байта) и (char)8 (внутреннее представление результата имеет длину 1 байт) изменяют длину внутреннего представления целых кон­ стант, не меняя их значений.

В этих преобразованиях константа не меняла значения и ос­ тавалась целочисленной. Однако возможны более глубокие преобразования, например, (long doubIe)6 или (float)4 не только изменяют длину константы, но и структуру ее внутреннего представления. В результатах будут выделены порядок и ман­ тисса, значения будут вещественными.

Преобразования типов арифметических данных нужно при­ менять аккуратно, так как возможно изменение числовых зна­ чений. При преобразовании больших целочисленных констант к вещественному типу (например, к типу float) возможна потеря значащих цифр (потеря точности). Если вещественное значение преобразуется к целому, то возможна ошибка при выходе полу­ ченного значения за диапазон допустимых значений для целых. В этом случае результат преобразования не всегда предсказуем и целиком зависит от реализации.

1.5. Разделители

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

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

Разделители, или знаки пунктуации, входят в число лексем

языка:

 

N

#

Квадратные скобки. Для ограничения индексов одно- и многомерных массивов, а также при записи индексированных элементов используются квадратные скобки [ ]. Примеры:

int А[5]; А - одномерный массив из пяти элементов;

int х, е[3][2]; е - двумерный массив (матрица) размером 3x2.

Выражение с индексированными элементами:

е[0][0] = х = А[2] =1 4;

означает, что начальному элементу массива е, переменной х и третьему элементу массива А присваивается значение 4. Так как индексы в массивах всегда начинаются с 0, то элемент А[2] со­ ответствует третьему элементу массива.

Круглые скобки. Назначение круглых скобок ():

1) выделяют выражения-условия (в операторе "если"):

if (х < 0) х = -х;

/♦абсолютная величина арифметической переменной*/

2) входят как обязательные элементы в определение и описа­ ние (в прототип) любой функции, где выделяют соответственно список формальных параметров и список спецификаций пара­ метров:

float F(float х, int k) /* Определение функции*/

{ тело_функции }

float F(float, int); /* Описание функции - ее

.прототип */

3) круглые скобки обязательны при определении указателя на функцию:

int (*pfunc)( ); /* Определение указателя pfunc на функцию */

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

45

4) группируют выражения, изменяя естественную последова­ тельность выполнения операций:

у = (а + Ъ) / с ; /* Изменение приоритета операций */

5) входят как обязательные элементы в операторы циклов:

for (i=0, j=l; i<j; i+=2, j++) тело_цикла; while ( i<j ) тело_цяхла;

do тело_цикла while ( k>0 );

6) необходимы при явном преобразовании типа. Примеры:

long

i = 12L;

/*

Определение

переменной

*/

float brig;

/*

Определение

переменной

*/

brig

= (float)i;

/* Явное приведение типа

*/

brig получает значение 12L, преобразованное к типу float;

7) применение круглых скобок настоятельно рекоменду­ ется в макроопределениях, обрабатываемых препроцессором (см. гл. 3):

#define R(x,y) sqrt((x)*(x) + (у) * (у))

Это позволяет использовать в качестве параметров макровызо­ вов арифметические выражения любой сложности и не сталки­ ваться с нарушениями приоритетов операций.

Фигурные скобки. Для обозначения соответственно начала и конца составного оператора или блока используют фигурные скобки {}. Пример использования составного оператора в ус­ ловном операторе:

if (d > х) { d— ; х++; )

Пример блока - тело любой функции:

float absx (float х)

{

return x>0.0?x:-x;

)

Обратите внимание на отсутствие точки с запятой после закры­ вающейся скобки обозначающей конец составного операто­ ра или блока.

46

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

Фигурные скобки используются для выделения списка ком­ понентов в определениях структурных и объединяющих типов:

/* Определение структурного типа cell: */ struct cell

{

char *b; int ее;

double U[6];

} ;

/* Определение объединяющего типа mix: */ union mix

{

unsigned int ii; char cc[2];

};

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

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

/* Инициализация массива:

*/

int month [ ] = { 1, 2, 3,

4, 5, б, 7, 8, 9, 10,

11, 12 >;

 

/* Инициализация структуры stock типа mixture */ struct mixture

{

int ii;

 

double dd;

 

char

со; }

.

stock =

{ 666, 3.67, ’At'

В примере mixture - имя структурного типа с тремя компо­ нентами разных типов, stock - имя конкретной структуры типа mixture. Компоненты ii, dd, сс структуры stock получают значе­ ния при инициализации из списка В фигурных скобках. (Подробно о структурах см. в гл. 6.)

Запятая. Запятая может быть использована в качестве опе­ рации, а может применяться как разделитель. В последнем слу­ чае она разделяет элементы списков. Во-первых, это списки

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

47

начальных значений элементов массивов и компонентов струк­ тур при их инициализации (примеры только что даны).

Другой пример списков - списки формальных и фактических параметров и их спецификаций в функциях.

Третье использование запятой как разделителя - в заголовке оператора цикла:

for (x=pl,y=p2,i=2; i<n; z=x+y, x=y, y=z, i++);

(В данном примере после выполнения цикла значением пере­ менной z будет величина, равная п-му члену последовательно­ сти чисел Фибоначчи, определенной по значениям первых двух pi и р2.)

Запятая как разделитель используется также в описаниях и определениях объектов (например, переменных) одного типа:

int i, re­

float х, у , z, pi, p2 ;

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

int i=l, m[ ]={ i, (i=2,i*i), i };

В данном примере запятая в круглых скобках выступает в роли знака операции. Операция присваивания "=" имеет более высо­ кий приоритет, чем операция "запятая". Поэтому вначале i по­ лучает значение 2, затем вычисляется произведение i*i, и этот результат служит значением выражения в скобках. Однако зна­ чением переменной i остается 2. Значениями ш[0], ш[1], ш[2] будут соответственно 1, 4, 2.

Точка с запятой. Каждый оператор, каждое определение и каждое описание в программе на языке Си завершает точка с запятой Любое допустимое выражение, за которым следует воспринимается как оператор. Это справедливо и для пусто­ го выражения, т.е. отдельный символ "точка с запятой" считает­

48

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

ся пустым оператором. Пустой оператор иногда используется как тело цикла. Примером может служить цикл for, приведен­ ный выше для иллюстрации особенностей использования запя­ той в качестве разделителя. (Вычисляется п-й член последовательности чисел Фибоначчи.)

Примеры операторов-выражений:

i++;

/* Результат - только изменение Значения

F(z,4);

переменной

± */

/* Результат

определяется телом функции

 

с именем F

*/

Двоеточие. Для отделения метки от помечаемого ею опера­ тора используется двоеточие

метка: оператор;

Многоточие. Это три точки без пробелов между ними. Оно используется для обозначения переменного числа парамет­ ров у функции при ее определении и описании (при задании ее прототипа). При работе на языке Си программист постоянно использует библиотечные функции со списком параметров пе­ ременной длины для форматных ввода и вывода. Их прототипы выглядят следующим образом:

int printf (const char * format,...); int scanf (const char * format,...);

Здесь с помощью многоточия указана возможность при об­ ращении к. функциям использовать разное количество парамет­ ров (не меньше одного, так как параметр format должен быть указан всегда и не может опускаться).

Подготовка своих функций с переменным количеством па­ раметров на языке Си требует применения средств адресной арифметики, например макросов, предоставляемых заголовоч­ ным файлом stdarg.h. О возможностях упомянутых макросов

подробно говорится в главе 5.

 

Звездочка. Как уже упоминалось, звездочка

используется

в качестве знака операции умножения и знака операции разы-

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

49

менования (получения доступа через указатель). В описаниях и определениях звездочка означает, что описывается (определя­ ется) указатель на значение использованного в объявлении типа:

/♦Указатель на величину типа int*/

int * point;

/* Указатель на указатель на объект типа char */ char ** refer;

Обозначение присваивания. Как уже упоминалось, для обозначения операции присваивания используется символ Кроме того, в определении объекта он используется при его инициализации:

/* инициализация

структуры

*/

};

struct {char х, int у} А={

'z', 1918

/* инициализация

переменной

*/

 

int F = 66;

 

 

 

Признак иреироцессорных средств. Символ

(знак номе­

ра или диеза в музыке) используется для обозначения директив (команд) препроцессора. Если этот символ является первым от­ личным от пробела символом в строке программы, то строка воспринимается как директива препроцессора. Этот же символ используется в качестве одной из препроцессорных операций (см. гл. 3).

Без одной из препроцессорных директив обойтись совер­ шенно невозможно - препроцессорная команда

#include <stdio.h>

включает в текст программы средства связи с библиотечными функциями ввода-вывода.

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

4-3124

50

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

1.6. В ы раж ения и приведение ариф м етических типов

Введя константы, переменные, разделители и знаки опера­ ций, охарактеризовав основные типы данных и рассмотрев пе­ ременные, можно конструировать выражения. Каждое выраже­ ние состоит из одного или нескольких операндов, символов операций и ограничителей, в качестве которых чаще всего вы­ ступают круглые скобки (). Назначение любого выражения - формирование некоторого значения. В зависимости от типа формируемых значений определяются типы выражений. Если значениями выражения являются целые и вещественные числа, то говорят об арифметических выражениях.

В арифметических выражениях допустимы следующие опе­ рации: '

+- сложение (или унарная операция +); - вычитание (или унарная операция изменения знака);

*- умножение;

/- деление;

% - деление по модулю (т.е. получение остатка от цело­ численного деления первого операнда на второй).

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

Примеры выражений с двумя операндами:

а+Ь

12.3-х

3.14159*Z

k/3

16%i

Нужно быть аккуратным, применяя операцию деления V к целочисленным операндам. Например, как мы уже упоминали выше, за счет округления результата значением выражения 5/3 будет 1, а соответствует ли это замыслам программиста, зависит от смысла той конкретной конструкции, в которой это выраже­ ние используется.

Чтобы результат выполнения арифметической операции был вещественным, необходимо, чтобы вещественным был хотя бы

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

51

один из операндов. Например, значением выражения 5.0/2 будет 2.5, что соответствует смыслу обычного деления.

Операции *, / , % (см. табл. 1.4) имеют один ранг (3), опе­ рации +, - также один ранг (4), но более низкий. Арифметиче­ ские операции одного ранга выполняются слева направо. Для изменения порядка выполнения операций обычным образом используются скобки. Например, выражение (d+b)/2.0 позволяет получить среднее арифметическое операндов d и Ь.

Как уже говорилось, введены специфические унариые опера­ ции ++ (ийкремент) и — (декремент) для изменения на 1 опе­ ранда, который в простейшем случае должен быть переменной (леводопустимым значением). Каждая из этих операций может

быть префиксной и постфиксной:

;

выражение ++т

увеличивает на 1 значение т , и это по­

 

лученное значение используется как значение выражения

 

++т (префиксная форма);

 

выражение —к

уменьшает на 1 значение к, и это новое

 

значение используется как значение выражения —к

 

(префиксная форма);

 

выражение i++

(постфиксная форма) увеличивает на 1

 

значение i, однако значением выражения i++ является пре­

 

дыдущее значение i (до его увеличения);

 

выражение)— (постфиксная форма) уменьшает на 1 значение), однако значением выражения j — является пре­ дыдущее значение j (до его уменьшения).

Например, если п равно 4, то при вычислении выражения п++*2 результат равен 8, ап примет значение 5. При п, равном 4, зна­ чением выражения ++п*2 будет 10, а п станет равно 5.

Внешнюю неоднозначность имеют выражения, в которых знак унарной операции ++ (или —) записан непосредственно рядом со знаком бинарной операции +:

х+++Ь или z— d

В этих случаях трактовка выражений однозначна и полно­ стью определяется рангами операций (бинарные аддитивные + и - имеют ранг 4; унарные ++ и — имеют ранг 2). Таким образом:

4*

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