- •Лексемы
- •Идентификаторы
- •Константы
- •Операции
- •Знаки пунктуации
- •Основные типы данных.
- •Описание переменных
- •Оператор присваивания
- •Примеры программ
- •Форматированный ввод, вывод
- •Особенности ввода, вывода символов
- •Функции gets, puts, atoi, atol и atof
- •Занятие 2. Операторы выбора.
- •Выражения, операции
- •Логические операции
- •Условная операция
- •Условный оператор
- •Оператор перехода goto
- •Оператор выбора switch
- •Оператор цикла с предусловием (while)
- •Оператор цикла с постусловием (do - while)
- •Оператор цикла for
- •Примеры использования операторо цикла
- •Занятие 3. Указатели. Ссылки. Массивы. Работа со строками.
- •Указатели
- •Операции разыменования и взятия адреса
- •Инициализация указателей
- •Арифметические операции с указателями
- •Присваивание указателей
- •Сравнение указателей
- •Операция new
- •Операция delete
- •Примеры использования указателей
- •Одномерные массивы
- •Инициализация одномерных массивов
- •Примеры работы с одномерными массивами
- •Многомерные массивы
- •Занятие 4. Указатели и массивы.
- •Указатели и одномерные массивы
- •Размещение одномерных массивов в динамической памяти.
- •Массивы указателей
- •Занятие 5. Указатели и многомерные массивы.
- •Двухмерный массив и вспомогательный массив указателей
- •Список рекомендуемой литературы.
Массивы указателей
Так как указатель это переменная в которой хранится адрес ячейки памяти, то язык С++ позволяет объявить массив указателей:
тип *имя_массива[размер_массива];
Объявим массив указателей из 3 элементов на объекты типа int.
int *array [5];
В таком массиве указателей можно хранить адреса различных целочисленных переменных.
#include <stdio.h>
void main()
{
int *array[3];
int a = 10, b = 20, c = 30;
array[0] = &a;
array[1] = &b;
array[2] = &c;
for (int i = 0; i<3; i++)
printf("%p\n", array[i]);
}
Это не основное применение массивов указателей, которые удобно применять при работе с многомерными массивами.
Занятие 5. Указатели и многомерные массивы.
Теоретическая часть
Многомерные массивы хранятся в памяти так, что самый правый индекс массива изменяется первым. Тогда для двумерного массива int A[2][3]; порядок хранения элементов такой: A[0][0], A[0][1], A[0][2], A[1][0], A[1][1], A[1][2]. Если мы введем указатель int *pA = &AA[0][0], то *pA – элемент с индексами [0][0], *(pA+3) – элемент с индексами [1][0]. Приведенная ниже программа наглядно демонстрирует это.
#include <stdio.h>
void main( )
{
int *pA;
int AA[3][2];
pA = &AA[0][0];
printf("Dostup po indexu:\n");
for (int i = 0; i<3; i++)
{
for (int j = 0; j<2; j++)
{
AA[i][j] = i + j;
printf("%p-%d\t", &AA[i][j], AA[i][j]);
}
printf("\n");
}
printf("\nDostup s ispolzovaniem ukazatelya:\n");
for (i = 0; i<2*3; i++)
printf("%p-%d\n", pA+i, *(pA+i));
printf("\n");
}
Результат работы программы:
Dostup po indexu:
0012FF64-0 0012FF68-1
0012FF6C-1 0012FF70-2
0012FF74-2 0012FF78-3
Dostup s ispolzovaniem ukazatelya:
0012FF64-0
0012FF68-1
0012FF6C-1
0012FF70-2
0012FF74-2
0012FF78-3
Как видно из этого примера адреса элементов, полученные с помощью указания индексов, полностью совпадают с адресами элементов, полученных с помощью указателя. Обратите внимание, что адреса элементов отличаются друг от друга на 4 байта, ровно столько занимает переменная типа int.
Приведенный выше пример вполне работоспособен, однако, он обладает рядом недостатков. Например, используя указатель pA, сложно распределить двумерный массив в динамической памяти. Для таких целей (да и просто для работы с многомерными массивами) рекомендуется использовать массивы указателей. Рассмотрим этот момент подробнее.
Допустим в программе нужно хранить список из 3 фамилий. Каждая фамилия может быть произвольной длины, но не больше, допустим, 20 символов. Данное требование можно выполнить, объявив двумерный массив символов char spisok[3][20]; т.е. 3 фамилии, по 20 символов для каждой. Тогда всего будет выделено 1байт * 20 символов * 3 фамилии = 60 байт.
Эту же задачу можно решить другим способом, а именно, объявив массив указателей char *sp [3] = {"Иванов", "Сидоров", "Козликов"}; Всего в этом массиве будет 3 элемента и каждый из них является указателем типа char *, для этого будет выделено 3*sizeof(char *) = 12 байт. Кроме того, компилятор размещает в памяти 3 строковые константы "Иванов" (7 байт), "Сидоров" (8 байт), "Козликов" (9 байт), а их адреса становятся значениями элементов sp[0], sp[1], sp[2]. Т.е. всего выделяется 12+7+8+9 = 36 байт. Выигрыш по сравнению с первым случаем очевиден.