Программная инженерия. 1 курс 1 семестр / Лекции / L-05.Operatoriinstrykciiivirajeniya
.pdfБинарные (двуместные) операции. Тернарная (трёхместная) операция
Запятая в качестве операции (ранг 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
В Си различают явное и неявное преобразование типов данных.
Неявное преобразование типов данных выполняет компилятор, а явное преобразование данных выполняет сам программист.
Результат любого вычисления будет преобразовываться к наиболее точному типу данных, из тех типов данных, которые участвуют в вычислении.
|
|
Результат |
|
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 |
|
|
|
|
Значения типов char и short
всегда преобразуются в int
14
Операция присваивания. Арифметические операции
Операция присваивания
Самой общей операцией является присваивание, например, p=a/b или ch = getch(). В Си присваивание обозначается одним знаком равенства (=); при этом значение справа от знака равенства присваивается переменной слева.
Можно применять также последовательные присваивания, например: sum=a= b. В таких случаях присваивание производится справа налево, то есть b будет присвоено a, которая в свою очередь будет присвоена sum, так что все три переменных получат одно и то же значение (а именно, начальное значение b).
Комбинированные операции
Ниже приводятся некоторые примеры выражений и способы их сокращения:
a = a + b; |
сокращается до |
a += b; |
a = a – b; сокращается до |
a –= b; |
|
a = a * b; |
сокращается до |
a *= b; |
a = a / b; |
сокращается до |
a /= b; |
a = a % b; сокращается до |
a %= b; |
Пример:
Вычислите X3 и X10 , используя четыре операции умножения для заданного целого значения 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 ’ы — это библиотечные функции, которые сами написаны на Си. Это позволило создателям языка Си ограничиться небольшим числом операторов.
Обратите внимание на то, что, в отличие от Паскаля, символ точки с запятой в Си считается не разделителем операторов, а частью синтаксиса самих операторов (притом не всех).
Иначе говоря, если синтаксисом оператора предусмотрена точка с запятой, то она будет нужна там вне всякой зависимости от контекста; если же она не предусмотрена — то её там не будет (это значит, что компилятор без всякой точки с запятой знает, как распознать конец такого оператора).
Оператор вычисления выражения: x + 5; x = 17;
Это произвольное арифметическое выражение, после которого стоит точка с запятой — она как раз и превращает выражение (которое могло бы быть частью другого выражения) в законченную конструкцию — оператор.
Подчеркнём ещё раз, это никакой не «оператор присваивания», такого в Си просто нет. Это оператор вычисления выражения ради побочного эффекта, а само выражение построено на основе бинарной арифметической операции — присваивания.
Пустой оператор ; |
Составной оператор (блок); локальные переменные |
В Си часто возникает потребность объединить несколько операторов в один.
Локальные переменные (и другие локальные имена, о которых мы узнаем позже) описываются в самом начале блока, сразу после открывающей фигурной скобки { и до появления в блоке первого оператора.
Ветвление: if ( <условие> ) <оператор 1> [ else <оператор 2> ]
Циклы: |
while ( <условие> ) <оператор>; |
|
do <оператор> while ( <условие> ) ; |
|
for… |
Возврат из функции: |
return |
Операторы перехода: |
break; continue; return; goto; |
Оператор выбора: |
switch |
Логические операторы: |
И &&; ИЛИ ||; НЕ !; |
Оператор сравнения: |
==; !=; >; <; >=; <=; |
Побитовые операторы: ~; &; |; ^; <<; >>;
Составное присваивание: +=; -=; *=; /=; %=; &=; |=; ^=; <<=; >>=;
Операторы работы с указателями: *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>6.3 (x-4)*3==12 6<=44
Логический тип в языке Си (С89) отсутствует, поэтому принято, что отношение имеет ненулевое значение (обычно 1), если оно истинно, и равно 0, если оно ложно.
Таким образом, значением отношения 6<=44 будет 1.
Операции >, >=, <, <= имеют один ранг 6.
Операции сравнения на равенство == и != также имеют одинаковый, но более низкий ранг 7, чем остальные операции отношений.
Арифметические операции имеют более высокий ранг, чем операции отношений, поэтому в первом примере для выражения а-b не нужны скобки.
Они перечислены по убыванию старшинства (ранга).
Как правило, логические операции применяются к отношениям.
До выполнения логических операций вычисляются значения отношений, входящих в логическое выражение.
Например, если a, b, c - переменные, соответствующие длинам сторон треугольника, то для них должно быть истинно, то есть не равно 0, следующее логическое выражение:
a+b>c && a+c>b && b+c>a
Несколько операций одного ранга выполняются слева направо,
причем вычисления прерываются, как только будет определена истинность (или ложность) результата, то есть если в рассмотренном примере 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