- •Ю.Е. Алексеев, а.В. Куров
- •Часть 4
- •Алексеев Юрий Евтихович Куров Андрей Владимирович
- •8. Символьный тип данных
- •8.1 Общие сведения и библиотечные функции
- •8.2 Примеры программ обработки символьных данных
- •8.3 Задания на обработку символьных матриц
- •9. Строки
- •9.1 Общие сведения и библиотечные функции
- •9.2 Примеры программ обработки строк (массивова символов)
- •9.3 Задания на обработку строк
- •10. Типы данных структура и объединение
- •10.1 Общие сведения о структурах
- •10.2 Примеры программ обработки структур
- •10.3 Задания на обработку структур
- •10.4 Объединения
- •10.5 Примеры программ обработки объединений
- •11. Файлы
- •11.1 Основные сведения о файлах
- •11.2 Библиотечные функции для работы с файлами
- •11.3 Примеры программ обработки текстовых файлов
- •11.4 Задания на обработку текстовых файлов.
- •11.5 Примеры программ обработки бинарных файлов
- •11.6 Задания на бинарные файлы.
- •12. Тип данных указатель
- •12.1 Общие сведения Объявления и присваивания
- •Операции с указателями
- •Приоритеты операций при работе с указателями.
- •Взаимосвязь массивов и указателей
- •12.2 Динамические переменные и массивы Динамические переменные
- •Динамические массивы
- •Двумерные динамические массивы
- •Доступ к элементам динамической матрицы
- •Библиотечные функции с для работы с динамическими переменными и массивами
- •Передача в функции динамических массивов
- •13 Динамические структуры данных
- •13.1 Списки Линейный список
- •Пример программы работы с однонаправленным списком
- •Пример программы работы с двунаправленным списком
- •13.2 Задания на обработку списков.
- •13.3 Деревья бинарные
- •Структура бинарного дерева
- •Примеры работ с бинарным деревом
- •Список литературы
- •Алфавитный указатель
- •Вопросы для самопроверки Символы
- •Структуры
- •Указатели
Двумерные динамические массивы
Двумерный динамический массив (матрицу) удобно рассматривать как одномерный массив, состоящий из одномерных массивов. Поэтому каждой строке матрицы (одномерному массиву) можно сопоставить указатель, хранящий адрес первого элемента очередной строки. Совокупность этих указателей образует одномерный массив указателей, этому массиву можно сопоставить указатель на массив указателей, т.е. указатель на указатель. В связи с этим при объявлении динамической матрицы следует объявить указатель на указатель:
<тип элементов массива> ** <идентификатор указателя>;
Идентификатор указателя является в данном случае указателем на массив указателей. После объявления указателя следует выделить память под матрицу, причем это делается в два этапа. Сначала надо выделить память для массива указателей. Подобный массив может быть объявлен следующим образом:
<тип элементов> *<идентификатор>[<количество строк матрицы>];
В этом объявлении используется правило: “суффикс крепче префикса”, т.е. данная конструкция воспринимается как массив указателей (а не указатель на массив). Память под массив указателей выделяется, как и ранее, операцией new:
<идентификатор> = new <тип элементов> *[ количество строк];
Например:
a=new float *[20];
n=new char *[30];
В первом случае выделяется память под массив указателей на тип float, состоящий из 20-ти элементов, адрес заносится в переменную-указатель a. Во втором случае выделяется память под массив указателей на тип char, состоящий из 30-ти элементов, адрес массива заносится в переменную-указатель n.
На втором этапе необходимо выделить память для хранения всех элементов каждой строки матрицы. Обычно это выполняют в цикле с помощью операции new, при этом очередному указателю (элементу массива) присваивается адрес первого элемента очередной строки матрицы. Здесь следует заметить, что количество элементов строк динамической матрицы может быть различным, поэтому можно работать с динамическими матрицами различной конфигурации. Доступ к элементам массива указателей при выделении памяти подстроки динамической матрицы можно выполнять несколькими способами: с помощью смещения от начала массива, с помощью индекса, с помощью текущего указателя. Приведем примеры использования каждого способа для первой матрицы:
1) использование смещения
for (int i=0; i<20;i++)
*(a+i)=new float[i+1];
2) использование индекса
for (int i=0; i<20;i++)
a[i]=new float[i+1];
3) использование вспомогательного текущего указателя:
float **p;
for (p=a; p<a+20;p++)
*p=new float[i+1];
Освобождение памяти , выделенной под динамическую матрицу, выполняется также в два этапа: сначала освобождается память, выделенная под каждую строку матрицы, а затем освобождается память, выделенная под массив указателей на каждую строку матрицы. В приведенном примере это может выглядеть следующим образом:
for (int i=0;i<20;i++)
delete [] a[i];
delete []a;
Пример программы 4. Далее приводится пример программы, в которой выполняется работа с динамической матрицей: выделяется память под динамическую матрицу и одномерный динамический массив, осуществляется ввод элементов матрицы, а затем вычисляется сумма элементов каждой строки матрицы и заносится в одномерный массив.
#include "stdafx.h"
#include "conio.h"
#include "D:\\temp\\RusString.h"
int _tmain(int argc, _TCHAR* argv[])
{
int m,n,i,j;
float **a, *b;
printRus("Введите количество строк и столбцов: ");
scanf("%d %d",&m,&n);
a=new float*[m];
for (i=0;i<m;i++)
a[i]=new float[n];
OutPuts("Введите элементы матрицы ");
for (i=0;i<m;i++)
for (j=0;j<n;j++)
scanf("%f",&a[i][j]);
OutPuts("Вывод матрицы ");
for (i=0;i<m;i++)
{
for (j=0;j<n;j++)
printf("%8.2f",a[i][j]);
printf("\n");
}
b=new float[m];
for (i=0;i<m;i++)
{
b[i]=0;
for (j=0;j<n;j++)
b[i]+=a[i][j];
}
OutPuts("Суммы элементов строк матрицы ");
for (i=0;i<m;i++)
printf("%6.2f\n",b[i]);
delete []b;
for (i=0;i<m;i++)
delete []a[i];
delete []a;
getch();
return 0;
}
Пример программы 5. В качестве второго примера приведем работу с динамической матрицей, имеющей треугольный вид. В приводимой программе вычисляется в каждой строке матрицы произведение элементов.
#include "stdafx.h"
#include "conio.h"
#include "D:\\temp\\RusString.h"
int _tmain(int argc, _TCHAR* argv[])
{
int m,i,j;
float **a, *b;
printRus("Введите количество строк: ");
scanf("%d",&m);
a=new float*[m];
for (i=0;i<m;i++)
a[i]=new float[i+1];
OutPuts("Введите элементы матрицы ");
for (i=0;i<m;i++)
for (j=0;j<i+1;j++)
scanf("%f",&a[i][j]);
OutPuts("Вывод матрицы ");
for (i=0;i<m;i++)
{
for (j=0;j<i+1;j++)
printf("%8.2f",a[i][j]);
printf("\n");
}
b=new float[m];
for (i=0;i<m;i++)
{
b[i]=1;
for (j=0;j<i+1;j++)
b[i]*=a[i][j];
}
OutPuts("Произведения элементов строк матрицы ");
for (i=0;i<m;i++)
printf("%6.2f\n",b[i]);
delete []b;
for (i=0;i<m;i++)
delete []a[i];
delete []a;
getch();
return 0;
В приведенных программах обращение к элементам динамических массивов производилось с помощью индексов. Можно использовать и другие способы адресации, одним из которых является использование смещения. Например, выделение памяти под каждую строку матрицы можно выполнить с использованием смещения следующим образом:
for (i=0;i<m;i++)
*(a+i)=new float[n];
Пример программы 6. В следующей программе для решения задачи, рассмотренной в примере программы 4, применим иной способ - использование дополнительного указателя:
float **p;
for (p=a;p<a+m;p++)
*p=new float[n];
Текст программы будет иметь в этом случае следующий вид:
#include "stdafx.h"
#include "conio.h"
#include "D:\\temp\\RusString.h"
int _tmain(int argc, _TCHAR* argv[])
{
int m,n,i,j;
float **a, *b,**p;
printRus("Введите количество строк и столбцов: ");
scanf("%d %d",&m,&n);
a=new float*[m];
for (p=a;p<a+m;p++)
*p=new float[n];
OutPuts("Введите элементы матрицы ");
for (i=0;i<m;i++)
for (j=0;j<n;j++)
scanf("%f",&a[i][j]);
OutPuts("Вывод матрицы ");
for (i=0;i<m;i++)
{
for (j=0;j<n;j++)
printf("%8.2f",a[i][j]);
printf("\n");
}
b=new float[m];
for (i=0;i<m;i++)
{
b[i]=0;
for (j=0;j<n;j++)
b[i]+=a[i][j];
}
OutPuts("Суммы элементов строк матрицы ");
for (i=0;i<m;i++)
printf("%6.2f\n",b[i]);
delete []b;
for (i=0;i<m;i++)
delete []a[i];
delete []a;
getch();
return 0;
}
