Массивы и указатели

Содержание

Слайд 2

Указатели Указатели Когда компилятор обрабатывает оператор объявления переменной, например, int var_int

Указатели

Указатели
Когда компилятор обрабатывает оператор объявления переменной, например, int var_int = 10;,

он выделяет память в соответствии с типом(int) и инициализирует его значением 10. Все обращения в программе к этой переменной по ее имени заменяется компилятором на адрес памяти, в которой хранится значение переменной.
Слайд 3

Указатели Программист в своей программе может сам определить свои собственные переменные

Указатели

Программист в своей программе может сам определить свои собственные переменные для

хранения адресов памяти. Такие переменные называются указателями.
В С++ различают три вида указателей:
указатель на объект;
указатель на функцию;
указатель на тип void.
Слайд 4

Указатели Эти указатели отличаются свойствами и набором допустимых действий (операций). Указатель

Указатели

Эти указатели отличаются свойствами и набором допустимых действий (операций). Указатель не

является самостоятельным типом, он всегда связан с другим конкретным типом.
Указатель на объект имеет следующий формат:
тип *имя_указателя [= инициализатор];
Слайд 5

Указатели Тип может быть любым (стандартный, пользовательский), кроме ссылки, причем, к

Указатели

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

моменту тип может быть только объявлен, но еще не определен.
Символ ‘*’ (звездочка) относится непосредственно к имени, поэтому при групповом объявлении указателей, символ нужно ставить перед каждым объектом, например,
double *ptr_d_1, var_double, *ptr_d_2;
Слайд 6

Указатели Рассмотрим пример: double var_double = 55.39566; double *ptr_double = &var_double;

Указатели

Рассмотрим пример:
double var_double = 55.39566;
double *ptr_double = &var_double;
int main()
{
setlocale(0,"RUS");
cout << "

Значение = " << var_double << endl;
cout << " Адрес переменной = " << ptr_double << endl;
cout << " Значение через указатель = " << *ptr_double << endl;
system("pause");
return 0;
}
Слайд 7

Указатели Ответ этой программы: Значение = 55.3957 Адрес = 00419000 Значение

Указатели

Ответ этой программы:
Значение = 55.3957
Адрес = 00419000
Значение через указатель = 57.3957
Величина

0041900016 является физическим адресом ячейки ОЗУ, по которому хранится переменная типа double. Несложно догадаться, что адрес – это положительное (неотрицательное) целое число в диапазоне от 0 до N.
При другом запуске программы адрес (результат программы) может быть другим.
Слайд 8

Указатели А сколько байт оперативной памяти будет занимать сам указатель? Выяснить

Указатели

А сколько байт оперативной памяти будет занимать сам указатель? Выяснить это

не сложно:
cout << " Кол-во байт под указатель = «
<< sizeof(ptr_double) << endl;
Результатом этого оператора будет число байт, выделяемых под указатель. Это количество представляет собой машинное слово ЭВМ. Таким образом вы можете программным способом выяснить разрядность своей машины.
Слайд 9

Указатели Память выделяемая под указатель зависит от разрядности машины. Указатель на

Указатели

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

синтаксису отличается от остальных указателей, общий формат которого следующий:
тип (*имя_указ)(список_параметров);
Например,
double (*ptr_func)(double, const int&);
Слайд 10

