Константы 2 страница
Ссылка — представляет собой синоним имени, указанного при инициализации ссылки.
Ссылку можно рассматривать как указатель, который всегда разыменовывается (реадресация).
Объявление:
тип *имя [инициатор] ;
Пример:
int kol ;
int &pal= kol ; // ссылка pal — альтернатива имени kol
const char &cR = '\n' ; // ссылка на константу
Замечания (!):
1. Переменная ссылка должна явно инициализироваться при её объявлении, кроме случаев, когда она:
— является параметром функции;
— описана как extern;
— ссылается на поле данных класса.
2. После инициализации ссылке не может быть присвоена другая переменная.
3. Тип ссылки должен совпадать с типом величины, на которую она ссылается.
4. Не разрешается определять указатели на ссылки, создавать массивы ссылок и ссылки на ссылки.
Применяются ссылки чаще всего в качестве параметров функций и типов, возвращаемых функциями значений. Ссылки позволяют использовать в функциях переменные, передаваемые по адресу, без операции реадресации, что улучшает читаемость программы.
Ссылка, в отличие от указателя, не занимает дополнительного пространства в памяти и является просто другим именем величины. Операция над ссылкой приводит к изменению величины, на которую она ссылается. Ссылку можно рассматривать как указатель, который всегда разыменовывается (реадресуется).
3.5. Лекция 8. Массивы
При использовании простых переменных каждой области памяти соответствует своё имя.
Если с группой некоторых величин необходимо выполнять однообразные действия, то им дают одно имя, а различают по порядковому номеру. Это позволяет создавать компактный циклический программный код для обработки таких переменных.
Массивы — конечная именованная последовательность однотипных величин.
3.5.1. Одномерные массивы
Объявление массива в программе имеет следующие форматы (синие квадратные скобки показывают, что инициализации может и не быть):
тип имя_массива [размер_массива] [= {инициализаторы}];
или
тип имя_массива [ ] [= {инициализаторы}];
Пример:
float a[10] ; // объявление массива из 10-ти
// вещественных чисел
int i[256] ; // объявление массива из 256-ти целых чисел
unsigned short int d[]= // объявление и инициализация
={15,255,120,0,1}; // массива из 5-ти целых чисел
Примечание (!):
1. Элементы массива нумеруются с нуля.
2. При объявлении массива используются те же модификаторы, что и при объявлении простых переменных.
3. Элементами массива не могут быть функции и элементы типа void.
4. Инициализирующие значения массива записываются в {}. Значения элементам присваиваются по порядку. Если элементов массива больше, чем инициализирующих значений, то элементы, для которых значения не указаны, обнуляются. Например:
int b[5]={3,2,1} ; // b[0]=3 ; b[1]=2 ; b[2]=1 ;
// b[3]=0 ; b[4]=0 .
int c[4]={1,2,3,4} ; // c[0]=1 ; c[1]=2 ; c[2]=3 ; c[3]=4 .
Для доступа к элементу массива указывается его имя и номер элемента в квадратных скобках, который называют индексом, например b[4] (b — имя, 4 — индекс).
Пример:
…
int main()
{
const int N=10 ; //количество эл-тов массива
int i, sum ;
int a[N]={3,4,5,6,4,3,1} ; //объявление и инициализация
//массива
for (i=0, sum=0 ; i<N ; i++)
sum+=a[i] ;
/* запись sum+=a[i] эквивалентна sum=sum+a[i] */
cout << ''Сумма элементов: '' << sum ;
return 0 ;
}
Замечания:
— память под массив выделяется на этапе компиляции;
— размерность массива может быть задана только целой положительной константой или константным выражением;
— размерность массивов рекомендуется задавать с помощью именованных констант (см. пример выше);
— (!) при обращении к элементам массива автоматический контроль выхода индекса за границу массива не производится, что может привести к ошибкам.
3.5.2. Многомерные массивы
Многомерные массивы объявляются указанием каждого измерения в отдельных квадратных скобках (квадратные скобки синего цвета показывают, что инициализации массива может и не быть):
тип имя [индекс_1][индекс_2]…[индекс_N] [={инициализаторы}];
Двумерный массив имеет следующий формат объявления:
тип имя [индекс_строк][индекс_столбцов] [={инициализаторы}];
Пример:
Здесь объявляется массив из 5-ти строк и 4-х столбцов.
При инициализации многомерного массива он представляется либо как массив из массивов, либо задаётся общий список элементов в том порядке, в котором они располагаются в памяти.
Пример:
int matr[][] = { {1, 2} , {3, 4} , {5, 6} } ;
или
int matr[3][2] = {1, 2, 3, 4, 5, 6} ;
В памяти такой массив располагается построчно последовательно.
Многомерные массивы размещаются в памяти так, что при переходе к следующему элементу массива быстрее всего изменяется последний индекс.
Например, в выше приведенном примере инициализируется двумерный массив
,
который в памяти размещается следующим образом, как показано на рис. 3.2:
Рисунок 3.2 — Схема размещения двумерного массива
Для доступа к элементу многомерного массива следует указывать все его индексы.
Пример:
matr[i][j] ;
*(matr[i]+j) //или:
*(*(matr+i)+j)
3.5.3. Динамические массивы
3.5.3.1. Одномерные динамические массивы
Динамические массивы создают с помощью операции new (С++) или malloc (С).
Формат создания динамического массива с помощью операции new:
тип *имя = new тип [размер массива] ;
Пример:
int n=100 ; // количество элементов массива
float *p=new float[n] ; // объявление динамического массива
… // из n элементов с плавающей запятой
delete []p ; // освобождение памяти
Обращение к элементам динамического массива производится либо по индексу, либо через указатель.
Пример:
float a, b ;
a = p[5] ; // обращение к 5-му элементу массива
// с помощью индекса
b = *(p+5) ; // обращение к 5-му элементу массива
// через указатель
Формат создания динамического массива с помощью операции malloc:
тип *имя =
(приведение_типа *) malloc (размер_массива * размер_типа) ;
Пример:
int n = 100; //количество элементов массива
float *p = (float *) malloc(n*sizeof(float));
//объявление динамического массива
… //из n элементов с плавающей запятой
free(p); //освобождение памяти
Примечание:
1. Преобразование типа обязательно, поскольку функция malloc возвращает значение указателя типа void*.
2. Размер типа определять с помощью функции sizeof() необходимо, так как в некоторых случаях на некоторых ПК размер может отличаться от ожидаемого.
3.5.3.2. Динамический многомерный массив
Для создания динамического многомерного массива необходимо указать в операции new все его размерности.
Пример:
int N_str=5 ; //количество строк
int **m=(int**) new int [N_str][10] ; //объявление двумерного
//динамического массива
Более безопасный и универсальный способ создания массива, когда размерности задаются на этапе выполнения, показан на следующем примере:
int N_str, N_stb ; //1
cout<<''Введите количество строк и столбцов: '' ;
cin>>N_str>>N_stb ; //2
int **a=new int *[N_str] ; //3
for ( int i=0 ; i<N_str ; i++) //4
{
a[i]=new int[N_stb] ; //5
}
… /* Инициализация массива и обработка данных*/
delete []a; //6
В примере:
//1 — объявляется двух переменных — количества строк и столбцов;
//2 — ввод с клавиатуры количества строк и столбцов;
//3 — объявление указателя на массив указателей на int;
//4 — цикл для выделения памяти под каждую строку;
//5 — каждому элементу массива указателей на строки присваивается адрес начала участка памяти, выделенного под строку, как показано на рис. 3.3;
//6 — освобождение памяти из-под массива.
Рисунок 3.3 — Задание динамического многомерного массива
На рис. 3.3 отображены два этапа объявления и выделения памяти под двумерный массив:
— этап 1: объявляется указатель на массив указателей на int и выделяется память под массив указателей;
— этап 2: в цикле выделяется память под каждую строку массива, каждому элементу массива указателей на строки присваивается адрес начала участка памяти, выделенного под строку.
3.5.4. Символьные массивы (строки)
Строка представляет собой массив символов, заканчивающийся нуль-символом ‘\0’.
Замечание.
По положению нуль-символа определяется длина строки, т.е. длина символьного массива.
Форматы объявления символьного массива:
char имя_массива [размер_массива] [= “ инициализатор ”] ;
char имя_массива [ ] = “ инициализатор ” ;
Примеры:
1. Объявление символьного массива заданной длины и инициализация строковым литералом:
char str[20] = ''University''; // объявление массива из 20 элементов
// с номерами от 0 до 19
Здесь под массив выделено 20 байт; символы массива записались в первые 11 байт, остальные ячейки памяти содержат нулевые значения:
2. Объявление символьного массива и инициализация строковым литералом без указания количества элементов массива:
char str[]= ''University''; // под массив выделено 11 Байт.
3. Запись следующего вида
char *str= ''University'';
создает указатель на строковую константу, а не символьный массив и не строковую переменную.
Примечание:
Указатель на константу удалить нельзя.
3.6. Лекция 9. Выражения и присваивания
Выражение — комбинация знаков операций и операндов, результатом которой является определённое значение.
Операнд — константа, литера, идентификатор, функция и т.д.
3.6.1. Операции инкремента и декремента (увеличения и уменьшения на 1)
Знак операции инкремента — ++ ,
знак операции декремента — – – .
Существует две формы записи этих операций:
— префиксная (++x, – –x), при которой вначале изменяется операнд, а затем его значение становится результатом выражения;
— постфиксная (x– –, x++), при которой значением выражения вначале является операнд (его исходное значение), после чего он изменяется.
Пример:
include <stdio.h>
int main()
{
int x=3, y=3;
printf(“Значение префиксного выражения ++x : %d\n”, ++x);
printf(“Значение постфиксного выражения y++ : %d\n”, y++);
printf(“Значение x после приращения : %d\n”, x);
printf(“Значение y после приращения : %d\n”, y);
return 0;
}
Результат выполнения программы:
Значение префиксного выражения ++x : 4
Значение постфиксного выражения y++ : 3
Значение x после приращения : 4
Значение y после приращения : 4.
3.6.2. Операция определения размера типа
Операция sizeof — предназначена для вычисления размера объекта или типа в байтах.
Существует две формы записи:
sizeof выражение ;
sizeof (тип) ;
Пример:
#include <iomanip.h>
int main()
{
float x =1 ;
cout<<“Размер типа: ”<< sizeof( float ) << endl; //1
cout<<“Размер выражения 1: ”<< sizeof x << endl; //2
cout<<“Размер выражения 2: ”<< sizeof (x+0.1) << endl; //3
return 0;
}
Результат выполнения примера:
Размер типа: 4
Размер выражения 1: 4
Размер выражения2: 8
Результат выполнения строки //3 отличается от результатов выполнения строк //1 и //2 так как по умолчанию ‘0.1’ имеет тип double и результат суммирования также по умолчанию имеет тип double, поэтому при сложении этой величины с переменной x происходит автоматическое преобразование типа переменной x и результата суммирования к типу double.
3.6.3. Операции отрицания ( – , ! , ~ )
Операция – — операция арифметического отрицания. Операция изменяет знак числа на противоположный.
Пример:
float x = 7 , y;
y = –x ; //в результате получаем y = –7 .
Операция ! — операция логического отрицания. Если операнд имеет значение ''Истинна'' (1), то применение операции ! даст результат — ''Ложь'' (0), и наоборот, если операнд ''Ложь'' (0), то операция дает результат ''Истинна'' (1).
Пример:
bool a = true, b=false, x, y;
x = !a ; // Получаем: x = 0, т.е false .
y = !b ; // Получаем: y = 1, т.е true .
Операция ~ — операция поразрядного (побитового) отрицания. Операция инвертирует каждый разряд (бит) числа.
Пример:
int x=110, y;
y= ~x ; // Получаем: y=145
Результат выполнения: y=~11010=14510=100100012
Рисунок 3.4 — К объяснению операции поразрядного отрицания
3.6.4. Операции деления ( / ) и нахождения остатка от деления ( % )
Операция / — операция деления, позволяет разделить один операнд на другой.
Операция % — операция получения остатка от деления позволяет определить отстаток от деления одного операнда на другой.
Пример:
int x=11, y=4 ;
float z=4 ;
cout<< x/y << x/z << x%y ;
Результат: 2 2.750000 3
Примечания:
При выполнении операции деления
y= a / b ;
если ''a'' и ''b'' — целые, то ''y'' округляется до целого, в противном случае тип результата определяется самым длинным типом из ''a'' и ''b''.
Операция «остаток от деления» применяется только к целочисленным типам.
3.6.5. Операции сдвига ( << >> )
Операция << — операция сдвига влево.
Операция >> — операция сдвига вправо.
Операции применяют к целочисленным операндам. Сдвигают влево или вправо двоичное представление операнда на количество двоичных разрядов (бит), заданное вторым операндом:
y=a<<b ;
z=c>>d ; .
Пример:
cout<< (2<<1) << (2<<2) << (2<<3) <<endl;
cout<< (64<<1) << (64<<2) << (64<<3) <<endl;
Исходное значение — 2 (000000102) ,
Результат : 4 (000001002) 8 (000010002) 16 (000100002)
Исходное значение — 64 (010000002) .
32 (001000002) 16 (000100002) 8 (000010002)
Примечание:
— операция сдвига влево на N бит эквивалентна умножению операнда на ;
— операция сдвига вправо на N бит эквивалентна делению операнда на ;
— при сдвиге двоичного представления операнда влево старшие биты выбрасываются, а младшие биты заполняются нулями;
— при сдвиге двоичного представления операнда вправо старшие биты заполняются нулями, а младшие биты выбрасываются;
— операция сдвига применяют к целочисленным типам.
3.6.6. Операции отношения ( < , <= , > , >=, == , != )
Операция < — операция меньше.
Операция <= — операция меньше или равно.
Операция > — операция больше.
Операция >= — операция больше или равно.
Операция == — операция равно.
Операция != — операция не равно.
Приоритет операций:
Операнды могут быть любых типов или указателями. Результатом выполнения операций всегда является либо ''Истина'' (1) либо ''Ложь'' (0) (тип bool).
Примечание! Операции == и = различаются, и их не следует путать. |
При необходимости можно использовать скобки.
3.6.7. Поразрядные операции
Операция & — операция поразрядного И (конъюнкция), которая сравнивает операнды побитно.
Результат равен 1, только в том случае, если оба бита равны ‘1’, в остальных случаях результат равен '0'.
Пример:
cout<< (6&5) ; // Результат — 4
Рис. 3.5 — К объяснению операции поразрядного И
Операция | — операция поразрядного ИЛИ (дизъюнкция) сравнивает операнды побитно: результат равен '1' если хоть один из двух сравниваемых битов равен ‘1’, результат равен ‘0’ только если оба сравниваемых бита равны '0'.
Пример:
cout<< (6|5) ; // Результат — 7
Рис. 3.6 — К объяснению операции поразрядного ИЛИ
Операция ^ — операция поразрядного исключающее ИЛИ сравнивает операнды побитно: результат равен '1' только если один из двух сравниваемых битов равен '1', в противном случае результат равен '0'.
Пример:
cout<< (6^5) ; // Результат — 3
Рис. 3.7 — К объяснению операции поразрядного «Исключающее ИЛИ»
Таблица 3.7 — Таблица истинности поразрядных операций
a | b | & | | | ^ |
3.6.8. Логические операции
Операция && — операция логического И.
Операция || — операция логического ИЛИ.
Пример:
a&&b ;
a||b ;
Результаты выполнения логических операций подчиняются таблице истинности логических операций (см. табл. 3.8).
Таблица 3.8 — Таблица истинности логических операций
a | b | && | || |
Примечание:
Операнды этих операций могут иметь арифметический тип или быть указателями.
Операнды в каждой операции могут быть различных типов. Результат всегда имеет тип bool.
При выполнении логических операций преобразование типов не производится.
При выполнении логических операций операнд, равный нулю, воспринимается как “false”, а операнд, отличающийся от нуля, воспринимается как “true”.
Пример:
…
if ((a<=b) && x)
y=a / x ;
else
{
if ((b>0) || (x!=a))
y = b * x ;
else
y = a / b ;
}
…
3.6.9. Операции присваивания
Операция = — простое присваивание.
Операции +=
–=
*=
/=
%= — сложное присваивание.
Примечание:
Операции присваивания могут использоваться как законченные операторы.
В одном выражении оператор присваивания может встречаться несколько раз. Вычисления в этом случае производятся справа налево. Порядок присвоения можно изменить с помощью скобок.
Пример:
a = b ; // переменной a присваивается значение b
a += 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 = c = d = e ; // d = e ; c = d ; b = c ; a = b ;
a= (b=c) * d ; // b = c; a = b * d ;
3.6.10. Условная операция
Формат записи:
Выражение_1 ? Выражение_2 : Выражение_3
Условная операция вначале обрабатывает Выражение_1, если результат выражения равен ‘true’ (т.е. отличается от «0»), то затем обрабатывается Выражение_2, в противном случае обрабатывается Выражение_3.
Примеры:
max = (b>a) ? b : a ;
i = (i<n) ? i+1 : 1 ;
3.6.11. Приоритеты выполнения операций
В языке С/С++ первыми выполняются операции с высшими приоритетами. Самый высший приоритет — 1. В табл. 3.9 перечислены существующие приоритеты операций.
Таблица 3.9 — Приоритеты выполнения операций
Приоритет | Операторы | Тип операции | Порядок выполнения |
() [] . –> | Выражение | Слева направо | |
! = ++ – – + – * & sizeof(тип) | Унарные | Слева направо | |
* / % | Мультипликативные | Слева направо | |
+ – | Аддитивные | ||
<< >> | Сдвиг | ||
< > <= >= | Отношение | ||
== != | Отношение | ||
& | Поразрядное И | ||
^ | Поразрядное исключающее ИЛИ | ||
| | Поразрядное ИЛИ | ||
&& | Логическое И | Слева направо | |
|| | Логическое ИЛИ | ||
? : | Условная | ||
= += –= *= /= %= &= ^= |= <<= >>= | Присваивание | Справа налево | |
, | Последовательное вычисление | Слева направо |
3.6.12. Преобразование типов
Преобразование типов либо задаётся в явном виде командами и операторами, либо производится в неявном виде при выполнении операций.
Если в выражении операнды имеют одинаковый тип, то результат операции будет иметь тот же тип.
Если в выражении операнды имеют различающиеся типы, то перед вычислениями производится преобразование типов по правилам, обеспечивающим преобразование более коротких типов в более длинные. Более длинный тип операндов задаёт тип результата.
Правила преобразования арифметических типов представляют собой следующую последовательность:
Любые операнды типа char, unsigned char или short преобразуются к типу int по правилам:
— char расширяется нулём или знаком в зависимости от умолчания для char ;
— unsigned char расширяется нулём;
— signed char расширяется знаком;
— short, unsigned short и enum при преобразовании не изменяются;
— затем любые два оператора становятся либо int, либо float, double или long double;
— если один из операндов имеет тип float, то другой преобразуется к float.
Примечание:
1. Если один из операндов имеет тип long double, то другой преобразуется к long double.
2. Если один из операторов имеет тип double, то другой преобразуется к double.
3. Если один из операторов имеет тип float, то другой преобразуется к float.
4. Если один из операндов имеет тип unsigned long, то другой преобразуется к unsigned long.
5. Если один из операндов имеет тип long, то другой преобразуется к типу long.
6. Если один из операндов имеет тип unsigned, то другой преобразуется к unsigned.
7. Иначе оба операнда должны иметь тип int.
3.7. Лекция 10. Операторы
Любое выражение, завершающееся точкой с запятой, рассматривается как оператор.
Примеры:
/* Оператор выражение: */
i++ ;
a = sin(b + c * 5) ;
func(x, y) ;
/* Пустой оператор: */
;
/* Составной оператор: */
if (x < y) { x = a + b ; y = (b – a) / 2 ; }
Пустой оператор состоит только из точек с запятой (;).
Составной оператор представляет собой несколько операторов и объявлений, заключенных в фигурные скобки.
3.7.1. Операторы ветвления
3.7.1.1. Условный оператор if
Формат записи (квадратные скобки показывают, что этих ветвей может и не быть):
if (выражение) [оператор_1]; [ else оператор_2 ; ]
Вначале вычисляется выражение, а затем, если выражение равно ‘true’ — выполняется оператор_1, если же выражение равно ‘false’ — оператор_2.
Один из операторов может отсутствовать, обычно отсутствует второй оператор.
Обозначение оператора в алгоритмах. Блок-схема алгоритма части программы, соответствующей оператору if, может быть представлена как в полном виде, так и в сокращенном виде, когда второй оператор отсутствует, как показано на рис. 3.8.
Рисунок 3.8 — Блок-схемы алгоритма оператора if:
а) полная запись; б) сокращенная запись (отсутствует ветвь 'false’),
в) сокращенная запись (отсутствует ветвь ‘true’)
Примеры:
if (a<0) b=1; //1
if (a<b && (a>d || a==0)) //2
b++ ;
else
{
b*=a;
a=0;
}
if (a++) b++ ; //3
if (a– –) ; b– – ; //4
В примере:
— //1 показан сокращенный оператор if с пропущенной ветвью 'false’,
— //2 — полный оператор if, в котором в ветви 'false’ записан составной оператор в фигурных скобках;
— //3 — сокращенный оператор if с пропущенной ветвью 'false’, в котором выражение в круглых скобках включает в себя также и постфиксный оператор ++; порядок действий здесь следующий: вначале вычисляется выражение (a), а затем проводится операция инкремента (++); если выражение (а) истинно, то выполняется оператор b++ (в итоге, после выполнения оператора if, производится увеличение значения переменной а на 1, в не зависимости от того, истинно ли выражение в круглых скобках);
— //4 — сокращенный оператор if с пропущенной ветвью 'true’ , в выражении которого (в круглых скобках) также записана постфиксная операция (– –).
Если какая либо переменная используется только внутри условного оператора, то рекомендуется объявлять её внутри скобок:
if (int t=fun(z)) a –=t ; else a+=t ;
3.7.1.2. Оператор switch
Оператор switch предназначен для разветвления процесса на несколько направлений.
Формат записи:
switch (выражение) {
case константное_выражение_1: [список_операторов_1] ;
case константное_выражение_2: [список_операторов_2] ;
…
case константное_выражение_n: [список_операторов_n] ;
[default : операторы] ;
}
Выполнение начинается с вычисления 'выражения’, а затем управление передается первому оператору из списка, помеченного константным выражением, значение которого совпало с вычисленным. После этого, если выход из переключателя не указан явно, последовательно выполняются все остальные ветви.
Дата добавления: 2015-10-21; просмотров: 753;