Главная / 2ИСиП / Лекция 4. Операции и выражения.

Лекция 4. Операции и выражения.

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

Операнды задают данные для вычислений.

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

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

Переменные

Переменная — это именованная область памяти, в которой хранятся данные определенного типа. Во время выполнения программы значение переменной может быть изменено. Перед использованием любую переменную необходимо объявить и определить.

Объявление информирует о типе переменной и классе памяти, а определение содержит указание компилятору выделить память в соответствии с типом переменной. При определении переменной может быть присвоено начальное значение — это называется инициализацией.

Переменная может быть объявлена многократно, но определена только в одном месте программы.

Для определения переменных применяется оператор описания следующего формата:

[класс памяти] [const] тип имя [инициализатор];

В одном операторе можно описать несколько переменных одного типа, разделяя их запятыми.

Модификатор const показывает, что значение переменной нельзя изменять во время выполнения программы. Такую переменную называют типизированной константой. Она должна быть инициализирована при объявлении. Инициализатор можно записывать в двух формах — со знаком равенства или в круглых скобках:

= значение 
( значение )

Примеры описания переменных:

short int a = 1;
char s, symbol = 'f'; /* инициализация относится только к symbol */
char t = 54;
float c = 0.22, x, sum;
const char C = 'C';

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

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

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

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

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

Класс памяти определяет время жизни и область видимости программного объекта.

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

Время жизни может быть постоянным (в течение выполнения программы) и временным (в течение выполнения блока).

Для задания класса памяти используются следующие спецификаторы:

auto — автоматическая переменная. Память под нее в стеке выделяется и при необходимости инициализируется каждый раз при выполнении оператора, содержащего ее определение, и освобождается при выходе из блока, в котором она описана. Время ее жизни — локальное.

extern — переменная определяется в другом месте программы. Используется для создания переменных, доступных во всех модулях программы, где они объявлены. Если переменная в том же операторе инициализируется, спецификатор extern игнорируется.

static — статическая переменная. Время жизни — постоянное. Инициализируется один раз при первом выполнении оператора, содержащего определение переменной. В зависимости от расположения оператора описания статические переменные могут быть глобальными и локальными. Глобальные статические переменные видны только в том модуле, в котором они описаны.

register — аналогично auto, но память выделяется по возможности в регистрах процессора.

int a;//1 глобальная переменная a main()
{ int b;//2 локальная переменная b
   extern int x;//3 переменная х определена позже
     static int c;//4 локальная статическая переменная c
    a = 1;//5 присваивание глобальной переменной
   int a;//6 локальная переменная a
   a = 2;//7 присваивание локальной переменной
    ::a = 3;//8 присваивание глобальной переменной
}
int x = 4;//9 определение и инициализация x 

Если при определении начальное значение переменным явным образом не задается, компилятор присваивает глобальным и статическим переменным нулевое значение соответствующего типа. Автоматические переменные не инициализируются.

Имя переменной должно быть уникальным в своей области действия.

Операции

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

Таблица 1.5 Основные операции языка С++

Операция Краткое описание
Унарные операции  
++ увеличение на 1
– – уменьшение на 1 (пробелы между символами не допускаются)
sizeof размер
~ поразрядное отрицание
! логическое отрицание
арифметическое отрицание (унарный минус)
+ унарный плюс
& взятие адреса
* разадресация
new выделение памяти
delete освобождение памяти
(type) преобразование типа
Бинарные операции  
* умножение
/ деление
% остаток от деления
+ сложение
вычитание
<<  сдвиг влево
>>  сдвиг вправо
меньше
<= меньше или равно
больше
>= больше или равно
== равно
!= не равно
& поразрядная конъюнкция (И)
^ поразрядное исключающее ИЛИ
| поразрядная дизъюнкция (ИЛИ)
&& логическое И
|| логическое ИЛИ
? : условная операция
= присваивание
*= умножение с присваиванием
/= деление с присваиванием
%= остаток отделения с присваиванием
+= сложение с присваиванием
–= вычитание с присваиванием
<<= сдвиг влево с присваиванием
>>= сдвиг вправо с присваиванием
&= поразрядное И с присваиванием
|= поразрядное ИЛИ с присваиванием
^= поразрядное исключающее ИЛИ с присваиванием
, последовательное вычисление

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

Операндом операции инкремента в общем случае является так называемое L-значение (L-value). Так обозначается любое выражение, адресующее некоторый участок памяти, в который можно занести значение. Переменная является частным случаем L-значения.

Операции отрицания (–, ! и ~). Арифметическое отрицание (унарный минус –) изменяет знак операнда целого или вещественного типа на противоположный.

Логическоеотрицание (!) дает в результате значение 0, если операнд есть истина (не нуль), и значение 1, если операнд равен нулю. Операнд должен быть целого или вещественного типа или типа указатель.