Указатели Рассмотрим пример: int max(int arg_1, int arg_2) { if(arg_1>arg_2)return arg_1;

Указатели

Рассмотрим пример:
int max(int arg_1, int arg_2)
{
if(arg_1>arg_2)return arg_1;
else return arg_2;
}
double max(double arg_1,

double arg_2)
{
if(arg_1>arg_2)return arg_1;
else return arg_2;
}
int (*ptr_fun_int)(int,int) = &max;
double (*ptr_fun_double)(double, double) = &max;
Слайд 11

Указатели int main() { int var_int_1 = 34, var_int_2 = 22;

Указатели

int main()
{
int var_int_1 = 34, var_int_2 = 22;
double var_double_1 = 1.23,

var_double_2 = -0.765;
cout << ptr_fun_int(var_int_1, var_int_2) << endl;
cout << ptr_fun_double(var_double_1, var_double_2) << endl;
system("pause");
return 0;
}
Слайд 12

Указатели Указатели на функции позволяют вызвать функцию не напрямую, а косвенно,

Указатели

Указатели на функции позволяют вызвать функцию не напрямую, а косвенно, что

повышает гибкость при использовании функций. В частности, можно создавать массивы указателей на функции и работать с ними как с элементами обычного массива.
Слайд 13

Указатели Указатель на тип void – отдельный указатель, используемый в тех

Указатели

Указатель на тип void – отдельный указатель, используемый в тех случаях,

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

Указатели Пример указателя на тип void: float fl = 3.14; float

Указатели

Пример указателя на тип void:
float fl = 3.14;
float *ptr_float = &fl;
int

main()
{
void *ptr_void = ptr_float;
cout << *(float *)ptr_void << endl;
// *static_cast(ptr_void) << endl;
system("pause");
return 0;
}
Слайд 15

Указатели Указатель может быть константой или переменной, а также указывать на

Указатели

Указатель может быть константой или переменной, а также указывать на константу

или переменную:
const int *ptr_int;
// указатель на целую константу
Int *const int const_ptr_int;
// константный указатель на переменную целого типа
Величины типа указатель подчиняются общим правилам определения области действия, видимости и времени жизни.
Слайд 16

Указатели *Инициализация указателей При объявлении указателя надо стремиться выполнить его инициализацию,

Указатели

*Инициализация указателей
При объявлении указателя надо стремиться выполнить его инициализацию, то есть

присвоить ему некоторое начальное значение. Использование неинициализированного указателя – распространенный источник ошибок в программе. Инициализатор записывается после имени указателя после знака равенства или в круглых скобках.
Слайд 17

Указатели Существуют следующие способы инициализации указателей: Присваивание указателю адреса существующего объекта:

Указатели

Существуют следующие способы инициализации указателей:
Присваивание указателю адреса существующего объекта:
- с помощью

операции получения адреса &
int var_int = 6338;
int *ptr_int = &var_int; // или
int *ptr_int(&var_int);
Слайд 18

Указатели Еще один пример: struct Test { int test_int; char test_char;

Указатели

Еще один пример:
struct Test
{
int test_int;
char test_char;
double tetst_double;
} test={10, 'A', 4.78};

Слайд 19

Указатели int main() { Test *ptr_Test = &test; cout test_int test_char tetst_double system("pause"); return 0; }

Указатели

int main()
{
Test *ptr_Test = &test;
cout << ptr_Test->test_int << ' '
<<

ptr_Test->test_char << ' '
<< ptr_Test-> tetst_double << endl;
system("pause");
return 0;
}
Слайд 20

Указатели - с помощью значения другого инициализированного указателя float var_float =

Указатели

- с помощью значения другого инициализированного указателя
float var_float = 3.55f;
float *ptr_float_1

= &var_float;
float *ptr_float_1 = ptr_float_2;
Слайд 21

Указатели - с помощью имени массива unsigned array_int[] = {33, 51,

Указатели

- с помощью имени массива
unsigned array_int[] = {33, 51, 78, 4,

15};
int main()
{
unsigned *ptr_array = &array_int; // & - не обязательно
cout << *(ptr_array + 3) << endl;
system("pause");
return 0;
}
Слайд 22

Указатели Известно, что имя массива является указателем на его первый элемент,

Указатели

Известно, что имя массива является указателем на его первый элемент, поэтому

следующие выражения эквивалентны:
cout << *ptr_array << endl;
cout << *array_int << endl;
В обоих случаях получим значение первого элемента массива.
Слайд 23

Указатели - с помощью имени функции void func(int,char){ // ……}; void

Указатели

- с помощью имени функции
void func(int,char){ // ……};
void (*ptr_fun)(int,char) = &func;
Знак

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

Указатели 2. Присваивание указателю адреса области памяти в явном виде: char

Указатели

2. Присваивание указателю адреса области памяти в явном виде:
char *vp =

(char *)0xB8000000;
int main()
{
cout << *vp << endl; // ???????
system("pause");
return 0;
}
Слайд 25

Указатели 3. Присваивание пустого указателя: short *ptr_short = NULL; long *ptr_long

Указатели

3. Присваивание пустого указателя:
short *ptr_short = NULL;
long *ptr_long = 0;
4. Выделение

участка динамической памяти:
- с помощью операции new:
int *p_i = new int;
Слайд 26

Указатели Здесь в динамической памяти выделяется место для хранения величины типа

Указатели

Здесь в динамической памяти выделяется место для хранения величины типа int.
int

*p_j = new int(100);
Здесь помимо выделение памяти, заносится значение 100.
int *p_array new int[10];
Здесь выделяется место в динамической области памяти для хранения массива целых чисел.
Слайд 27

Указатели - с помощью функции malloc: int *p_i = (int *)malloc(sizeof(int));

Указатели

- с помощью функции malloc:
int *p_i = (int *)malloc(sizeof(int));
Функция malloc заимствована

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

Указатели На программистском сленге это означает появление «мусора» в памяти. Полезный

Указатели

На программистском сленге это означает появление «мусора» в памяти.
Полезный совет при

попытке выделения памяти в динамической области. Проверяйте значение указателя после выполнения операции new или функции malloc на равенство нулю. Если указатель нулевой, то операционной системе не удалось найти достаточного свободного объема памяти . Это предотвратит последующие ошибки.
Слайд 29

Указатели int main() { float *ptr_float = new float(67.44f); if(!ptr_float) {

Указатели

int main()
{
float *ptr_float = new float(67.44f);
if(!ptr_float)
{
cout << " Недостаточно памяти "

<< endl;
exit(1);
}
else cout << " Ok " << endl;
system("pause");
return 0;
}
Слайд 30

Указатели Операции над указателями Как уже было сказано, указатели – переменные,

Указатели

Операции над указателями
Как уже было сказано, указатели – переменные, хранящие адреса

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

Указатели Определим основные операции допустимые над указателями: операция разадресация (разыменования), косвенное

Указатели

Определим основные операции допустимые над указателями:
операция разадресация (разыменования), косвенное обращение к

объекту (*);
присваивание;
сложение с константой;
вычитание константы;
инкремент (--);
декремент (++);
Слайд 32

Указатели сравнение; приведение типов. При работе с указателями очень часто используется

Указатели

сравнение;
приведение типов.
При работе с указателями очень часто используется операция получения (взятия)

адреса (&).
Основной операцией над указателями является операция разадресация или разыменования, которая предназначена для доступа к величине, на которую указывает указатель.
Слайд 33

Указатели Эта операция симметрична, то есть с ее помощью можно получить

Указатели

Эта операция симметрична, то есть с ее помощью можно получить значение

объекта или изменить его.
Рассмотрим пример:
int main()
{
typedef unsigned long int UINT;
//
UINT *ptr_UINT = new UINT(12L);
// объявление и инициализация указателя на объект UINT
cout << " Величина UINT " << *ptr_UINT << endl;
// получение значения по указателю
return 0;
}
Слайд 34

Указатели Эта операция применима только к указателям на объект какого-либо типа

Указатели

Эта операция применима только к указателям на объект какого-либо типа и

на тип void. К указателям на функцию она не имеет смысла.
Арифметические операции над указателями, в частности, сложение с константой, вычитание константы, инкремент, декремент допустимы, но не над всеми видами указателей.
Слайд 35

Указатели Например, при работе с массивами они допустимы, а с указателями

Указатели

Например, при работе с массивами они допустимы, а с указателями на

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

Указатели Рассмотрим пример использования арифметических операций: float array_float = {3.2, -44.6,

Указатели

Рассмотрим пример использования арифметических операций:
float array_float = {3.2, -44.6, -0.073, 12,

5.0};
// ….
float summa_array(float arr[])
{
float rez = 0;
for(int i =0; i<5; i++)
rez += *(arr+i); //сложение указателя с константой
return rez;
}
Слайд 37

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

Указатели

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

указателей. Преобразование указателей в С++ допускается двумя способами:
унаследованным от языка С. Общий формат оператора преобразования следующий:
(тип *) имя_указателя;, или
тип * (имя_указателя);.
Слайд 38

Указатели - в стиле языка С++, используя операции static_cast, dynamic_cast, reinterpret_cast,

Указатели

- в стиле языка С++, используя операции static_cast, dynamic_cast, reinterpret_cast, например,


static_cast (ptr_int);
Операции преобразования широко используются при преобразовании в иерархии родственных классов в условиях наследования.
Слайд 39

Указатели Обычно операция преобразования используется при выполнении операции присваивания. Присваивание без

Указатели

Обычно операция преобразования используется при выполнении операции присваивания. Присваивание без явного

преобразования допускается если в левой части выражения используется указатель на тип void или типы указателей совпадают. Значение 0 неявно приводится к указателю на любой тип.
Присваивание указателей на объекты указателям на функции и наоборот не допускается!
Слайд 40

Ссылки *Ссылки Ссылка (ссылочный тип данных) – синоним имени, указанного при

Ссылки

*Ссылки
Ссылка (ссылочный тип данных) – синоним имени, указанного при инициализации ссылки.

Ссылку можно рассматривать как указатель, который не надо разыменовывать. Формат объявления ссылки следующий:
тип_ссылки &имя_ссылки = инициализация;
Слайд 41

Ссылки Пример объявления ссылки: int var_int = 57; int &ref_int =

Ссылки

Пример объявления ссылки:
int var_int = 57;
int &ref_int = var_int;
const char &ref_char

= ‘\n’;
Следует запомнить следующие правила определения и использования ссылок:
- переменная-ссылка должна явно инициализироваться при ее описании, кроме случаев, когда она является параметром функции, описана как extern или ссылается на поле данных класса;
Слайд 42

Ссылки - тип ссылки должен совпадать с типом величины, на которую

Ссылки

- тип ссылки должен совпадать с типом величины, на которую она

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

Ссылки Ссылки позволяют использовать в функциях переменные, передаваемые по адресу, без

Ссылки

Ссылки позволяют использовать в функциях переменные, передаваемые по адресу, без операции

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

Массивы

Массивы

Слайд 45

Слайд 46

Слайд 47