Данные вещественного типа


Тип данных Диапазон значений
float от 3.4Е-38 до 3.4Е+38
double от 1.7Е-308 до 1.7Е+308
long double от 3.4Е-4932 до 3.4Е+4932

 

Примеры различных вариантов записи вещественной константы единица.

1.0Е+0, 1.0, 1., 1Е+0, 0.1e+1; /* вещественные единицы типа double*/

1.0Е+0l, 1.0l, 1.l, 1Е+0l, 0.1e+1l;/* вещественные единицы типа long double*/

1.0Е+0f, 1.0f, 1.f, 1Е+0f, 0.1e+1f; /* вещественные единицы типа float*/

Перечислимые константы вводятся с помощью служебного слова enum. По существу, это обычные целочисленные константы (типа int), которым приписываются уникальные и удобные для использования обозначения. В общем виде перечислимые константы объявляются следующим образом:

enum [ имя типа] { имя1 [=инициализатор] ,

имя2 [=инициализатор], … , имяN [=инициализатор]};

где имя1, имя2,…, имяN – произвольные идентификаторы, не совпадающие со служебными словами и именами других объектов программы. В квадратные скобки заключены элементы перечисления, которые могут быть опущены. Если в объявлении перечисляемых констант опустить = инициализатор, то они будут приписываться идентификаторам по умолчанию. При этом самый левый в фигурных скобках идентификатор получит значение 0, а каждый последующий увеличивается на единицу.

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

enum { zero, one, two, ten = 10, eleven, five = 5, six, sss };

Перечисляемые константы zero, one, two, ten, eleven, five, six, sss в соответствии с описанными выше правилами получили следующие значения: zero == 0, one == 1, two == 2, ten == 10, eleven ==11, five == 5, six ==6, sss == 7.

Символьные (литерные) константы – это один или два символа, заключённые в апострофы (‘ ‘). Односимвольные константы имеют стандартный тип char. Примеры односимвольных констант ‘x’, ‘Z’, примеры двухсимвольных констант ‘DS’, ‘Sa’. Кроме приведенных выше примеров существует ещё один способ записи символьных констант. Это последовательность символов, начинающихся со знака ‘\’, которую называют Esc-последовательностью. Примеры символьных констант (Esc -последовательностей) ‘\n’, ‘\0’, ‘\012’, ‘\x07\x07’, ‘\n\t’. Таблица допустимых в языке Си++ Esc – последовательностей приведена ниже.

Таблица 2.4

Допустимые Esc-последовательности в языке Си++.

N Изобра- жение Внутрен- ний код Обозначаемый символ (название) Значение или реакция
0x07 Bel (audible bell) Звуковой сигнал
\b 0x08 Bs (backspace) Возврат на шаг (забой)
\f 0x0c Ff (form feed) Перевод страницы (формата)
\n 0x0a Lf (line feed) Перевод строки (новая строка)
\r 0x0d Cr (carriage return) Возврат каретки
\t 0x09 Ht (horizontal tab) Табуляция горизонтальная
\v 0x0b Vt (vertical tab) Табуляция вертикальная
\\ 0x5c \ (backslash) Обратная косая черта
\’ 0x27 ‘ (single quote) Апостроф ( одиночная кавычка)
\” 0x22 “ (double quote) Двойная кавычка
\? 0x3f ? (question mark) Вопросительный знак
\000 (Octal number) Восьмеричный код символа
\xhh 0xhh (hex number) Шестнадцатеричный код символа

 

Первые семь Esc – последовательностей таблицы являются управляющими кодами для устройств с посимвольным интерфейсом (принтер, монитор и т.д.). Они не отображаются в тексте и вообще не имеют графического представления. Но когда принтер или монитор выводит на экран текст и в нем встречаются два байта с кодом 0x0d, 0x0a (\r\n), то вместо вывода символов на экран они выполняют команды перейти к началу текущей строки и перейти на новую строку. То есть, вставляя в нужных местах текста, управляющие Esc – последовательности, мы можем форматировать текст на экране монитора или на распечатке принтера так, как считаем нужным.

