Использование указателей при работе с массивами является мощным средством экономии памяти, ведь мы можем организовывать массивы в куче, когда это требуется программе, и отдавать память в переиспользование, когда массив перестает быть нам нужен.
Для работы с динамическими массивами требуется сначала объявить указатель требуемого типа данных, например,
double *uk_mas;
Затем где-нибудь в программе выделить память в куче для массива
uk_mas = new double[50];
После этого с массивом можно работать обычным образом, например,
for (int i = 0; i < 50; i++)
uk_mas[i] = rand()%100;
После работы с массивом следует освободить его память операцией
delete[] uk_mas;
Теперь можно снова использовать освобожденный объем памяти посредством повторного резервирования памяти. Если в операторе delete не указать квадратные скобки, то результат его работы окажется непредсказуемым.
Таким образом, время жизни динамического массива, как и любой динамической переменной, - с момента выделения памяти до момента ее освобождения. Область действия зависит от места описания указателя, через который производится работа с массивом. Область действия и время жизни указателей подчиняются общим правилам. Локальная переменная при выходе из блока, в котором она описана, теряется. Если эта переменная является указателем и в ней хранится адрес выделенной динамической памяти, то при выходе из блока эта память перестает быть доступной, однако не помечается как свободная, поэтому не может быть использована в дальнейшем. Это называется утечкой памяти и является распространенной ошибкой.
Если размер массива точно не определен или массив очень большой, то лучше использовать динамические массивы, объявленные с применением указателей.
Пример
Дан массив из 100 целочисленных элементов. Создать другой массив, содержащий только четные элементы исходного массива.
#include <iostream>
#include <iomanip>
#include <cstdlib>
const int M = 100;
int main ()
{ int mas[M];
int *ukm; // указатель на целое
int k = 0; // счетчик четных элементов
j = 0; // для нового массива
for (int i = 0; i < M; i++)
{ mas[i] = rand() % 100 – 50;
cout << setw(4) << mas[i];
if (mas[i] % 2 == 0)
k++;
}
cout << endl;
ukm = new int[k];
for (int i = 0; i < M; i++)
{ if (mas[i] % 2 == 0)
{ ukm[j] = mas[i];
cout << setw(4) << ukm[j]; // вывод значений нового массива
j = j + 1;
}
}
cout << endl;
return 0;
}
Указатели и матрицы
Мы знаем, что двумерный массив представляется в С++ как массив, состоящий из массивов. С матрицами можно успешно работать с помощью указателей.
int matr[4][2]; // массив [4×2]
int *uk_matr; // указатель на целый тип
В этом случае uk_matr = matr указывает на первый элемент первой строки: uk_matr == &matr[0][0], uk_matr + 1 – на matr[0][1] и так далее согласно расположению элементов массива в памяти, которое всегда однозначно (сначала запоминаются элементы первой строки, за ней – элементы второй строки и так далее).
ukmatr ukmatr + 1 ukmatr + 2
matr[0][0] | matr[0][1] | matr[1][0] | matr[1][1] | … |
matr
Тогда
uk_matr == &matr[0][0]
uk_matr + 1 == &matr[0][1]
uk_matr + 2 == &matr[1][0]
…
uk_matr +5 == &matr[2][1]
или
matr[0] == &matr[0][0]
matr[1] == &matr[1][0] и так далее.
Выделить память под матрицу в куче можно таким образом.
1) int *uk_ma = new int[row*col]; … delete[]uk_ma;
2) uk_ma = malloc(row*col*sizeof(int)); free(uk_ma);
Но тогда в куче будет выделен сплошной кусок памяти, что неэффективно для матриц больших размеров.
Чаще выделение памяти под матрицу выполняют иначе.
Пусть требуется создать двумерный динамический массив целых чисел размерностью n*m.
…
int m, n, i;
int **mas; // указатель на указатель типа int
…
cin << n; // число строк матрицы
cin << m; // число столбцов матрицы
mas = new int* [n]; // выделяется память под n указателей на строку
for (i = 0; i < n; i++)
mas[i] = new int[m]; // выделяется память для каждой строки
…
for (i = 0; i < n; i++)
delete [] mas[i]; // освобождение памяти
delete [] mas;
Для двумерного динамического массива в данном случае память не представляет собой сплошной участок, так как выделяется с помощью нескольких операций new.
Пример
Найти максимальный элемент каждого столбца в двумерном массиве и переписать эти значения в одномерный массив (всё в динамических массивах)
#include <iostream>
#include <ctime>
#include <iomanip>
#include <cstdlib>
using namespace std;
int main()
{
const int rows=5;
const int cols=5;
srand(time(0)); // перемешиваем базу случайных чисел
// создаем указатель на матрицу, указатель на одномерный массив и выделяем память
float **ptr2arr = new float *[cols];
float *ptrmax = new float[cols];
for (int count=0;count<rows; count++)
ptr2arr[count] = new float[cols];
// заполняем матрицу вещественными случайными числами
for (int count_row =0; count_row <rows; count_row++)
{
for (int count_col=0;count_col<cols;count_col++)
ptr2arr[count_row][count_col] = ((rand()%10+1) / float(rand()%10+1));
}
// выводим матрицу
for (int count_row = 0; count_row < rows; count_row++)
{
for (int count_col =0; count_col < cols; count_col++)
cout « setw(4) « setprecision(2) « ptr2arr[count_row][count_col] « " ";
cout « endl;
}
/* находим максимальный элемент каждого столбца в матрице и переписываем эти значения в одномерный массив */
cout « "-------------------------------------------\n";
for (int count_col =0; count_col < cols; count_col++)
{
ptrmax[count_col]=0;
for (int count_row=0;count_row < rows; count_row++)
{
if(ptr2arr[count_row][count_col] >= ptrmax[count_col])
ptrmax[count_col] = ptr2arr[count_row][count_col];
}
cout « setw(4) « setprecision(2) « ptrmax[count_col]«" ";
}
// удаляем занимаемую массивами память (отдаем в переиспользование)
for (int count=0; count < rows; count++)
delete ptr2arr [count];
delete [] ptrmax;
delete [] ptr2arr;
return 0;
}
Дата: 2019-05-28, просмотров: 236.