Поразрядное отрицание (~), часто называемое побитовым, инвертирует каждый разряд в двоичном представлении целочисленного операнда.

Деление (/) и остаток от деления (%). Операция деления применима к операндам арифметического типа. Если оба операнда целочисленные, результат операции округляется до целого числа, в противном случае тип результата определяется правилами преобразования.

Операция остатка от деления применяется только к целочисленным операндам. Знак результата зависит от реализации.

Операции отношения ( <, <=, >, >=, = =, != ) сравнивают первый операнд со вторым. Операнды могут быть арифметического типа или указателями. Результатом операции является значение true или false. Операции сравнения на равенство и неравенство имеют меньший приоритет, чем остальные операции сравнения.

Поразрядные операции (&, |, ^) применяются только к целочисленным операндам и работают с их двоичными представлениями. При выполнении операций операнды сопоставляются побитово (первый бит первого операнда с первым битом второго, второй бит первого операнда со вторым битом второго, и т.д.).

Логические операции (&& и ||). Операнды логических операций И (&&) и ИЛИ (||) могут иметь арифметический тип или быть указателями, при этом операнды в каждой операции могут быть различных типов.

Преобразования типов не производятся, каждый операнд оценивается с точки зрения его эквивалентности нулю (операнд, равный нулю, рассматривается как false, не равный нулю — как true). Результатом логической операции является true или false.

Логические операции выполняются слева направо.

Операции присваивания (=, +=, -=, *= и т.д.). Операции присваивания могут использоваться в программе как законченные операторы. К операциям они относятся потому, что могут использоваться в выражениях и формируют результат своего выполнения.

Формат операции простого присваивания (=):

операнд_1 = операнд_2

Первый операнд должен быть L-значением, второй — выражением. Сначала вычисляется выражение, стоящее в правой части операции, а потом его результат записывается в область памяти, указанную в левой части.

В сложных операциях присваивания ( +=, *=, /= и т.п.) при вычислении выражения, стоящего в правой части, используется и L-значение из левой части, например, при сложении с присваиванием ко второму операнду прибавляется первый, и результат записывается в первый операнд.

Условная операция (?:). Эта операция тернарная, то есть имеет три операнда. Ее формат:

операнд_1 ? операнд_2 : операнд_3

Первый операнд может иметь арифметический тип или быть указателем. Он оценивается с точки зрения его эквивалентности нулю.
Если результат вычисления операнда 1 равен true, то результатом условной операции будет значение второго операнда, иначе — третьего операнда.

Выражения

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

Примеры выражений:

(a + 0.12)/6
x && y || !z
(t * sin(x)-1.05e4)/((2 * k + 2) * (2 * k + 3))

Операции выполняются в соответствии с приоритетами. Для изменения порядка выполнения операций используются круглые скобки.
Если в одном выражении записано несколько операций одного приоритета, унарные операции, условная операция и операции присваивания выполняются справа налево, остальные — слева направо.
Порядок вычисления подвыражений внутри выражений не определен.
Результат вычисления выражения характеризуется значением и типом.
В выражение могут входить операнды различных типов. Если операнды имеют одинаковый тип, то результат операции будет иметь тот же тип.
Если операнды разного типа, перед вычислениями выполняются преобразования типов по правилам, обеспечивающим преобразование более коротких типов в более длинные для сохранения значимости и точности.

Арифметические операции с числами.

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

Название операции Символ, применяемый для обозначения в языке С. Краткое описание. Пример.
Сложение + Складывает два значения вместе, результатом является сумма операндов: 5+18 результат 23
Вычитание Вычитает значение, находящееся справа из значения, находящегося слева от оператора. Результат – разность операндов: 20-15 результат 5
Умножение * Перемножает два значения, результатом является произведение операндов: 5*10 результат 50
Деление / Делит значение, находящееся слева на значение, находящееся справа от оператора. Например: 20/4 результат 5
Деление по модулю % Результатом этой операции является остаток от целочисленного деления, например, если мы делим 11 на 3, то целых частей у нас получается 3, (так как 3*3=9), в остатке будет 2, это число и будет результатом деления по модулю:
11/3 = 3 целых 2 в остатке
11%3 = 2 (остаток)

Инкремент и декремент.

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

1.Инкремент – обозначается конструкцией ++. Данный оператор увеличивает содержимое любой переменной на единицу и перезаписывает значение переменной. Например,

int a=8;
cout<<a; // на экране число 8 a++;
cout<<a; // на экране число 9

2.Декремент – обозначается конструкцией —. Данный оператор уменьшает содержимое любой переменной на единицу и перезаписывает значение переменной. Например,

int a=8;
cout<<a; // на экране число 8 a—;
cout<<a; // на экране число 7