Необходимость в 8 – 11 Esc-последовательностях возникает, когда требуется использовать символы \, ‘, “, ? в тексте программы. Действительно, если в символьной строке встречается один символ \, то он воспринимается не как символ косой черты \, а как признак начала Esc – последовательности. Поэтому, если в программе необходимо написать строку, содержащую путь к файлу, например “С:\BC\BIN\bc.txt”, то правильно её будет записать так “C:\\BC\\BIN\\bc.exe”, воспользовавшись Esc – последовательностью ‘\\’.

Последние два варианта записи Esc-последовательности \000 и \хhh позволяют задать символ с помощью его кода в восьмеричном или шестнадцатеричном представлении. Дело в том, что каждый символ в памяти компьютера хранится в виде однобайтового числа (кода). Соответствие между кодом и символом устанавливается по так называемым табл. ASCII кодов (приложение 1). Так символу W по табл. ASCII кодов соответствует код 87, который в восьмеричной или шестнадцатеричной системе счисления записывается как 127 и 57 соответственно. Поэтому символ W можно записать в программе несколькими способами как ‘W’ или с помощью Esc-последовательностей, как ‘\125’ или '\х57'.

Необходимо отметить, что табл. ASCII 866 для MS-DOS отличается от табл. ASCII 1251 для MS Windows. Так, например, символ ‘Ф’ в ASCII 866 имеет код 148, а ASCII 1251 – код 212. Именно поэтому текст, набитый в редакторе под DOS, не может быть прочитан без перекодировки в текстовых редакторах под Windows.

Строка или строковая константа, иногда называемая литерной строкой, определяется как последовательность символов, заключённых в кавычки “ ” (не в апострофы):

Пример строки:

“Это строка, называемая также строковой константой”

Среди символов строки могут использоваться ESC-последовательности. В этом случае, как и в представлениях отдельных символов, они начинаются с обратной косой черты \.

//Программа 1.2

#include "stdafx.h"

#include <iostream>

void main(){

std::cout<<"\n This is a string, \nor - \" string \",\

\n or - ";

std::cout<<"\"literal string \".";

getchar();

}

При выводе на экран дисплея этих строк Esc-последовательности ‘\n’ и ‘\”’ обеспечат такое размещение информации.

This is a string,

Or - “string”,

or – “literal string”.

При использовании строк в программе необходимо помнить, что компилятор в конец строки по умолчанию добавляет один бай с кодом х00 (нулевой байт) или, как говорят, нулевой символ ‘\0’ (‘\000’, ‘\x00’). Поэтому длина в байтах любой строки всегда на единицу больше, чем число символов в ней присутствующих.

Пример:

“”;//– пустая строка, содержащая только один символ ‘\0’.

“Это строка”;/ десять символов включая пробел плюс символ ‘\0’ итого одиннадцать/

“\tЭто строка” /*Как уже говорилось, Esc-последовательность, в данном случае ‘\t’, хотя и записывается в виде двух символов, но на самом деле является одним символом (байтом), поэтому длина этой строки двенадцать байт. */

 

Операции

Знаки операций обеспечивают формирование и последующее вычисление выражений. Один и тот же знак операции может употребляться в различных выражениях и по-разному интерпретироваться в зависимости от контекста. Для изображения операций в большинстве случаев используются несколько символов. В стандарте языка Си++ определены следующие знаки операций:

[ ] ( ) . -> ++ -- & * + - ~ ! sizeof

/ % << >> < > <= >= == != ^ | &&

|| ?: = *= /= %= += -= <<= >>= &= ^= |=

, :: .* ->* new delete typeid

