Похожие презентации:
04 Указатели и динамические массивы
1. Основы программирования
Указатели и динамическиемассивы
1
2. Описание и создание переменных
Данные, которые обрабатывает программа, находятся впамяти компьютера. Описание любой переменной
подразумевает выполнение несколько операций:
• объявление – задание имени и типа объекта
• определение
памяти)
–
создание
переменной
(выделение
• инициализация (не во всех случаях!) – присвоение
начального значения переменной.
2
3. Описание и создание переменных
Простое описание числовых переменных:int k; double x;
После создания глобальные переменные по умолчанию
инициализируются нулем, а для остальных содержимое
выделенной памяти не изменяется.
Явная инициализация при описании:
int k = 4; double x = 3.1415;
Раздельное описание и присвоение начального значения:
int k; double x;
k = 4; x = 3.1415; или cin >> k >> x;
3
4. Описание и создание переменных
Любая переменная занимает определенное ее типомколичество байт, начиная с некоторого адреса. Имя
переменной – это, фактически, скрытая ссылка на
область памяти, где хранится значение переменной.
Но в С/С++ также существует и очень широко
используется
возможность
доступа
к
объектами
непосредственно через их адреса. Реализовать это
позволяют указатели – переменные и константы.
4
5. Указатели
Указатель – это переменная (или константа), значениемкоторой является адрес области памяти, выделенной для
переменной или значения определенного типа.
Общий формат описания переменной-указателя:
тип *имя_переменной;
5
6. Указатели
Пример:int *pa; double *px;
pa будет хранить адрес переменной/значения типа int
px – адрес переменной/значения типа double.
pa и px будет выделена память, необходимая для
хранения адреса в памяти (4 или 8 байт), но реальные
адреса по умолчанию не задаются.
Значения переменным-указателям нужно присваивать
явно!
6
7. Операции с указателями
Взятие адреса – унарный префиксный & – извлечениеадреса переменной (константы хранятся в памяти, но
их адреса недоступны в программе):
int a = 2, b, *pa;
double y, x = 3.1415, *px;
pa = &a; px = &x;
Разыменование – унарная префиксная * – ссылка на
объект, на который указывает указатель:
y = *px; b = (3 + *pa) * 10;
cin >> *pa; cout << *px;
*pa *= 5; *px = y * 0.01;
7
8. Арифметические операции
К указателям можно применять только целочисленноесложение или вычитание.
При увеличении (уменьшении) указателя на 1
происходит переход не к следующему (предыдущему)
байту, а к следующему (предыдущему) элементу
заданного типа.
8
9. Арифметические операции
Примеры:int *pa, a = 2; double x = 3.1415, *px;
pa = &a; px = &x;
px++;
// px указывает на следующий за x в памяти
// элемент double (px увеличивается на 8)
*(pa+5) = 7;
// 5-му после a в памяти элементу int
// (на расстоянии 5*4 байт от a) присваивается
// значение 7, значение pa не изменяется
9
10. Операторы для работы с памятью
Память для явно описанных переменных и статическихмассивов выделяется автоматически при сборке или
выполнении программы.
В С++ также существует возможность динамического
выделения и освобождения памяти в процессе работы
программы. Доступ к этой памяти осуществляется с
помощью указателей.
Непосредственно выделением и освобождением
памяти занимается операционная система компьютера,
к
которой
программа
обращается
через
соответствующие операторы.
10
11. Операторы для работы с памятью
Динамическое выделение памяти:указатель = new тип;
/* выделяется память, необходимая для размещения
переменной заданного типа, адрес начального байта
присваивается указателю */
Освобождение памяти:
delete указатель;
/* освобождается память, выделенная оператором new
для указателя*/
11
12. Операторы для работы с памятью
Примеры:int *pa;
double *px;
pa = new int;
px = new double;
cin >> *pa;
*px = 3.1415;
cout << *pa * *pa;
*pa = (int)*px;
delete px;
delete pa;
12
13. Статические и динамические массивы
Если в программе описывается статический массив,например :
int arr[50];
то происходит не только выделение памяти для 50
элементов int, но и создается указатель-константа
arr, хранящий адрес начального байта выделенной
памяти (arr – константа, поэтому размер и положение
массива в памяти изменить нельзя).
13
14. Статические и динамические массивы
Если размер массива заранее не известен, то удобноиспользовать динамический массив, выделяя для него
реально необходимую память и освобождая ее, когда
потребуется.
Динамическое выделение памяти для массива:
указатель = new тип[длина]; - выделяется
память, необходимая для длина элементов типа,
адрес начального байта присваивается указателю.
длина - это любое целочисленное выражение,
константа или переменная.
14
15. Статические и динамические массивы
Освобождение памяти, занятой массивом:delete [] указатель; - освобождается память,
выделенная оператором new для массива.
Освобождение
неиспользуемой
динамически
выделенной
памяти
–
это
хороший
тон
в
программировании на С/С++.
Если память выделяется, а значение указателя на нее
теряется, то происходит «утечка памяти» - память
занята, но доступа к ней нет. Такие потерянные участки
освобождаются автоматически только при завершении
работы программы.
15
16. Обращение к элементам массивов
Пусть созданы 2 массива - статический и динамический:int arr[50]; double *mas = new double [100];
arr и mas – это указатели по типу и имена массивов по
сути, поэтому к элементам массивов можно обращаться
либо задавая индекс в квадратных скобках, либо
используя операции с указателями:
mas[0] эквивалентно *mas
arr[i] эквивалентно *(arr+i)
mas[j] эквивалентно *(mas+j)
arr+i – адрес i-го элемента arr
mas+j – адрес j-го элемента mas
16
17. Пример динамического массива
В следующем примере определяется длина n и выделяетсяпамять для динамического вещественного массива arr.
Затем массив заполняется случайными числами в диапазоне
[0.0, 1.0]. Далее массив выводится на экран, при этом
используются не индексы, а изменяемый в цикле указатель
на текущий элемент массива ptr.
После вывода значений динамический массив удаляется
(освобождается выделенная для него память). При этом сама
переменная-указатель arr все еще существует и ее можно
использовать повторно для создания другого одномерного
массива.
17
18. Пример динамического массива
int k, n; double *arr, *ptr;cout << “Input array length: ”;
cin >> n;
arr = new double[n];
srand(time(0));
for (k = 0; k < n; k++)
arr[k] = (double)(rand()) / RAND_MAX;
for (ptr = arr, k = 0; k < n; k++, ptr++)
cout << *ptr << endl;
delete [] arr;
18
19. Указатель на указатель
Переменная-указатель хранится в памяти, как и всепеременные других типов, т.е. имеет определенный
адрес. Для хранения адреса указателя нужно
использовать переменную типа указатель на указатель
(двойной указатель):
int x = 13, *px, **ppx;
Использование переменных:
px = &x;
// px получает адрес x
ppx = &px;
// ppx получает адрес px
*ppx
// px или ее значение
**ppx, *px
// x или ее значение 13
19
20. Двумерный массив и указатели
Одномерный статический массивint mas[50];
mas является константой-указателем на начальный
(нулевой) элемент массива.
Двумерный статический массив
int arr[10][20];
arr имеет специальный тип:
int (*)[20] – это указатель на целочисленный
массив длиной 20 (массив массивов).
arr не является указателем на указатель int **.
10 строк по 20 элементов располагаются в памяти
последовательно.
20
21. Двумерный массив и указатели
При создании двумерного динамического массива с nстроками и m столбцами необходимо явно выделить
память для:
• массива длины n указателей на строки
• n массивов длины m для элементов строк.
21
22. Двумерный массив и указатели
Адрес массива указателей на строки долженсохраняться в переменной типа указатель на указатель,
например, int **x. Адрес i-й строки должен
храниться на i-й позиции в массиве указателей на
строки, т.е. в элементе x[i].
Память для строк выделяется независимо, поэтому:
• строки будут располагаться в памяти произвольно (не
последовательно)
• длины строк, в принципе, могут быть разными (если
это необходимо).
23. Двумерный динамический массив
В следующем примере после описания переменныхсначала создается динамический массив указателей на
строки (n элементов типа int*).
Затем в цикле n раз выделяется память для всех строк
длины m и формируются значения указателей на строки.
После заполнения массива случайными значениями
производится удаление динамического массива с
освобождением всей выделенной памяти: сначала
удаляются строки, а затем массив указателей на строки.
После этого сама переменная x (указатель на указатель)
все еще существует и ее можно использовать повторно для
создания другого двумерного массива.
23
24. Двумерный динамический массив
int n, m, **x, i, j;cin >> n >> m;
x = new int* [n];
// массив указателей
for (i = 0; i < n; i++)
x[i] = new int [m];
// массивы целых
for (i = 0; i < n; i++)
for (j = 0; j < m; j++)
x[i][j] = rand();
for (i = 0; i < n; i++)
delete [] x[i];
delete [] x;
24
25. Матрица в виде одномерного массива
В некоторых случаях бывает удобно использоватьодномерный массив для представления матрицы.
Если матрица имеет n строк и m столбцов, то
соответствующий одномерный массив будет содержать
n*m элементов. Если считать, что эти элементы
располагаются в памяти последовательно «по строкам»
(m значений строки 0, затем m значений строки 1 и т.д.),
то элементу a[i][j] матрицы соответствует элемент
a[i*m+j] одномерного массива.
25
26. Матрица в виде одномерного массива
Реализация предыдущего примера с использованиемодномерного динамического массива x.
int n, m, *x, i, j;
cin >> n >> m;
x = new int [n*m];
// массив целых
for (i = 0; i < n; i++)
for (j = 0; j < m; j++)
x[i*m+j] = rand();
delete [] x;
26
27. Символы и строки в С
Символьные переменные и константы С имеют типchar, занимают 1 байт памяти и хранят целое число –
код символа (номер символа в таблице кодировки).
Константы заключаются в одинарные кавычки:
char a, b = ’b’, c = ’4’, *d;
Для
управляющих
и
специальных
символов
используются константы с обратным слэшем:
’\n’ – новая строка
’\’’ – одинарная кавычка
’\”’ – двойная кавычка
’\\’ – обратный слэш
’\xN’ – символ с 16-ричным кодом N
’\0’ – символ с кодом 0 (конец строки)
27
28. Символы и строки в С
При обработке текстов удобно использовать не простомассивы символов (статические или динамические), а
строки – последовательности символов, которые
заканчиваются символом с кодом 0: ’\0’ (этот символ
не учитывается при определении длины строки).
Для работы со строкой как единым объектом имеются
стандартные функции, все они используют нуль-символ
в качестве ограничителя. При использовании этих
функций в программу нужно включить заголовочный
файл cstring (string.h).
28
29. Символы и строки в С
Строковые константы заключаются в двойные кавычки:“word", “too many words", "1 2 3 4 5“.
Нуль-символ автоматически добавляется в конец
строковых констант. Например, “too many words"
содержит 15 символов, хотя ее длина равна 14.
Строковая константа
указатель на char.
трактуется
как
константа-
29
30. Символы и строки в С
Примеры:char stat[20], *dptr, *cptr;
cptr = “too many words“;
// изменение указателя
strcpy_s(stat, 15, “too many words“);
cout << “leng = ” << strlen(stat);
int k = strlen(stat) + 1;
dptr = new char [k];
strcpy_s(dptr,
k, stat);
30
31. Строки в С++
С++ сохраняет все возможности С для работы состроками с нуль-символом в конце.
Кроме того, в библиотеку стандартных шаблонов С++
(STL) включен специальный тип данных string. Он
предоставляет множество операторов и функций для
более простой и удобной работы с текстами.
31
32. Области памяти для переменных
Перед запуском программы ей выделяется память,которая включает 4 основные области:
1. Область кода – собственно программа
2. Область данных (data) – глобальные и staticпеременные
3. Стек (stack) – локальные переменные всех блоков,
параметры функций
4. Куча (heap) – область динамически выделяемой
памяти
33. Области видимости переменных
Любая переменная С/С++ имеет свою областьвидимости, т.е. часть программы, в которой эту
переменную можно использовать.
Область видимости зависит от того, где была описана
(определена) переменная.
Здесь действуют следующие правила:
34. Области видимости переменных
• глобальные переменные (описанные вне функций)видны в любом месте программы и существуют, пока
программа не закончит свою работу
• глобальные переменные с модификатором static видны
везде в том файле, где они описаны (программа на С++
может состоять из нескольких файлов), и существуют,
пока не закончится программа
35. Области видимости переменных
• переменные, описанные внутри любого блока {…}(составного оператора, тела функции), а также
параметры функции, создаются при выполнении
данного блока, видны только в нем и удаляются при
выходе из блока
• переменные, описанные внутри блока с модификатором
static, существуют, пока выполняется программа, но
видны только внутри своего блока
36. Области видимости переменных
• переменные, описанные внутри оператора цикласоздаются и видны только в цикле, и удаляются при
завершении цикла
• если в блоке или цикле создается новая переменная с
таким же именем, как некоторая ранее определенная
старая, то новая «перекрывает» старую, т.е. старая
(даже глобальная) не будет видна, пока существует
новая.
37. Области видимости переменных
int a = 100;double func(int d, int t)
{ float k; k = a / d + t; return k; }
void main()
{
float a = 3.1415; double *pm;
int d = 123, tt = 456, k = 0;
pm = new double[2];
for (int a = 0; a < 5; a++) k +=a;
pm[0] = k + a;
pm[1] = func(d, tt);
}
Программирование