Действия: что делает программа
Глава 2
Выражения
Выражения — это операции, которые выполняют программы. Если valueA, valueB и valueC- — переменные типа int, то выражение
valueB + valueC
вычисляет сумму значений valueB и valueC. Результат выражения обычно присваивается какой-нибудь переменной с помощью оператора, аналогичного следующему:
valueA = valueB + valueC; I
После выполнения этого оператора значение valueA будет равно сумме значений valueB и valueC. Знак плюс — один из операторов языка С. Он указывает компилятору, какую операцию нужно выполнить над двумя операндами.
Язык С включает семь операторов, без которых не обходится практически ни одна программа. В следующих разделах познакомимся с арифметическими и логическими операторами, операторами отношений, отрицания, инкремента и декремента, а также операторами поразрядных операций, j
Арифметические операторы
Еще сидя за школьной партой, вы узнали, как обращаться с арифметическими операторами +, -, * и / (табл.2.1). В языке С эти операторы работают аналогичным образом. Может быть, только оператор деления по модулю (%) вам знаком не так хорошо. Оператор %используется для вычисления остатка от деления целых чисел. Например, значение выражения 24 % 11 (читается 24 по модулю 11) равно 2, т.е. остатку от целочисленного деления 24/11. Значение выражения 8 % 2 равно 0, так как 8 делится на 2без остатка.
Таблица 2.1. Арифметические операторы
Оператор | Описание | Пример |
* | Умножение | (а *. Ь) |
/ | Деление | (а / Ь) |
+ | Сложение | (а + Ь) |
— | Вычитание | (а — Ь) |
% | Деление по модулю | (а % Ь) |
Листинг 2.1 содержит пример числовых выражений, использующих арифметические операторы. В примере выполняется преобразование значений градусов по Фаренгейту в градусы по Цельсию.
Листинг 2.1. CELSIUS.С(преобразование градусов по Фаренгейту в градусы по Цельсию)
_______________________________________________________________________
1: #include
2: #include
3:
4: main()
5: {
6: double fdegrees, cdegrees;
7: char answer[128];
8:
9: printf(Fahrenheit to Celsius conversion\n\n);
10: printf(Degrees Fahrenheit? );
11: gets(answer);
12: fdegrees = atof(answer);
13: cdegrees = ((fdegrees — 32.0) * 5.0) / 9.0;
14: printf(Degrees Celsius = %f\n, cdegrees);
15: return 0;
16: }
Программа использует две переменные с плавающей запятой типа double — fdegrees и cdegrees. После того как программа предложит ввести число, функция atof() преобразует строку answer в число с плавающей запятой, присвоив результат переменной fdegrees. Выражение
((fdegrees — 32.0) * 5.0)/ 9.0
вычисляет эквивалентную температуру в градусах по Цельсию. При этом наличие круглых скобок в выражении влияет на обычный порядок выполнения операций: прежде всех выполняются операции, заключенные во внутренние круглые скобки. В этом примере выражение вычисляется в такой последовательности:
1) 32.0 вычитается из fdegrees;
2) результат первого шага умножается на 5.0;
3) результат второго шага делится на 9.0.
Замечание
Всегда используйте столько круглых скобок, сколько нужно для того, чтобы сделать ясной структуру выражения. Круглые скобки совершенно не влияют на быстродействие, с их помощью вы просто задаете желаемый порядок вычисления.
Сложные выражения без круглых скобок вычисляются в соответствии с фиксированным приоритетом, назначенным каждому оператору. Поскольку операторы *и /имеют более высокий приоритет, чем +и -, то выражение
(А + В * С)
логически идентично выражению
(А + (В * С)).
Поскольку умножение выполняется перед сложением, внутренняя пара скобок не нужна. Но если вы хотите выполнить сложение до умножения, вы должны написать
((А + В) * С).
К приоритетам операторов мы вернемся несколько позже, рассмотрев все операторы языка С.
В программировании на С операторы / и * имеют один и тот же приоритет, таким образом выражение А / В * С вычисляется слева направо, т.е. как в выражении (А / В) * С, но не как А /(В * С).
Операторы отношений
Операторы отношений обрабатывают свои операнды таким образом, чтобы получить либо истинный (ненулевой), либо ложный (нулевой) результат. Выражение
(А В)
истинно только в случае, если А меньше В. Переменные А и В должны принадлежать к таким типам данных, которые можно сравнивать. Обычно это целые или значения с плавающей запятой.
В табл. 2.2 перечислены все операторы отношений языка С. В дальнейшем некоторые из них вы будете использовать в операторах, которые могут принимать решения и выполнять операции, основанные на истинных и ложных выражениях.
Таблица 2.2.Операторы отношений
Оператор | Описание | Пример |
Меньше | (а Ь) | |
Меньше или равно | (а | |
Больше | (а Ь) | |
= | Больше или равно | (а = Ь) |
== | Равно | (а == Ь) |
!=: | Не равно | (а != Ь) |
Замечание
Оператор равенства представлен двойным знаком равенства, таким образом, выражение (А == В) будет истинно, только если А равно В. Не путайте такие выражения с операторами типа А = В, которые присваивают значение В переменной А. Для операторов присваивания всегда используйте одиночный знак равенства (=), а для сравнения двух значений — двойной (==).
Логические операторы
Логические операторы и || объединяют выражения отношений в соответствии с правилами для логического И и ИЛИ. Используйте логический оператор И () в сложных выражениях отношений, аналогичных следующему:
(А В) (В С),
которое будет истинным, только если А меньше В и В меньше С.
Подобным образом используйте оператор ИЛИ (||). Выражение
(А В) || (В С)
будет истинным, только если А меньше В или В меньше С.
Сложные логические выражения вычисляются рациональным способом. Например, если при вычислении выражения
(А
оказалось, что А больше В, то все выражение, как и его первая составляющая (А
Оператор отрицания
Инвертируйте результат любого логического выражения с помощью унарного оператора отрицания !. Выражение
! (А В)
(не верно, что А меньше В) эквивалентно выражению
(А = В).
Оператор неравенства != связан с оператором отрицания. Выражение i
! (А == В)
(не верно, что А равно В) эквивалентно выражению
(А != В).
Это выражение истинно, только если А не равно В.
Операторы инкремента и декремента
Двумя самыми интригующими операторами языка С являются ++ (инкремент) и — (декремент). Оператор ++ (плюс плюс) прибавляет к операнду единицу. Оператор — (минус минус) вычитает единицу.
Несколько примеров проясняют, как работают эти важные операторы. Следующих два оператора дают идентичные результаты:
i = i + 1; /* прибавление единицы к i */
i++; /* то же самое */
Выражение i++ во второй строке является сокращенной записью более длинного выражения сложения и присваивания, приведенного в первой строке. Выражение i++ прибавляет единицу к текущему значению переменной i. Следующие два выражения также дают одинаковые результаты:
i = i — 1: /* вычитание единицы из i */
i—; /* то же самое •/
Выражение i— вычитает единицу из i.
Кроме инкремента и декремента своих операндов, выражения, подобные i++ и i—, также имеют свои собственные значения, как и все другие выражения. Но эти значения зависят от расположения операторов ++ и —.
Если оператор следует за своим операндом, то значение выражения i++ или i— равно значению i до модификации. Другими словами, оператор
j = i++;
присваивает переменной j значение переменной i, которое она имела до выполнения этого оператора. Например, если значение i равно 7, то после выполнения этого оператора значение i будет равно 8, а j получит значение 7.
Если же операторы инкремента и декремента предшествуют своим операндам, значение выражения будет равно значению операнда после модификации, т.е. оператор
j = ++i;
присваивает переменной j инкрементированное значение i, а также инкрементирует текущее значение i. Если значение i равно 7, то после выполнения этого оператора обе переменные j и iстанут равными 8.
Чтобы лучше понять эти различия, можно обратиться к длинным формам записи выражений инкремента и декремента. Действие оператора
j = i++;
аналогично действию двух следующих операторов:
j = i;
i++;
А оператор
j = ++i;
действует подобно такой паре операторов:
++i;
j = i;
Листинг 2.2 демонстрирует действие операторов ++ и —.Скомпилируйте и запустите программу, затем введите целое значение и вы получите полную картину результатов применения операторов инкремента и декремента к этому значению.
Листинг 2.2. INCDEC.C (операции ++ и —)
__________________________________________________
1: include
2:
3: main()
4: {
5: int a, b, с, v, k;
6:
7: printf(Enter an integer value: );
8: scanf(%d, v);
9: k = v;
10: printf(\n Before During After\n);
11: v=k; a=v; b= v++; с = v; printf(v++%8d%8d%8d\n, a, b, c);
12: v=k; a = v; b= v—; с = v; printf(v—%8d%8d%8d\n, a, b, c);
13: v = k; a=v; b= ++v; c = v; printf(++v%8d%8d%8d\n, a, b, c);
14: v=k; a=v; b= —v; c = v; printf(—v%8d%8d%8d\n, a, b, c);
15: return 0;
16: }
________________________________________________________
Если при выполнении программы вы введете целое число 8, то на дисплее будет выведена таблица значений, отображающая действие операторов инкремента и декремента:
Before( До ) During( Во время) After( После)
v++ 8 8 9
v— 8 8 7
++v 8 9 9
—v 8 7 7
________________________________________________________
Рассмотрите внимательнее эти результаты. Колонка Веfоге (До) отображает значение переменной v перед вычислением выражения. Колонка During (Во время) показывает значение выражения (то, чему была бы равна переменная k, если бы, например, вы выполнили оператор k = v++;). Колонка After (После) показывает итоговое значение переменной v после вычисления выражения.
Использование функции scanf() в строке 8 несколько отличается от того, о котором шла речь в главе1. Оператор
scanf(%d, v);
выполняет чтение десятичного целого значения (%d) и сохраняет результат в переменной v. Выражение v передает адрес переменной v функции scanf(). За исключением строковой переменной (как описано в главе1), аргументы в функцию scanf() могут передаваться только по адресу.
Поразрядные операторы
Подобно всем двоичным компьютерам, PC обрабатывают числа, представленные в двоичной системе счисления. Двоичные разряды, или биты, в таких числах, как 1011, полностью соответствуют переключателям внутри компьютерной памяти, работающим по принципу включено — выключено:бит, равный 0, означает выключено, а бит, равный 1, — включено.
Чтобы увеличить скорость компьютера, процессор выполняет чтение, запись и передачу информации не по одному биту, а по группам, представляющим собой 8-битовые байты или 16-битовые слова. С -программы могут обрабатывать такие значения непосредственно в двоичном коде.
Шесть поразрядных операторов выполняют булевы логические операции, названные по имени английского математика Джорджа Буля (1815-1864). В табл. 2.3 сведены все поразрядные операторы языка С.
Таблица 2.3.Поразрядные операторы
Оператор | Описание | Пример | |
Поразрядное И | С = А В; | ||
Поразрядное ИЛИ | С = А | В; | ||
^ | Поразрядное исключающее ИЛИ | С = А ^ В; | |
Сдвиг битов влево | С = А | ||
Сдвиг битов вправо ———————————————л———————————————— | С = А В; | , | |
~ | Дополнение до 1, или поразрядное отрицание | С = ~ А; |
Первые три поразрядных оператора из табл. 2.3 объединяют два операнда в соответствии с правилами логического И (), логического ИЛИ (|) и исключающего ИЛИ (^ ). Следующие два оператора, , сдвигают разряды влево и вправо. Оператор — инвертирует биты значения операнда, заменяя каждый 0 на 1 и каждую 1 на 0; получившееся в результате значение называется дополнением до единицы.
Следующие разделы продемонстрируют каждую операцию из табл. 2.3, что, возможно, поможет вам понять обработку битов в языке С.