За исключением операций [], () и ?: все знаки операций распознаются компилятором как отдельные лексемы. Язык Си++ даёт возможность расширить действия или, как говорят, перегрузить стандартные операции, т.е. распространить их действие на нестандартные для них операнды (объекты, например переменные, константы, над которыми выполняется операция). Опишем кратко стандартные возможности отдельных операций.

Унарные операции (операции над одним операндом):

& операция получения адреса операнда;

* операция обращения по адресу, т.е. раскрытия ссылки, иначе операция разыменования (доступ по адресу к значениям того объекта на который указывает операнд). Операндом должен быть адрес;

- унарный минус изменяет знак арифметического операнда (-3);

+ унарный плюс (введен для симметрии с унарным минусом) (+5);

~ поразрядное инвертирование внутреннего двоичного кода целочисленного аргумента (побитовое отрицание) ~5 равно -6, (5 в двоичном виде равна 00000000 00000101 при выполнении побитового отрицания получаем 11111111 11111010, что соответствует в дополнительном коде числу -6);

! логическое отрицание (НЕ) применяется к скалярным операндам целочисленный результат 0 (если операнд не нулевой, т.е. истинный) или 1 (если операнд нулевой, т.е. ложный). В качестве логического значения в языке Си++ используют целые числа: 0 – ложь и не нуль (!0) – истина. Отрицание любого ненулевого числа будет – 0, а отрицание нуля будет 1. Таким образом: !1 равно 0; !2 равно 0; !(-5.5) равно 0; !0 равно 1;

++ увеличение на единицу (инкремент или автоувеличение) унарная операция, операндом которой должно быть леводопустимое выражение;

++операнд – (префиксная операция) увеличение значения операнда на единицу до его использования в выражении; Пример:

int a = 3, b = 2;

b = (++a)-b; /*Результат работы b = 2, a = 4. Сначала а увеличивается на единицу, и только потом рассчитывается выражение b=а –b.*/

операнд++ - (постфиксная операция) увеличение значения операнда на единицу после его использования в выражении. Пример:

int a = 3, b = 2;

b = (a++)-b; /*Результат работы b = 1, a = 4. Сначала вычисляется выражение b = a – b, и только потом а увеличивается на единицу.*/

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

-- уменьшение на единицу (декремент или автоуменьшение) – унарная операция, операндом которой должно быть леводопустимое выражение;

--операнд – (префиксная операция) уменьшение значения операнда на единицу до его использования в выражении;

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

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

sizeof операция вычисления размера (в байтах) объекта того типа, который имеет операнд. Разрешены два формата операции: sizeof унарное выражение и sizeof (тип).

Проиллюстрируем применение этой операции со стандартными типами:

//Программа 1.3

#include "stdafx.h"

#include <iostream>

void main(){

std::cout<<"\n sizeof(int) = "<<sizeof(int);

std::cout<<"\t sizeof(short) = "<<sizeof(short);

std::cout<<"\t sizeof(long) = "<<sizeof(long);

std::cout<<"\n sizeof(float) = "<<sizeof(float);

std::cout<<"\t sizeof(double) = "<<sizeof(double);

std::cout<<"\t sizeof(char) = "<<sizeof(char);

std::cout<<"\n sizeof('2') = "<<sizeof('2');

std::cout<<"\t sizeof(2) = "<<sizeof(2);

std::cout<<"\t sizeof(2L) = "<<sizeof(2L);

std::cout<<"\n sizeof(2U) = "<<sizeof(2U);

std::cout<<"\t sizeof(2.) = "<<sizeof(2.);

std::cout<<"\t sizeof(2.F) = "<<sizeof(2.F);

std::cout<<"\t sizeof(2.L) = "<<sizeof(2.L);

getchar();

}

Результаты выполнения программы приведены ниже. Они полностью согласуются с данными в табл. 2.1, т.е. объект типа int занимает в памяти два байта, объект типа short два байта и т.д. Количество памяти, отводимое под константу, зависит от её типа, а тип константы зависит от способа её записи в программе. Так, использованные в программе константы имеют следующие типы: ‘2’ – char, 2 – int, 2L – long, 2U – unsigned int, 2. – double, 2.F – float, 2.L – long double.

