Функции динамического распределения памяти

 

Рассмотрим функции динамического распределения памяти, унаследованные от языка С. Прототипы функций динамического распределения памяти находятся в заголовке <cstdlib>. Все ком­пиляторы языка С++ поддерживают четыре функции динами­ческого распределения памяти: calloc(), malloc(), realloc() и free().

 

1. void* calloc(size_t num, size_t size);

Функция calloc() выделяет память (заполненную нулями), размер которой равен num*size байтов. Функция выделяет динамическую память, достаточную для размещения массива, состоящего из num элементов, каждый элемент размером size байтов. Функция возвращает указатель на первый байт выделенной области. Если требуемый объём памяти выделить невозможно, возвращается нулевой указатель. Прежде чем использовать выделенную память, необходимо проверить значение, возвращаемое функцией.

 

2. void* malloc(size_t size);

Функция malloc() возвращает указатель на первый байт выделенной области, имеющей размер size байтов. Если требуемый объём памяти выделить невозможно, возвращает­ся нулевой указатель. Прежде чем использовать выделенную память, необходимо проверить возвращаемое функцией значение.

 

3. void* realloc(void* ptr, size_t size);

Функция realloc() изменяет размер выделенной ранее памяти, на которую ссылается указатель ptr. Значение параметра size может быть как меньше, так и больше предыдущего объема. Функция возвращает указатель на первый байт выделенного блока памяти, поскольку может возникнуть необходимость скопировать его в другое место. В этом случае содержимое старого блока копируется в новый, и потери информации не происходит.

Если указатель ptr является нулевым, функция просто выделяет size байтов памяти и возвращает указатель на первый байт выделенного участка (т.е. аналогична malloc). Если параметр size равен нулю, память, на которую ссыла­ется указатель ptr, освобождается (т.е. аналогична free).

Если требуемый объём памяти выделить невозможно, возвращается нулевой указатель, и старый блок памяти остается неизменным.

 

4. void free(void *ptr);

Функция free() освобождает память, отмеченную указателем ptr. После этого освобождённую память можно использовать вновь.

Функцию можно применять лишь к указателю, используемому ранее в вызове функций calloc(), malloc() и realloc().

 

Функции malloc(), calloc() и realloc() возращают указатель типа void*. В языке С++ при присваивании указателя типа void* указателю другого типа необходимо выполнять явное приведение типа.

Рассмотрим пример программы с использованием функций динамического распределения памяти.

 

Задача 3. Ввести с клавиатуры набор вещественных чисел, количество которых заранее не фиксировано, и найти среди них максимальное число.

 

// Листинг 7.3

#include <iostream>

#include <cstdlib>

 

using namespace std;

 

int main() {

setlocale(LC_ALL, "Russian");

int n, m, i, j;

 

// Ввод с клавиатуры размера массива p1

cout << "n = ";

cin >> n;

 

// Выделение динамич. памяти для массива

int *p1 = (int*)malloc(n*sizeof(int));

if (p1 == 0) {

cout << "Не удалось выделить память\n"

return 1;

}

 

cout << "Исходный массив p1:" << endl;

for (i = 0; i < n; ++i) {

p1[i] = i;

cout << p1[i] << " ";

}

cout << endl;

 

// Ввод с клавиатуры размера массива p2

cout << "m = ";

cin >> m;

 

// Выделение динамической памяти для массива

double *p2 =

(double*)calloc(m, sizeof(double));

if (p2 == 0) {

cout << "Не удалось выделить память\n"

return 1;

}

 

cout << "Массив p2:" << endl;

for (i = 0; i < m; ++i)

cout << p2[i] << " ";

cout << endl;

 

// Добавим два элемента в массив p1

n += 2;

 

// Выделение динамической памяти

// для увеличенного массива

p1 = (int*)realloc(p1, n*sizeof(int));

 

 

p1[n-2] = 13;

p1[n-1] = 15;

 

cout << "Изменённый массив" << endl;

for (i = 0; i < n; ++i)

cout << p1[i] << " ";

cout << endl;

 

// Удалим четыре элемента из массива p1

n -= 4;

// Выделение динамической памяти

// для уменьшенного массива

p1 = (int*)realloc(p1, n*sizeof(int));

cout << "Изменённый массив" << endl;

for (i = 0; i < n; ++i)

cout << p1[i] << " ";

cout << endl;

 

// Освобождение динамической памяти

free(p1);

free(p2);

return 0;

}

 