Достаточно просто, не правда ли?! Такие выражения могут быть представлены и так: a=a+1 или a=a-1. Следует отметить, что для литералов ни инкремент, ни декремент не используются, т. к. совершенно не логично поступать следующим образом 5=5+1. Это явная ошибка. Однако на этом мы не закончим знакомство с инкрементом и декрементом. В прошлом разделе урока мы выяснили, что синтаксис унарного оператора, может быть не только таким

операнд оператор;

, но и таким

оператор операнд;

Такие формы записи носят название постфиксной, (оператор располагается после значения) и префиксной (оператор располагается до значения). И инкремент, и декремент обладают обеими формами. Давайте разберемся, какие есть различия между формами, и в каких случаях эти различия имеют значение.

Пример 1.

int a=8;
cout<<a; // на экране число 8 a++;
cout<<a; // на экране число 9 ++a;
cout<<a; // на экране число 10

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

Пример 2.

int a=8;
cout<<++a; // на экране число 9
cout<<a++; // на экране число 9
cout<<a; // на экране число 10

Прежде чем разбирать пример, давайте установим три правила:

1. Все команды в языке С выполняются справа налево.
2. Если кроме постфиксной формы инкремента или декремента, в строке есть еще какая-либо команда, то сначала выполняется эта команда, и только потом инкремент или декремент независимо от расположения команд в строке.
3. Если кроме префиксной формы инкремента или декремента, в строке есть еще какая-либо команда, то все команды в строке выполняются справа налево согласно приоритету операторов.

Теперь более подробно о примере:

• Изначально значение переменной равно числу 8.
• Команда cout<<++a; содержит префиксную форму оператора инкремент, следовательно, используя третье правило, описанное выше, мы сначала увеличиваем значение переменной а на единицу, а затем показываем его на экран с помощью команды cout<<.
• Команда cout<<a++; содержит постфиксную форму оператора инкремент, следовательно, используя второе правило, описанное выше, мы сначала показываем значение переменной (всё еще 9) на экран с помощью команды cout<<, а затем увеличиваем значение переменной a на единицу.
• При выполнении следующей команды cout<<a; будет показано уже измененное (увеличенное) значение, то есть число 10.

Сокращенные арифметические формы.

Исходя из предыдущих тем данного раздела урока, мы с вами теперь знаем, как упростить неудобную и «некрасивую» запись типа х=х+1 или х=х-1, превратив её в х++, или х—. Но таким образом, мы можем увеличивать и уменьшать значение переменной лишь на единицу, а как быть с любым другим числом? Например, как упростить запись:

Х=Х+12;

В данном случае, тоже есть простое решение – использовать так называемые комбинированные операторы или сокращенные арифметические формы. Выглядят они следующим образом:

Название формы Комбинация Стандартная запись Сокращенная запись
Присваивание с умножением *= А=А*N A*=N
Присваивание с делением /= A=A/N A/=N
Присваивание с делением по модулю %= A=A%N A%=N
Присваивание с вычитанием -= A=A-N A-=N
Присваивание со сложением += A=A+N A+=N

Мы рекомендуем вам в дальнейшем пользоваться сокращенными формами, так как это не только является хорошим тоном в программировании, но и значительно повышает читабельность программного кода. Кроме того, в некоторых источниках упоминается о том, что сокращенные формы обрабатываются компьютером быстрее, повышая скорость выполнения программы.

 Математические функции языка С#

С# содержит большое количество встроенных математических функций, которые реализованы в классе Math пространства имен System.

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

Замечание. Использование нескольких функций с одним и тем же именем, но с различными типами параметров, называется перегрузкой функции. Например, функция Math.Abs(), вычисляющая модуль числа, имеет 7 перегруженных версий: double Math.Abs (double x), float Math.Abs (float x), int Math.Abs(int x), и т.д.

Название Описание
1. Math.Abs(<выражение>) Модуль
2. Math.Ceiling(<выражение>) Округление для большего целого
3. Math.Cos(<выражение>) Косинус
4. Math.Е Число е
5. Math.Exp(<выражение>) Экспонента
6. Math.Floor(<выражение>) Округление до меньшего целого
7. Math.Log(<выражение>) Натуральный логарифм
8. Math.Log10(<выражение>) Десятичный логарифм
9. Math.Max(<выражение1>, <выражение2>) Максимум из двух значений
10. Math.Min(<выражение1>, <выражение2>) Минимум из двух значений
11. Math.PI Число
12. Math.Pow(<выражение1>, <выражение2>) Возведение в степень
13. Math.Round(<выражение>) Простое округление
14. Math.Sign(<выражение>) Знак числа
15. Math.Sin(<выражение>) Синус
16. Math.Sqrt(<выражение>) Квадратный корень
17. Math.Тan(<выражение>) Тангенс