sizeof(int)=4 sizeof(short) = 2 sizeof(long)=4
sizeof(float)=4 sizeof(double)=8 sizeof(char)=1
sizeof(‘2’)=1 sizeof(2) = 4 sizeof(2L) = 4
sizeof(2U)=2 sizeof(2.) = 8 sizeof(2.F)=4
sizeof(2.L)=8    

Бинарные операции (операция над двумя операндами). Эти операции делятся на следующие группы:

· аддитивные;

· мультипликативные;

· сдвигов;

· поразрядные;

· операции отношений;

· логические;

· присваивания;

· выбор компонента структурированного объекта;

· операции с компонентами классов;

· операция «запятая»;

· скобки в качестве операций.

Аддитивные операции:

+ бинарный плюс (сложение арифметических операндов или сложение указателя с целочисленным операндом);

- бинарный минус (вычитание арифметических операндов или указателей).

Мультипликативные операции:

* умножение операндов арифметического типа;

/ деление операндов арифметического типа. При целочисленных операндах (константах и переменных целого типа) абсолютное значение результата округляется до целого. Например, 19/3 равно 6, -19/6 равняется - 6.

% получение остатка от деления целочисленных операндов (деление по модулю). При неотрицательных операндах остаток положительный. В противном случае остаток определяется реализацией компилятора. В компиляторе ВС++: 17%4 равняется 1, (-17)%4 равняется –1, 17%(-4) равно +1, (-17)%(-4) равняется –1. При ненулевом делителе для целочисленных операндов всегда выполняется соотношение: (a/b)*b+a%b = a.

Операции сдвига (определены только для целочисленных операндов).

Формат выражения с операцией сдвига:

левый_операнд операция_сдвига правый_операнд

<< сдвиг влево битового представления значения левого целочисленного операнда на количество разрядов, равное значению правого целочисленного операнда. Сдвиг влево на n позиций битового представления значения левого целочисленного операнда эквивалентен умножению его значения на 2n. Пример: 6<<2 равно 24 (6 в двоичной системе это 110 сдвинув влево на два разряда, т.е. дописав справа два нуля, получим в двоичной системе 11000 или 24 в десятичной);

>> сдвиг вправо битового представления значения левого целочисленного операнда на количество разрядов, равное значению правого целочисленного операнда. Сдвиг вправо на n позиций битового представления значения левого целочисленного операнда эквивалентен уменьшению его значения в 2n раз с отбрасыванием дробной части результата. Пример: 9>>2 равно 2 (9 в двоичной системе это 1001 сдвинув вправо на два разряда, т.е. отбросив справа две цифры, получим в двоичной системе 10 или 2 в десятичной).

Поразрядные операции (определены только для целочисленных операндов):

& поразрядная конъюнкция (И) битовых представлений значений целочисленных операндов;

| поразрядная дизъюнкция (ИЛИ) битовых представлений значений целочисленных операндов;

^ поразрядное исключающее (ИЛИ) битовых представлений значений целочисленных операндов.

Таблица 2.5

Таблица истинности для операций &, |, ^

a b a&b a|b a^b

 

Таблицей истинности следует пользоваться следующим образом, если а = 0 и b = 0, то результаты операций a&b, a|b, a^b в соответствии с таблицей истинности равны a&b = 0, a|b = 0, a^b = 0. Поскольку рассматриваются битовые операции, то под a и b следует понимать биты одной и той же разрядности в операндах рассматриваемых операций. Так, например:

побитовое выполнение операций &, |, ^ над операндами 9 и 7.

 

Операции отношения (сравнения):

< меньше, чем; например, 5<6 равно истина (1), 5<4 равно ложь (0);