Результат выполнения программы:

 

n = 8

Исходный массив p1:

0 1 2 3 4 5 6 7

m = 5

Массив p2:

0 0 0 0 0

Изменённый массив

0 1 2 3 4 5 6 7 13 15

Изменённый массив

0 1 2 3 4 5

 

При несоответствии способов выделения и освобождения памяти результат не определён.

Если при исчерпании свободной памяти, выделяемой с помощью оператора new, желательно не обрабатывать исклю­чения, а проверять возвращаемый new указатель на равенство 0 (так, как это делается в С при использовании функций динамического распределения памяти), можно использовать специально предназначенные для этого версии операторов new с параметром nоthrow (их объявления лежат в заголовочном файле <new>). Такой оператор – new(nothrow) или new(nothrow)[ ] – исключений не возбуждает, а возвращает 0, если невозможно выделить память.

 

Рассмотрим программу, использующую оператор new с параметром nоthrow.

 

// Листинг 7.4

#include <new>

#include <iostream>

using namespace std;

int main() {

int n = 0;

char *p;

while (1) {

// Выделение динамической памяти в 1 Mб

p = new(nothrow) char[1024*1024];

++n;

if (!p) { // p == 0

cout << n << " new returned 0" << endl;

exit (0);

}

cout << n << " MB OK" << endl;

}

return 0;

}

 

Результат выполнения программы:

1 MB OK

2 MB OK

3 MB OK

...

1891 MB OK

1892 MB OK

1893 new returned 0

 

Рассмотрим универсальный и безопасный способ выделения памяти для двумерного динамического массива, когда обе его размерности задаются на этапе выполнения программы. Сначала выделяется память для вспомогательного массива matr указате­лей на строки, а затем происходит выделение памяти для одно­мерных массивов matr[i] элементов каждой строки (рис. 7.1).

 

Рис. 7.1. Выделение памяти для двумерного динамического массива

 

Рассмотрим примеры решения задач с использованием двумерных динамических массивов.

 

Задача 4. Сформировать, заполнить данными, вывести на экран и уничтожить массив, представляющий прямоугольную матрицу, размеры (n – число строк, m – число столбцов) матрицы вводятся пользователем с клавиатуры, а каждый элемент матрицы вычисляется по формуле matr ij = i + j.

 

// Листинг 7.5

#include <iostream>

using namespace std;

 

int main() {

int n, m, i, j;

// Ввод с клавиатуры числа строк n и числа

cin >> n >> m; // столбцов m в матрице

 

// Указатель для вспомогательного массива

// указателей на строки

int **matr = new int * [n]; // (1)

 

// Выделение памяти для массивов-строк

for (i = 0; i < n; ++i) // (2)

matr[i] = new int[m]; // (3)

 

// Заполнение значениями элементов матрицы

// и вывод на экран

for (i = 0; i < n; ++i) {

for (j = 0; j < m; ++j) {

matr[i][j] = i+j;

cout << matr[i][j] << "\t";

} // for j

cout << endl;

} // for i

 

// Порядок освобождения памяти из-под матрицы

for (i = 0; i < n; ++i) // обратен выделению

delete [] matr[i];

delete [] matr;

return 0;

}

 

Результат выполнения программы:

0 1 2

1 2 3

 

В строке (1) объявляется переменная типа указатель на указатель на int и выделяется память для вспомогательного массива указателей на строки (количество строк – n). В строке (2) организуется цикл для выделения памяти для каждой строки двумерного массива. В строке (3) каждому элементу массива указателей на строки присваивается адрес начала участка памяти, выделенного для i-той строки двумерного массива. Каждая строка состоит из m элементов типа int (см. рис.3.1).

 

Задача 5. Сформировать массив, представляющий прямоугольную целочисленную матрицу, размеры (n – число строк, m – число столбцов) матрицы вводятся пользователем с клавиатуры в процессе работы программы. Заполнить матрицу путём считывания данных из файла (matrix.txt), вывести её на экран. Определить номер самого левого столбца, содержащего только положительные элементы, если такого столбца нет, вы­вести соответствующее сообщение. Увеличить каждый элемент матрицы в два раза, записать изменённую матрицу в файл (matrix1.txt), освободить динамическую память.

 

