Similar presentations:
Массивы и указатели
1.
Массивы и указателиУказатели
2.
УказателиУказатели
Когда компилятор обрабатывает оператор
объявления переменной, например, 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;
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
Значение через указатель = 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;
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;
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, его
необходимо преобразовать к указателю на
конкретный тип явным образом.
14.
УказателиПример указателя на тип void:
float fl = 3.14;
float *ptr_float = &fl;
int main()
{
void *ptr_void = ptr_float;
cout << *(float *)ptr_void << endl;
// *static_cast<float *>(ptr_void) << endl;
system("pause");
return 0;
}
15.
УказателиУказатель может быть константой или переменной, а
также указывать на константу или переменную:
const int *ptr_int;
// указатель на целую константу
Int *const int const_ptr_int;
// константный указатель на переменную целого типа
Величины типа указатель подчиняются общим
правилам определения области действия,
видимости и времени жизни.
16.
Указатели*Инициализация указателей
При объявлении указателя надо стремиться
выполнить его инициализацию, то есть
присвоить ему некоторое начальное значение.
Использование неинициализированного
указателя – распространенный источник
ошибок в программе. Инициализатор
записывается после имени указателя после
знака равенства или в круглых скобках.
17.
УказателиСуществуют следующие способы
инициализации указателей:
1. Присваивание указателю адреса
существующего объекта:
- с помощью операции получения адреса &
int var_int = 6338;
int *ptr_int = &var_int;
// или
int *ptr_int(&var_int);
18.
УказателиЕще один пример:
struct Test
{
int test_int;
char test_char;
double tetst_double;
} test={10, 'A', 4.78};
19.
Указатели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 = 3.55f;
float *ptr_float_1 = &var_float;
float *ptr_float_1 = ptr_float_2;
21.
Указатели- с помощью имени массива
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 (*ptr_fun)(int,char) = &func;
Знак операции взятия адреса & здесь также
не обязателен, так как имя функции
трактуется как адрес ячейки памяти,
начиная с которого находится объектный
код данной функции.
24.
Указатели2. Присваивание указателю адреса области
памяти в явном виде:
char *vp = (char *)0xB8000000;
int main()
{
cout << *vp << endl;
system("pause");
return 0;
}
// ???????
25.
Указатели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 заимствована из языка С, тем не
менее, она работает.
При работе с динамической областью памяти
необходимо следить за тем, чтобы указатель
не вышел за пределы области видимости. В
этом случае память отведенная под указатель
освобождается, указатель обнуляется, а
переменная становится недоступной.
28.
УказателиНа программистском сленге это означает
появление «мусора» в памяти.
Полезный совет при попытке выделения памяти
в динамической области. Проверяйте
значение указателя после выполнения
операции new или функции malloc на
равенство нулю. Если указатель нулевой, то
операционной системе не удалось найти
достаточного свободного объема памяти . Это
предотвратит последующие ошибки.
29.
Указатели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, -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<float *> (ptr_int);
Операции преобразования широко
используются при преобразовании в
иерархии родственных классов в условиях
наследования.
39.
УказателиОбычно операция преобразования используется
при выполнении операции присваивания.
Присваивание без явного преобразования
допускается если в левой части выражения
используется указатель на тип void или типы
указателей совпадают. Значение 0 неявно
приводится к указателю на любой тип.
Присваивание указателей на объекты
указателям на функции и наоборот не
допускается!
40.
Ссылки*Ссылки
Ссылка (ссылочный тип данных) – синоним
имени, указанного при инициализации
ссылки. Ссылку можно рассматривать как
указатель, который не надо
разыменовывать. Формат объявления
ссылки следующий:
тип_ссылки &имя_ссылки = инициализация;
41.
СсылкиПример объявления ссылки:
int var_int = 57;
int &ref_int = var_int;
const char &ref_char = ‘\n’;
Следует запомнить следующие правила определения и
использования ссылок:
- переменная-ссылка должна явно инициализироваться
при ее описании, кроме случаев, когда она является
параметром функции, описана как extern или ссылается
на поле данных класса;
42.
Ссылки- тип ссылки должен совпадать с типом
величины, на которую она ссылается;
- не разрешается определять указатели на
ссылки, создавать массивы ссылок и ссылки
на ссылки.
Ссылки применяются чаще всего в качестве
параметров функций и типов
возвращаемых функциями результатов.
43.
СсылкиСсылки позволяют использовать в функциях
переменные, передаваемые по адресу, без
операции разыменования, что упрощает
процесс программирования.
Ссылки, в отличие от указателей не занимают
место в памяти и являются по сути другим
именем объекта. Операции над ссылкой
приводит к изменению величины, на
которую она ссылается.