> больше, чем; например: 5>6 равно ложь (0), 5>4 равно истина (1);

<= меньше или равно; например, 5<=5 равно истина (1), 5<=4 равно ложь (0);

>= больше или равно;

== равно;

!= не равно.

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

Логические бинарные операции:

&& конъюнкция (И) арифметических операндов или отношений. Целочисленный результат 0 (ложь) или 1 (истина);

|| дизъюнкция (ИЛИ) арифметических операндов или отношений. Целочисленный результат 0 (ложь) или 1 (истина).

Таблица 2.6

Таблица истинности для операций && и ||

a b a&&b a||b

 

Таблицей истинности следует пользоваться следующим образом, если а = 0 и b = 0, то результаты операций a&&b, a||b в соответствии с таблицей истинности равны a&&b = 0, a||b = 0. Поскольку рассматриваются логические операции, то под a и b следует понимать весь операнд в целом, а не отдельные его биты, причём если операнд является любым число отличным от нуля, то он истина, т.е. 1, если операнд равен нулю, то он ложь, т.е. 0. Результат логической операции всегда либо нуль (ложь), либо единица (истина). Так, например, 9&&7 = 1, 9||7 = 1, 9&&-7=1, 0&&7 = 0.

Операции присваивания

В качестве левого операнда присваивания может выступать только модифицированное l-значение – ссылка на некоторую именованную область памяти, значение которой доступно изменениям. Название леводопустимое выражение или l-значение произошло от изображения операции присваивания (А=Е, А стоит слева от операции присваивания), так как только l-значение может быть использовано в качестве его левого операнда. Леводоступное выражение определяет в общем случае именованную ссылку на некоторый объект, значение которого доступно изменениям. Частным случаем такой ссылки является имя переменной. Пример:

float a;

const double pi = 3.1415;

а = 2; /* переменная а – леводоступное выражение (переменной а можно присвоить значение и компилятор не выдаёт ошибки)*/

2 = а; /*неименованная константа не может быть леводоступным выражением (компилятор выдаст ошибку)*/

pi = 3.14159; /*именованная константа не может быть леводоступным выражением (компилятор выдаст ошибку) */

(а+а) = 3; /*неименованное выражение не может быть леводоступным выражением (компилятор выдаст ошибку) */

Итак, перечислим операции присваивания:

= присваивание значения выражения- операнда из правой части операнду левой части: Р= 10.3 +2*b ;

*= присвоить операнду левой части произведение значений обоих операндов: Р*=2 эквивалентно Р=Р*2;

/= присвоить операнду левой части частное от деления значений левого операнда на значение правого: Р/=2.4-с эквивалентно Р=Р/(2.4-с);

%= присвоить операнду левой части остаток от деления целочисленного значения левого операнда на целочисленное значение правого операнда: Р%=В-2*С эквивалентно Р=Р%(В-2*С);

+= присвоить операнду левой части сумму значений обоих операндов: А+=А-В эквивалентно А= А+(А-В);

-= присвоить операнду левой части разность значения левого и правого операндов: Х-=5.2-С эквивалентно Х=Х-(5.2-С);

<<= присвоить целочисленному операнду левой части значение, полученное сдвигом влево его битового представления на количество разрядов, равное значению правого целочисленного операнда: а<<=4 эквивалентно а=a<<4;

>>= присвоить целочисленному операнду левой части значение, полученное сдвигом вправо его битового представления на количество разрядов, равное значению правого целочисленного операнда: а>>=4 эквивалентно а=a>>4;

&= присвоить целочисленному операнду левой части значение, полученное поразрядной конъюнкцией (И) его битового представления с битовым представлением целочисленного операнда правой части е&=34 эквивалентно е=е&34;

|= присвоить целочисленному операнду левой части значение, полученное поразрядной дизъюнкцией (ИЛИ) его битового представления с битовым представлением целочисленного операнда правой части а|= в эквивалентно а=а|в;