Примечание: файл matrix.txt, из которого заполняется матрица, должен находиться в том же каталоге, где находится файл с текстом программы. Файл matrix1.txt, в который выводится изменённая матрица, создаётся в том же каталоге.

 

// Листинг 7.6

#include <fstream>

#include <iostream>

 

using namespace std;

 

int main() {

setlocale(LC_ALL, "Russian");

 

int n, m, i, j;

cout << "Введите число строк и столбцов "

"в матрице:" << endl;

cin >> n >> m; // Число строк и столбцов

 

// Выделение динамической памяти для матрицы

int **matr = new int * [n];

for (i = 0; i < n; ++i)

matr[i] = new int[m];

 

// Открытие файла для ввода

ifstream infile("matrix.txt");

 

if(!infile) {

cout << "File can not be open" << endl;

return 1; // Выход из программы

}

 

// Заполнение матрицы (считыванием из файла)

for (i = 0; i < n; ++i) {

for (j = 0; j < m; ++j) {

infile >> matr[i][j];

cout << matr[i][j] << "\t";

} // for j

cout << endl;

} // for i

 

infile.close();

 

// Определение номера самого левого столбца

// с положительными элементами

int flag, nstolb = -1;

// Внешний цикл по столбцам

for (j = 0; j < m; ++j) {

flag = 1;

// Внутренний цикл по строкам

for (i = 0; i < n; ++i)

if (matr[i][j] < 0) {

flag = 0;

break;

}

if (flag) {

nstolb = j;

break;

}

}

 

if (nstolb == -1)

cout << "Столбцов с положительными "

"элементами нет" << endl;

else cout << "Номер самого левого столбца: "

<< nstolb << endl;

 

// Открытие файла для вывода

ofstream outfile("matrix1.txt");

 

if (!outfile) {

cout << "File can not be open" << endl;

return 1; // Выход из программы

}

 

// Запись матрицы в файл

for (i = 0; i < n; ++i) {

for (j = 0; j < m; ++j) {

matr[i][j] *= 2;

outfile << matr[i][j] << "\t";

} // for j

outfile << "\n";

} // for i

outfile.close();

 

// Освобождение динамической памяти

for(i = 0; i < n; ++i)

delete [] matr[i];

delete [] matr;

 

return 0;

}

 

Результат выполнения программы:

Введите число строк и столбцов в матрице:

3 4

-1 2 3 4

5 6 7 8

9 10 -11 12

Номер самого левого столбца: 1

 

Задание. Создать программу на языке С++, решающую задачу согласно варианту. Использовать динамическое выделение памяти для двумерных массивов.

Размеры массива вводить с клавиатуры. Предусмотреть возможность ввода элементов матрицы с клавиатуры и из заранее созданного текстового файла (по желанию пользователя программы).

Выводить результаты на экран и в файл.

Вариант 1

Дана целочисленная прямоугольная матрица.

Определить:

1) сумму элементов в тех строках, которые содержат хотя бы один отрицательный элемент;

2) номера строк и столбцов всех седловых точек матрицы. Матрица A имеет седловую точку Aij, если Aij является минимальным элементом в i-й строке и максимальным в j-м столбце.

 

Вариант 2

Дана целочисленная прямоугольная матрица.

1) Определить количество столбцов, не содержащих ни одного нулевого элемента.

2) Переставляя строки заданной матрицы, расположить их в соответствии с ростом характеристик. Характеристикой строки целочисленной матрицы назовём сумму её положительных чётных элементов.

 

Вариант 3

Дана целочисленная прямоугольная матрица. Определить:

1) количество столбцов, содержащих хотя бы один нулевой элемент;

2) номер строки, в которой находится самая длинная серия одинаковых элементов.

 

Вариант 4

Дана целочисленная квадратная матрица. Определить:

1) произведение элементов в тех строках, которые не содержат отрицательных элементов;

2) максимум среди сумм элементов диагоналей, парал­лельных главной диагонали матрицы.

 

Вариант 5

Дана целочисленная прямоугольная матрица.

1) Упорядочить строки целочисленной прямоугольной матрицы по возрастанию количества одинаковых элементов в каждой строке.

2) Найти номер первого из столбцов, не содержащих ни одного отрицательного элемента.

 

Вариант 6

Дана целочисленная матрица. Определить:

1) количество строк, не содержащих ни одного нулевого элемента;

2) максимальное из чисел, встречающихся в заданной матрице более одного раза.

 

Вариант 7

Дана целочисленная квадратная матрица.

