- •СПбГУТ им. проф. М.А. Бонч–Бруевича Кафедра программной инженерии и вычислительной техники (ПИ и
- •1. Обработка данных. Операции
- •Обработка данных. Операции
- •Операции (15 рангов)
- •Обзор операций
- •Унарные (одноместные) операции
- •Бинарные (двуместные) операции
- •Бинарные (двуместные) операции
- •Операции
- •Бинарные (двуместные) операции
- •Бинарные (двуместные) операции. Тернарная (трёхместная) операция
- •Обзор операций
- •Операция явного преобразования типа
- •Преобразование типов операндов арифметических операций
- •Операция запятая (,)
- •2. Операторы
- •3. Выражения
- •Отношения и логические выражения
- •Выражения и операторы
- •4. Приведение типов в выражениях
- •Приведение типов в выражениях
Бинарные (двуместные) операции. Тернарная (трёхместная) операция
Запятая в качестве операции (ранг 15)
Несколько выражений, разделенных запятыми «,», вычисляют ся последовательно слева направо.
В качестве результата сохраняются тип и значение самого правого выражения.
Таким образом, операция «запятая» группирует вычисления слева направо.
Тип и значение результата определяются самым правым из разделенных запятыми операндов (выражений).
Значения всех левых операндов игнорируются.
Например, если переменная x имеет тип int, то значением выражения (x=3, 3*x) будет 9, а переменная x примет значение 3
Скобки в качестве операций
Круглые ( ) и квадратные [ ] скобки играют роль бинарных операций (ранг 1) при вызове функций и индексировании элементов массивов.
Для программиста, начинающего использовать язык Си, мысль о том, что скобки в ряде случаев являются бинарными операциями, часто даже не приходит в голову.
И это даже тогда, когда он практически в каждой программе обращается к функциям или применяет индексированные переменные.
Итак, отметим, что скобки могут служить бинарными операциями, особенности и возможности которых достойны внимания.
Круглые скобки обязательны в обращении к функции:
имя_функции(список_аргументов)
где операндами служат имя_функции и список_аргументов.
Результат вызова определяется (вычисляется) в теле функции, структуру которого задает ее определение.
В выражении имя_массива[индекс]
операндами для операции [ ] служат имя_массива и индекс.
Тернарная (условная трехместная) операция (ранг 13).
В отличие от унарных и бинарных операций, тернарная операция используется с тремя операндами. В изображении условной операции применяются два символа '?' и ':' и три выражения-операнда:
выражение_1 ? выражение_ 2 : выражение_3
Первым вычисляется значение выражения_1.
Если оно истинно, то есть не равно нулю, то вычисляется значение выражения_2, которое становится результатом.
Если при вычислении выражения_1 получится 0 (ложь), то в качестве результата берется значение выражения_3.
Классический пример:
x < 0 ? -x : x;
Выражение возвращает абсолютную величину переменной x.
11
Обзор операций
Пример 1: |
Смысл записи |
Пример 2: |
Значения |
int i, j, k; |
|
int n, a, b, c, d; |
|
float x, y; |
|
n = 2; a = b = c = 0; |
|
... |
|
a = ++n; |
n=3, a=3 |
х *= y; |
x = x*y; |
a += 2; |
a=5 |
i += 2; |
i = i + 2; |
b = n++; |
b=3, n=4 |
x /= y+15; |
x = x/(y + 15); |
b –= 2; |
b=1 |
--k; |
k = k – 1; |
c = --n; |
n=3, c=3 |
k--; |
k = k – 1; |
c *= 2; |
c=6 |
j = i++; |
j = i; i = i + 1; |
d = n--; |
d=3, n=2 |
j = ++i; |
i = i + 1; j = i; |
d %= 2; |
d=1 |
12
Операция явного преобразования типа
Операция преобразования (приведения) типа (ранг 2) имеет следующий формат:
(имя_типа) операнд
Такое выражение позволяет преобразовывать значение операнда к заданному типу.
В качестве операнда используется унарное выражение, которое в простейшем случае может быть переменной, кон стантой или любым выражением, заключенным в круглые скобки.
Например, преобразования (long)8 (внутреннее представление результата имеет длину 4 байта) и (char)8 (внутреннее представление результата имеет длину 1 байт) изменяют длину внутреннего представления целых констант, не меняя их значений.
В этих преобразованиях константа не меняла значения и оставалась целочисленной.
Однако возможны более глубокие преобразования, например |
||||
(long double)6 |
или (float)4 |
не только изменяют длину константы, |
||
но и структуру ее внутреннего представления. |
|
|||
В результатах будут выделены порядок и мантисса, значения |
||||
будут вещественными. |
|
|
||
Примеры: |
|
|
|
|
long i = 12L; |
/* |
Определение переменной |
*/ |
|
float brig; |
/* |
Определение переменной |
*/ |
|
brig = (float)i; |
/* |
Явное приведение типа |
*/ |
brig получает значение 12L, преобразованное к типу float.
Преобразования типов арифметических данных нужно применять аккуратно, так как возможно изменение числовых значений.
При преобразовании больших целочисленных констант к вещественному типу (например, к типу float) возможна потеря значащих цифр (потеря точности).
Если вещественное значение преобразуется к целому, то возможна ошибка при выходе полученного значения за диапазон допустимых значений для целых.
В этом случае результат преобразования не всегда предсказуем и целиком зависит от реализации.
Тонкости терминологии: что такое оператор, операция, инструкция и кто из них operator, а кто statement?
Лучше говорить операция, так как оператор в англоязычной литературе, это нечто иное.
Вот когда оператором обзывают операцию (инструкцию), сиречь statement, вот тут, да, начинается путаница.
Оператор (statement) – часть программы, определяющая действие, предпринимаемое при выполнении программы.
Выражение, завершающееся точкой с запятой, является
оператором.
Такие операторы, как if, for и while, имеют блоки, способные содержать другие операторы.
Некоторые компиляторы без L не скомпилируют |
13 |
|
Преобразование типов операндов арифметических операций
Если операнды |
|
|
|
Но, как правило, в |
|
арифметических |
|
|
операциях участвуют |
||
операндов имеют один |
|
операнды различных типов. |
|||
тип, то и результат |
|
|
|
В этом случае они |
|
операции будет иметь |
|
преобразуются к общему типу |
|||
такой же тип |
|
|
в порядке увеличения их |
||
|
|
|
«размера памяти», т.е. |
||
|
|
||||
Стрелки отмечают |
|
|
объема памяти, необходимого |
||
преобразования даже |
|
|
для хранения их значений. |
||
однотипных операндов |
|
|
Поэтому неявные |
||
перед выполнением |
|
|
преобразования всегда идут от |
||
операции |
|
|
«меньших» объектов к |
||
|
|
|
«большим». |
|
|
|
|
|
|
||
short, char int |
unsigned |
long |
double |
||
|
|
|
|
float |
double |
Действуют следующие правила
Eсли один из операндов имеет тип double, то и другой преобразуется в double
Eсли один из операндов long, то другой преобразуется в long
Значения типов char и short всегда преобразуются в int
В Си различают явное и неявное преобразование типов данных.
Неявное преобразование типов данных выполняет компилятор, а явное преобразование данных выполняет сам программист.
Результат любого вычисления будет преобразовываться к наиболее точному типу данных, из тех типов данных, которые участвуют в вычислении.
x |
y |
Результат |
Пример |
деления |
|||
|
|
|
|
делимое |
делитель |
частное |
x = 15 y = 2 |
|
|
|
|
int |
int |
int |
15/2=7 |
|
|
|
|
int |
float |
float |
15/2=7.5 |
|
|
|
|
float |
int |
float |
15/2=7.5 |
|
|
|
|
14
|
|
Операция присваивания. Арифметические операции |
|
|
|||
|
|
|
|
Комбинированные операции |
|
||
|
Операция присваивания |
||||||
|
|
|
|
Ниже приводятся некоторые примеры выражений и способы их |
|||
|
Самой общей операцией является присваивание, например, |
||||||
p=a/b или ch = getch(). В Си присваивание обозначается одним |
сокращения: |
|
a += b; |
||||
знаком равенства (=); при этом значение справа от знака |
|
a = a + b; сокращается до |
|||||
равенства присваивается переменной слева. |
|
a = a – b; |
сокращается до |
a –= b; |
|||
|
Можно применять также последовательные присваивания, |
|
a = a * b; |
сокращается до |
a *= b; |
||
|
|
a = a / b; сокращается до |
a /= b; |
||||
например: sum=a= b. В таких случаях присваивание производится |
|
||||||
|
a = a % b; сокращается до |
a %= b; |
|||||
справа налево, то есть b будет присвоено a, которая в свою |
|
||||||
очередь будет присвоена sum, так что все три переменных |
|
Пример: |
и X10 , используя четыре операции умножения для |
||||
получат одно и то же значение (а именно, начальное значение b). |
|
Вычислите X3 |
|||||
|
|
|
заданного целого значения X. |
|
|
|
Арифметические операции. Инкремент. Декремент |
|
|
||
|
|
||||
|
Си поддерживает обычный набор арифметических операций: |
|
|
||
|
|
умножение (*) |
|
|
|
|
|
деление (/) |
|
|
|
|
|
определение остатка от деления (%) |
|||
|
|
сложение (+) |
|
|
|
|
|
вычитание (–) |
|
|
|
|
Для увеличения значений переменной на единицу используют |
||||
инкремент (++), для уменьшения на единицу декремент (--). |
|||||
|
Так : |
|
|
|
|
|
x++; // увеличивает x на единицу |
||||
|
y--; // уменьшает y на единицу |
||||
|
Примеры постфиксных и префиксных операций: |
||||
|
a=2; |
|
a=2; |
||
|
x=18–2*a++; |
x=18–2*(++a); |
|||
|
Получим : |
a=3 |
|||
|
a=3 |
|
|||
|
x= 14 |
|
x=12 |
#include <stdio.h> int x,x2,x3,x5,x10; main()
{
printf("\n Программа расчета X^3 и X^10\n"); puts("Введите значение X");
scanf("%i",&x);
x2=x*x;
x3=x*x2;
x5=x2*x3;
x10=x5*x5;
printf("%i в 3–ей степени = %i \n",x,x3); printf("%i в 10–ой степени = %i",x,x10);
}
15
Операция запятая (,)
Операция запятая
Данная операция используется при организации строго гарантированной последовательности вычисления выражений.
Форма записи:
выражение1, …, выражениеN;
выражения1,…,N вычисляются гарантированно последовательно и результатом операции становится значение выражения N.
Пример:
m=(i=1, j=i++, k=6, n=i+j+k);
получим последовательность вычислений:
i=1, j=i=1, i=2, k=6, n=2+1+6, в результате m=n=9.
Пример:
int x=1, y=2, z; z=(x++, x-y); // z=0
z=x++, x-y; /* z=1, т.к. оператор ″,″ имеет наименьший приоритет из всех операторов */
Другим вариантом использования оператора for является бесконечный цикл. Для организации такого цикла можно использовать пустое условное выражение, а для выхода из цикла обычно используют дополнительное условие и оператор break.
Пример: for (;;)
{ ...
... break;
}...
|
|
|
Введение в операторы |
||
|
|
|
|
Пример (на for): |
|
|
|
Операции и операторы. |
|||
for (<инициализация>; <условие>; |
<выражение>) оператор1; |
||||
|
|
|
|
|
[else оператор2;] |
|
|
|
for (i=0; i <n; i = i+l) a[i]=0; |
||
|
Этот оператор устанавливает первые n элементов массива a |
||||
|
равными нулю. |
|
|
|
|
|
Выполнение оператора начинается с установки i в ноль (это |
||||
|
делается вне цикла). |
||||
Затем оператор повторяется до тех пор, пока i < n, выполняя при |
|||||
|
этом присваивание и увеличение i. |
||||
Вместо оператора присвоения значения текущему элементу |
|||||
|
массива нуля может быть составной оператор (блок), |
||||
|
заключенный в фигурные скобки. |
||||
Некоторые варианты использования оператора for повышают его |
|||||
|
гибкость за счет возможности использования нескольких переменных, |
||||
|
управляющих циклом: |
||||
|
|
int main() |
|||
|
{ |
int top, bot; |
|||
|
|
|
char string[100], temp; |
||
|
|
|
for ( top=0, bot=100 ; top < bot ; top++, bot--) |
||
|
|
|
{ temp=string[top]; |
||
|
|
|
} string[bot]=temp; |
||
|
} |
return 0; |
В этом примере, реализующем запись строки символов в обратном |
|
порядке, для управления циклом используются две переменные top и bot. |
|
Отметим, что здесь используются несколько выражений, записанных |
16 |
через запятую, и выполняемых последовательно. |
2. Операторы |
|
|
|
||||||
Оператор – это наименьшая автономная часть языка |
Пустой оператор ; |
|
|
|
|||||
программирования, команда (это наименьшая исполняемая |
Составной оператор (блок); локальные переменные |
||||||||
единица программы). |
|||||||||
|
В Си часто возникает потребность объединить несколько операторов |
||||||||
Количество операторов в языке Си гораздо меньше, чем в |
|||||||||
в один. |
|
|
|
|
|
||||
Паскале, потому что все возможности, которые только могут быть |
|
|
|
|
|
||||
вытеснены из языка в библиотеку, реализованы именно в |
Локальные переменные (и другие локальные имена, о которых |
||||||||
библиотеке. |
|||||||||
Как уже говорилось, в Си (самом по себе) отсутствуют какие |
мы узнаем позже) описываются в самом начале блока, сразу после |
||||||||
открывающей фигурной скобки { и до появления в блоке первого |
|||||||||
бы то ни было средства ввода-вывода, а всевозможные printf ’ы и |
|||||||||
scanf ’ы — это библиотечные функции, которые сами написаны |
оператора. |
|
|
|
|
||||
Ветвление: |
if ( <условие> ) <оператор 1> [ else <оператор 2> ] |
||||||||
на Си. Это позволило создателям языка Си ограничиться |
|||||||||
небольшим числом операторов. |
Циклы: while ( <условие> ) <оператор>; |
||||||||
Обратите внимание на то, что, в отличие от Паскаля, символ |
|
|
|
do <оператор> while ( <условие> ) ; |
|||||
точки с запятой в Си считается не разделителем операторов, а |
|
|
|
for… |
|
|
|
||
частью синтаксиса самих операторов (притом не всех). |
Возврат из |
|
|
|
|||||
функции: |
|
return |
|||||||
Иначе говоря, если синтаксисом оператора предусмотрена |
Операторы перехода: |
|
break; continue; return; goto; |
||||||
точка с запятой, то она будет нужна там вне всякой зависимости |
Оператор выбора: switch |
|
|
||||||
от контекста; если же она не предусмотрена — то её там не будет |
Логические операторы: И |
&&; ИЛИ ||; НЕ !; |
|||||||
(это значит, что компилятор без всякой точки с запятой знает, как |
Оператор сравнения: |
==; !=; >; <; >=; <=; |
|||||||
распознать конец такого оператора). |
|||||||||
Побитовые операторы: ~; &; |; ^; <<; >>; |
|||||||||
Оператор вычисления выражения: x + 5; x = 17; |
|||||||||
Составное присваивание: |
+=; -=; |
*=; /=; %=; &=; |=; ^=; <<=; |
|||||||
Это произвольное арифметическое выражение, после |
|||||||||
которого стоит точка с запятой — она как раз и превращает |
>>=; |
|
|
|
|
|
|||
выражение (которое могло бы быть частью другого |
Операторы работы с указателями: |
|
|||||||
*a; *a; a->b; a.b; a->*b; a.*b; |
|||||||||
выражения) в законченную конструкцию — оператор. |
|
|
|
|
|
|
|
||
|
Другие операторы: |
|
|
|
|||||
Подчеркнём ещё раз, это никакой не «оператор |
|
|
|
Оператор «запятая»; |
|
|
|||
присваивания», такого в Си просто нет. Это оператор |
|
|
|
Тернарная условная операция; |
|
||||
вычисления выражения ради побочного эффекта, а само |
|
|
|
Sizeof (размер); |
|
|
|
||
выражение построено на основе бинарной арифметической |
|
|
|
и др. |
|
|
|
||
|
|
|
|
|
|||||
операции — присваивания. |
|
|
|
|
|
|
|
|
17
3. Выражения
Выражение – это объект, состоящий из констант, идентификаторов переменных, обращений к функциям и операций, указывающих, что надо делать над объектами в этом выражении.
Каждое выражение состоит из одного или нескольких операндов, символов операций и ограничителей, в качестве которых чаще всего выступают круглые скобки ( ).
Назначение любого выражения – формирование некоторого значения.
В зависимости от типа формируемых значений определяются
типы выражений.
Если значениями выражения являются целые и вещественные числа, то говорят об арифметических выражениях.
Арифметические выражения
В арифметических выражениях допустимы следующие
операции (рассматривали в предыдущих вопросах): + сложение (или унарная операция +);
- вычитание (или унарная операция изменения знака); * умножение; / деление;
% деление по модулю (то есть получение остатка от целочисленного деления первого операнда на второй).
Операндами для перечисленных операций служат константы |
||
и переменные арифметические типы, а также выражения, |
||
заключенные в круглые скобки. |
|
|
Примеры выражений с двумя операндами: |
||
a+b 12.3-x |
3.14159*Z |
k/3 16%i |
Нужно быть аккуратным, применяя операцию деления '/' к цело-численным операндам.
Например, за счет округления результата значением выражения 5/3 будет 1, а соответствует ли это замыслам программиста, зависит от смысла той конкретной конструкции, в которой это выражение используется.
Чтобы результат выполнения арифметической операции был вещественным, необходимо, чтобы вещественным был хотя бы один из операндов.
Например, значением выражения 5.0/2 будет 2.5, что соответствует смыслу обычного деления.
Как уже говорилось, введены специфические унарные операции ++ (инкремент) и -- (декремент) для изменения на «1»
операнда, который в простейшем случае должен быть переменной (леводопустимым значением).
Каждая из этих операций может быть префиксной и постфиксной.
Внешнюю неоднозначность имеют выражения, в которых знак |
|
унарной операции ++ (или --) записан непосредственно рядом со |
|
знаком бинарной операции +: |
|
x+++b или z---d |
|
В этих случаях трактовка выражений однозначна и полностью |
|
определяется рангами операций (бинарные аддитивные + и - |
|
имеют ранг 4; унарные ++ и -- имеют ранг 2). Таким образом: |
|
x+++b эквивалентно (x++)+b |
z---d эквивалентно (z--)-d |
18
Отношения и логические выражения
|
|
|
Они перечислены по убыванию старшинства (ранга). |
|
Отношение определяется как пара арифметических |
|
|
|
выражений, соединенных (разделенных) знаком операции |
|
Как правило, логические операции применяются к |
|
отношения. |
|
отношениям. |
|
Знаки операций отношения (уже были введены выше): |
|
|
|
|
До выполнения логических операций вычисляются значения |
|
|
== равно; |
||
|
отношений, входящих в логическое выражение. |
||
|
!= не равно; |
||
|
Например, если a, b, c - переменные, соответствующие длинам |
||
|
< меньше, чем; |
||
|
сторон треугольника, то для них должно быть истинно, то есть не |
||
|
> больше, чем; |
||
|
равно 0, следующее логическое выражение: |
||
|
<= меньше или равно; |
a+b>c && a+c>b && b+c>a |
|
|
>= больше или равно. |
||
|
|
Примеры отношений:
a-b>6.3 (x-4)*3==12 6<=44
Логический тип в языке Си (С89) отсутствует, поэтому принято, что отношение имеет ненулевое значение (обычно 1), если оно истинно, и равно 0, если оно ложно.
Таким образом, значением отношения 6<=44 будет 1.
Операции >, >=, <, <= имеют один ранг 6.
Операции сравнения на равенство == и != также имеют одинаковый, но более низкий ранг 7, чем остальные операции отношений.
Арифметические операции имеют более высокий ранг, чем операции отношений, поэтому в первом примере для выражения а-b не нужны скобки.
Несколько операций одного ранга выполняются слева направо, причем вычисления прерываются, как только будет определена истинность (или ложность) результата, то есть если в рассмотренном примере a+b окажется не больше c, то остальные отношения не рассматриваются - результат ложен.
Так как значением отношения является целое (0 или 1), то ничто не противоречит применению логических операций к целочисленным значениям.
При этом принято, что любое ненулевое положительное значение воспринимается как истинное, а ложной считается только величина, равная нулю.
Значением !5 будет 0, значением 4 && 2 будет 1 и т. д.
19
Выражения и операторы
Понятие R-value и L-value:
Данные в Си могут представляться литералами и переменными (и те и другие хранят значения данных в областях памяти).
Это хранимое значение называется R-value (read value), т.е.
значение, которое можно прочитать.
Значение адреса области памяти для хранения значения переменной называется L-value (location value), т.е. значение, которое определяет местоположение.
Фундаментальное различие между литералами и переменными заключается в том, что переменная именует область памяти, в которой хранится R-value, а литерал – нет.
Переменная определяет как R-value так и L-value, а литерал
только R-value.
Присваивание может включать несколько операций присваивания:
int i, j, k;
float x, y, z;
y=10; //y=10 i=j=k=0; //k=0, j=k, i=j
--------
x=i+(y=3)-(z=0); //z=0, y=3, x=i+y-z;
|
Примеры недопустимых выражений: |
|
|
присваивание константе: |
2 = x+y; |
|
|
|
присваивание функции: |
getch() = i; |
|
|
присваивание результату операции: |
(i+1) = 2+y; |
Любое выражение, которое заканчивается точкой с запятой, является оператором.
Пустой оператор состоит только из точки с запятой.
Синтаксис языка СИ требует, чтобы после метки обязательно следовал оператор. Фигурная же скобка оператором не является.
Поэтому, если надо передать управление на фигурную скобку, необходимо использовать пустой оператор:
label1:; { // код на Си return 0;
}
Программа:
Операторы; …;
Выражения…
Операнды, Операции, Скобки…
Переменные, Константы, Выражения
20