^= присвоить целочисленному операнду левой части значение, полученное применением поразрядной операции исключающего (ИЛИ) к битовым представлениям значений обоих операндов а^=х+в эквивалентно а=а^(х+в).

Обратите внимание, что для всех операций сокращенная форма присваивания Операнд1 op= Выражение эквивалентна Операнд1 = Операнд1 op (Выражение), где op – обозначение операции, т.е. всегда вычисляется сначала значение выражения и только потом выполняется операция op=.

Существует ли какая-нибудь разница при выполнении строк программы, отличающихся друг от друга только способом записи, например, (a= a+1;) или (a+=1;)? Да, разница существует и заключается только в том, что вторая строка выполняется быстрее. Последовательность действий при выполнении первой строки программы можно описать так: создаётся неименованная переменная, которая инициализируется значением переменной a; неименованная переменная увеличивается на единицу; переменной а присваивается значение неименованной переменной. Последовательность действий при выполнении второй строки программы можно описать так: переменная а увеличивается на единицу. То есть, можно сказать, что вторая строка программы выполняется приблизительно в три раза быстрее.

Операция выбора компонента структурированного объекта:

. (операция точка) прямой выбор компонента структурированного объекта, например, структуры. Формат применения операции:

имя_структурированного_объекта.имя_компонента;

-> косвенный выбор компонента структурированного объекта, адресуемого указателем. При использовании операции требуется, чтобы с объектом был связан указатель. В этом случае формат применения операции имеет вид:

указатель_на_структурированный_объект-> имя_компонента;

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

Операции с компонентами классов:

.* прямое обращение к компоненту класса по имени объекта и указателю на компонент;

->* косвенное обращение к компоненту класса через указатель на объект и указатель на компонент.

Комментарии по этим операциям будут даны позже после введения понятия класса.

:: операция указания области видимости имеет две формы: бинарную и унарную. Бинарная форма применяется для доступа к компоненту класса. Унарная операция :: позволяет получить доступ к внешней для некоторой функции именованной области памяти.

Запятая в качестве операции:

, несколько выражений, разделенных запятыми, вычисляются слева направо. В качестве результата сохраняются тип и значение самого правого выражения. Таким образом, операция «запятая» группирует вычисления слева направо. Тип и значение результата определяется самым правым из разделенных запятыми выражений. Значения всех левых выражений игнорируются. Например, в выражении (d = 4, f=5, d*2-f;) действия выполняются в таком порядке: переменной d присваивается 4; переменной f присваивается 5; результатом всего выражения в скобках является значение d*2-f т.е. 3.

Круглые ( ) и квадратные [ ] скобки играют роль бинарных операций при вызове функций и индексировании элементов массивов. Таким образом, вызов функции, который имеет формат

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

- это операция. Обращение к элементу массива, например, ar[1] -это тоже операция, которую можно записать и в таком виде ar+1.

Условная операция

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

выражение_1 ? выражение_2 : выражение_3

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

int x = 1;

х = x<0 ? –x : x;

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

Операция явного преобразования (приведения) типа в языке Си++ имеет две различные формы. Каноническая форма, унаследованная от языка Си, имеет следующий формат:

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

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

Кроме рассмотренной канонической операции преобразования типа, в языке Си++ введена ещё одна возможность приведения типов, которую обеспечивает функциональная форма преобразования типа:

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

Она может использоваться только в тех случаях, когда тип имеет простое (несоставное) наименование. Например:

long(2); //Всё правильно ошибок нет. Создаётся неименованная константа типа //long, которая инициализируется значением 2

unsigned long (2);// Ошибка. Имя типа составное.

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

Операции new и delete для динамического распределения памяти. Эти две унарные операции используются для динамического распределения памяти. Операция

new имя_типа;

либо

new имя_типа инициализатор;

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

тип* имя_ указателя = new имя_типа инициализатор;

или

тип* имя_ указателя = new имя_типа;