1) Найти такие k, что k-я строка матрицы совпадает с k-м столбцом.

2) Найти сумму элементов в тех строках, которые содержат хотя бы один отрицательный элемент.

 

Вариант 8

Дана вещественная квадратная матрица.

1) Построить результат сглаживания заданной вещественной квадратной матрицы. Соседями элемента Aij в матрице назовём элементы Akl с i-1≤k≤i+1, j-1≤l≤j+1, (k,l)≠(i,j). Операция сглаживания матрицы даёт новую матрицу того же размера, каждый элемент которой получается как среднее арифметическое имеющихся соседей соответствующего элемента исходной матрицы.

2) В сглаженной матрице найти сумму модулей элементов, расположенных ниже главной диагонали.

 

Вариант 9

Дана целочисленная прямоугольная матрица

1) Переставляя столбцы заданной матрицы, расположить их в соответствии с ростом характеристик. Характеристикой столбца целочисленной матрицы назовём сумму модулей его отрицатель­ных нечётных элементов.

2) Найти сумму элементов в тех столбцах, которые содер­жат хотя бы один отрицательный элемент.

 

Вариант 10

Дана целочисленная прямоугольная матрица.

1) Уплотнить заданную матрицу, удаляя из неё строки и столбцы, заполненные нулями.

2) Найти номер первой из строк, содержащих хотя бы один положительный элемент.

 

Вариант 11

Дана вещественная квадратная матрица.

1) Осуществить циклический сдвиг элементов квадратной матрицы вправо на k элементов таким образом:

2) элементы 1-й строки сдвигаются в последний столбец сверху вниз, из него – в последнюю строку справа налево, из неё – в первый столбец снизу вверх, из него – в первую строку; для остальных элементов – аналогично.

 

Вариант 12

Дана целочисленная квадратная матрица.

1) Подсчитать количество локальных минимумов заданной квадратной матрицы. Элемент матрицы называется локальным минимумом, если он строго меньше всех имеющихся у него соседей.

2) Найти сумму модулей элементов, расположенных выше главной диагонали.

 

Вариант 13

Дана целочисленная квадратная матрица.

Осуществить циклический сдвиг элементов прямоугольной матрицы на n элементов вправо или вниз (в зависимости от введённого режима). n может быть больше количества элементов в строке или столбце.

Вариант 14

Дана вещественная квадратная матрица.

1) Путем перестановки элементов квадратной вещественной матрицы добиться того, чтобы её максимальный элемент находился в левом верхнем углу, следующий по величине – в позиции (2,2), следующий по величине (3,3) и т.д., заполнив таким образом всю главную диагональ.

2) Найти номер первой из строк, не содержащих ни одного положительного элемента.

 

Вариант 15

Дана целочисленная прямоугольная матрица.

1) Определить номер первого из столбцов, содержащих хотя бы один нулевой элемент.

2) Переставляя строки заданной матрицы, расположить их в соответствии с убыванием характеристик. Характеристикой строки целочисленной матрицы назовем сумму ее отрицательных четных элементов.

Вариант 16

Коэффициенты системы линейных уравнений заданы в виде прямоугольной матрицы.

1) С помощью допустимых преобразований привести систему к треугольному виду.

2) Найти количество строк, среднее арифметическое элементов которых меньше заданной величины.

 

Вариант 17

Дана целочисленная квадратная матрица. Определить:

1) сумму элементов в тех столбцах, которые не содержат отрицательных элементов;

2) минимум среди сумм модулей элементов диагоналей, параллельных побочной диагонали матрицы.

 

Вариант 18

Дана целочисленная прямоугольная матрица. Определить:

1) количество отрицательных элементов в тех строках, которые содержат хотя бы один нулевой элемент;

2) номера строк и столбцов всех седловых точек матрицы. Матрица A имеет седловую точку Aij, если Aij является минимальным элементом в i-й строке и максимальным в j-м столбце.

 

Вариант 19

Дана целочисленная квадратная матрица. Определить:

1) сумму элементов в тех строках, которые не содержат отрицательных элементов;

2) минимум среди сумм элементов диагоналей, параллель­ных главной диагонали матрицы.

 

Вариант 20

Дана целочисленная прямоугольная матрица. Определить:

1) количество строк, содержащих хотя бы один нулевой элемент;

2) номер столбца, в котором находится самая длинная серия одинаковых элементов.


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: