- •Лексемы
- •Идентификаторы
- •Константы
- •Операции
- •Знаки пунктуации
- •Основные типы данных.
- •Описание переменных
- •Оператор присваивания
- •Примеры программ
- •Форматированный ввод, вывод
- •Особенности ввода, вывода символов
- •Функции gets, puts, atoi, atol и atof
- •Занятие 2. Операторы выбора.
- •Выражения, операции
- •Логические операции
- •Условная операция
- •Условный оператор
- •Оператор перехода goto
- •Оператор выбора switch
- •Оператор цикла с предусловием (while)
- •Оператор цикла с постусловием (do - while)
- •Оператор цикла for
- •Примеры использования операторо цикла
- •Занятие 3. Указатели. Ссылки. Массивы. Работа со строками.
- •Указатели
- •Операции разыменования и взятия адреса
- •Инициализация указателей
- •Арифметические операции с указателями
- •Присваивание указателей
- •Сравнение указателей
- •Операция new
- •Операция delete
- •Примеры использования указателей
- •Одномерные массивы
- •Инициализация одномерных массивов
- •Примеры работы с одномерными массивами
- •Многомерные массивы
- •Занятие 4. Указатели и массивы.
- •Указатели и одномерные массивы
- •Размещение одномерных массивов в динамической памяти.
- •Массивы указателей
- •Занятие 5. Указатели и многомерные массивы.
- •Двухмерный массив и вспомогательный массив указателей
- •Список рекомендуемой литературы.
Двухмерный массив и вспомогательный массив указателей
Приведем пример работы с двумерным массивом (матрицей) с использованием вспомогательного массива указателей.
# include <stdio.h>
# include <stdlib.h>
# include <time.h>
# define N 3
# define M 2
void main()
{
float matr[N][M];
float *pmatr[N];
srand(time(NULL));
printf("Доступ с помощью индексации имени массива:\n");
for (int i = 0; i<N; i++)
{
for (int j = 0; j<M; j++)
{
matr[i][j] = float (rand())/RAND_MAX*10;
printf("%3.1f\t", matr[i][j]);
}
printf("\n");
}
printf("Доступ с использованием вспомогательного массива:\n");
for (i = 0; i<N; i++)
pmatr[i] = &matr[i][0];
for (i = 0; i<N; i++)
{
for (int j = 0; j<M; j++)
printf("%3.1f\t", *(*(pmatr+i)+j));
printf("\n");
}
}
Доступ с помощью индексации имени массива называется прямым, а с помощью указателей вспомогательного массива – косвенным. Также отметим, что введенный массив pmatr также можно индексировать, т.е. запись *(*(pmatr+i)+j)) эквивалентна записи pmatr[i][j].
Так как указатель это переменная, в которой хранится адрес другой переменной, то С++ разрешает ввести «указатель на указатель» - т.е. переменную в которой будет храниться адрес ячейки памяти, в которой записан адрес другой ячейки. Синтаксис объявления «указателя на указатель» следующий:
тип **имя_указателя;
Следующий пример демонстрирует, как получить доступ к переменной, используя двойное разъименовывание указателя.
# include <stdio.h>
void main()
{
int A = 5; //переменная А
int *pA; //указатель на переменную А
int **ppA; //указатель на указатель pA
pA = &A; //получаем адрес переменной А
ppA = &pA; //получаем адрес указателя pA
printf("A = %d\n", **ppA);// получаем значение переменной А
}
Аналогично можно ввести «указатель на указатель на указатель» и т.д. Применяются они при работе с многомерными массивами.
# include <stdio.h>
void main()
{
int a = 10, b = 20, c = 30; //набор переменных
int * pM[3]; //массив указателей
pM[0] = &a; //записываем
pM[1] = &b; //в массив
pM[2] = &c; //адреса переменных a, b, c
int **ppM; //указатель на массив указателей
ppM = pM; //вспоминаем, что имя массива – адрес его
//первого элемента
//печатаем адреса переменных a, b, c хранящиеся в массиве pM
//и значения этих переменных, полученные с помощью указателя ppM
for (int i = 0; i<3; i++)
printf("&pM[%d] - %p\t%d\n", i, &pM[i], *(*(ppM+i)));
}
Результат работы программы:
&pM[0] - 0012FF68 10
&pM[1] - 0012FF6C 20
&pM[2] - 0012FF70 30
Заметим, что выражение *(*(ppM+i)) можно заменить эквивалентным, но более простым для понимания ppM[i][0].
Теперь рассмотрим, как можно разместить целочисленную матрицу размером N на M в динамической памяти. Алгоритм действия следующий.
-
Объявляем указатель на массив указателей int **pMatr;.
-
Выделяем память для хранения N указателей на первые элементов в каждой строке pMatr = new int * [N];.
-
В цикле выделяем память для хранения строк матрицы. Фактически эти строки можно рассматривать как одномерные массивы из M элементов.
for (i = 0; i<N; i++)
pMatr[i] = new int[M]; //в строке М элементов
Рисунок 6.1 – Схема имитации двухмерного динамического массива с помощью массива указателей и набора одномерных массивов.
Приведем программу, которая запрашивает размер матрицы и размещает ее в динамической памяти.
# include <stdio.h>
# include <stdlib.h>
# include <time.h>
void main()
{
int i, j, N, M;
printf("N = ");
scanf("%d", &N);
printf("M = ");
scanf("%d", &M);
int **pMatr;
pMatr = new int * [N];
for (i = 0; i<N; i++)
pMatr[i] = new int[M];
srand(time(NULL));
for (i = 0; i<N; i++)
{
for (j = 0; j<M; j++)
{
*(*(pMatr+i)+j) = rand()%11;
printf("%d\t", pMatr[i][j]);
}
printf("\n");
}
}
Еще раз обратим внимание на эквивалентность записей *(*(pMatr+i)+j) и pMatr[i][j]. Каждый может пользоваться формой, которая ему больше понятна.