где имя_указателя – это идентификатор.

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

delete имя_указателя;

где имя_указателя адресует освобождаемый участок памяти, ранее выделенный с помощью операции new. Повторное применение операции delete к тому же указателю даёт неопределенный результат. Также непредсказуем результат применения этой операции к указателю, получившему значение без использования операции new. Однако применение delete к указателю с нулевым значением (NULL) не запрещено, хотя и не имеет особого смысла.

 

Таблица 2.7

Ранг операций. Ниже приведена таблица рангов (приоритетов) операций.

Ранг Операции Ассоциатив- ность
( ) [] -> :: . ®
! ~ + - ++ -- & * sizeof (унарные операции) new delete (тип) тип( )  
.* ->* ®
* / % (мультипликативные бинарные операции) ®
+ - (аддитивные бинарные операции) ®
<< >> ®
< <= >= > ®
== != ®
& ®
^ ®
| ®
&& ®
|| ®
? : ( условная операция)  
= *= /= %= += -= &= ^= |= <<= >>=  
, (операция запятая) ®

 

При вычислении выражений операции выполняются последовательно друг за другом в строгом соответствии с их рангом. В первую очередь в выражении выполняются операции с наивысшим 1-м рангом, потом 2-м рангом и т.д.. Последними выполняются операции с наинизшим 16-м рангом. Если в выражении имеются операции одного ранга, то они выполняются последовательно друг за другом в соответствии с направлением ассоциативности для этого ранга (слева направо ® или справа налево ). Например, в выражении (13-4>5 && 3+5<4 && 4+5>3) восемь операций. Наивысшим ранг в данном случае пятый у аддитивных операций ( - , +). Ассоциативность для этого ранга направлена слева направо поэтому операции будут выполнены друг за другом в следующем порядке (13-4), (3+5), (4+5). Найдем результат этого выражения, выполняя последовательно операции в соответствии с их рангом и ассоциативностью:

(13-4>5 && 3+5<4 && 4+5>3)

(9>5 && 3+5<4 && 4+5>3)

(9>5 && 8<4 && 4+5>3)

(9>5 && 8<4 && 9>3)

(1 && 8<4 && 9>3)

(1 && 0 && 9>3)

(1 && 0 && 1)

(0 && 1)

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

 

Разделители

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

[] () {} , ; : … * = # &

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

Квадратные скобки [] являются разделителями (а не операцией) при определении размерности объявляемого массива

int A[] = { 1,2,3,4,5}; //квадратные скобки выступают в качестве разделителя

int s[2][5]; //квадратные скобки выступают в качестве разделителя

Круглые скобки ():

· входят как обязательный элемент в операторы цикла и условия;

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

· обязательны в оюъявлении указателя на функцию;

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

· являются необходимым элементом при выполнении операции преобразования типа;

· применение круглых скобок настоятельно рекомендуется в макроопределениях.

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

Запятая , разделяет элементы списков, используется в описаниях и определениях объектов одного типа, участвует в качестве разделителя в заголовке оператора цикла for.

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

Точка запятой ; завершает каждый оператор, каждое определение (кроме определения функции) и каждое описание. Любое допустимое выражение, за которым следует ‘;’, воспринимается как оператор. Это справедливо и для пустого выражения, т.е. отдельный символ «точка с запятой» считается пустым оператором.

Двоеточие : служит для отделения метки от помечаемого ею оператора:

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

Метка – это идентификатор. Таким образом, допустимы, например, такие помеченные операторы:

XYZ: a = b+c –d; vv: x*=10; // XYZ и vv метки

Второе применение двоеточия – описание производного класса, где имя класса отделяется от списка базовых классов двоеточием.

Многоточие ‘…’ - это три точки без пробелов между ними. Оно используется для обозначения переменного числа параметров у функции при её описании и определении.

Звездочка * не является операцией при описании и определении указателей, например:

int * point; // звездочка не выполняет роль операции при описании указателя

char ** refer; // аналогично

Знак ‘=’ является разделителемпри определении объекта, отделяя определение объекта от списка его инициализации:

int D = 62; //

В списке формальных параметров функции знак ‘=’ указывает на выбираемое по умолчанию значение аргумента (фактического параметра).

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

Символ & и && играет роль разделителя при объявлении переменных типа ссылка:

int Bl;

int& a1 = B1;//а1 это ссылка, которую можно инициировать lvalue-объектом, т.е. объектом, который в принципе можно поставить слева от знака =,(например, B1 = 7;). Если написать код int& a1 = 2*B1; то компилятор выдаст сообщение об ошибке.

 

int B2;

int&& a2 = 2*B2; //а2 это ссылка, которую можно инициализировать только rvalue объектом (т.е. временным объектом, который получится после выполнения операции 2*В2) при этом время жизни этого временного объекта продлевается до времени жизни ссылки. Если попытатся записать строчку кода int&& a2 = B2, то компилятором будет выдано сообщение об ошибке.

 

Возможность объявить ссылки вида type&& появилась в языке Си++ с принятием 11-го стандарта.

 

2.7. Первоначальные сведения о функциях языка Си++

До этого момента все приведённые выше программы содержали только одну функцию – main(). Как уже говорилось любая программа, написанная на языке Си++, должна обязательно содержать функцию main(), и эта функция должна быть в программе единственной, так как именно с выполнения операторов этой функции и начинается выполнение программы. Синтаксис определения любой функции, в том числе и функции main(), задаётся следующими правилами:

тип_функции имя_функции (список формальных параметров){

тело функции

}

где тип_функции – тип возвращаемого в точку вызова функцией значения; имя_функции – в общем случае определяется пользователем; список формальных параметров - список типов данных, передаваемых функции; тело функции – последовательность, заключённых в фигурные скобки, операторов, реализующих алгоритм работы программы на языке Си++. Совокупность

тип_функции имя_функции (список формальных параметров);

называют ещё сигнатурой функции.

Приведем пример определения функции, которая суммирует два числа:

int sum(int z, int g) {

int s = z+g;

return s;

}

где int – тип функции; sum – имя функции; (int z, int g) – список формальных параметров (в данном случае z - первый формальный параметр типа int, g – второй формальный параметр типа int); в фигурные скобки {} заключено тело функции (состоящее в данном случае из двух операторов); int sum(int z, int g) – сигнатура функции sum().

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

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

int sum(int z, int g) {

int s = z+g;

return s;

}

 

где имя_функции – имя вызываемой функции; список_фактических_параметров – список констант, переменных или выражений записанных через запятую. Если фактический параметр представлен выражением, то сначала вычисляется значение выражения, и только потом осуществляется вызов функции. Для примера несколько вызовов функции sum() можно записать следующим образом:

sum(2, 1); sum(3+5,3-7); sum(f+2, d); sum(2, 2*sum(3,5))

в первом вызове первый фактический параметр равен 2, второй – 1; во втором вызове два фактических параметра представлены выражениями, только после нахождения значений которых осуществляется вызов функции; в третьем вызове первый фактический параметр является выражением, в котором используется переменная f, значение которой должно было быть определено выше в теле программы до вызова функции, вторым фактическим параметром является значение переменной d.

Что же происходит при вызове функции? При вызове функции формальным параметрам присваивается значение фактических параметров в строгом соотве



Дата добавления: 2020-12-11; просмотров: 446;


Поиск по сайту:

Воспользовавшись поиском можно найти нужную информацию на сайте.

Поделитесь с друзьями:

Считаете данную информацию полезной, тогда расскажите друзьям в соц. сетях.
Poznayka.org - Познайка.Орг - 2016-2024 год. Материал предоставляется для ознакомительных и учебных целей.
Генерация страницы за: 0.09 сек.