Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
лекция 21-22.docx
Скачиваний:
14
Добавлен:
23.03.2015
Размер:
63.35 Кб
Скачать

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

Довольно часто возникает необходимость выделить память динамически, используя malloc(), но работать с этой памятью удобнее так, будто это массив, который можно индексировать. В этом случае нужно создать динамический массив. Сделать это несложно, потому что каждый указатель можно индексировать как массив. В следующем примере одномерный динамический массив содержит строку:

/* Динамическое распределение строки, строка вводится

пользователем, а затем распечатывается справа налево. */

#include <stdlib.h>

#include <stdio.h>

#include <string.h>

int main(void)

{

char *s;

register int t;

s = malloc(80);

if(!s) {

printf("Требуемая память не выделена.\n");

exit(1);

}

gets(s);

for(t=strlen(s)-1; t>=0; t--) putchar(s[t]);

free(s);

return 0;

}

Перед первым использованием s программа проверяет, успешно ли прошло выделение памяти. Эта проверка необходима для предотвращения случайного использования нулевого указателя. Обратите внимание на то, что указатель s используется в функции gets(), а также при выводе на экран (но на этот раз уже как обыкновенный массив).

Можно также динамически выделить память для многомерного массива. Для этого нужно объявить указатель, определяющий все, кроме самого левого измерения массива. В следующем примере двухмерный динамический массив содержит таблицу чисел от 1 до 10 в степенях 1, 2, 3 и 4.

#include <stdio.h>

#include <stdlib.h>

int pwr(int a, int b);

int main(void)

{

/* Объявление указателя на массив из 10 строк

в которых хранятсяцелые числа (int). */

int (*p)[10];

register int i, j;

/* выделение памяти для массива 4 x 10 */

p = malloc(40*sizeof(int));

if(!p) {

printf("Требуемая память не выделена.\n");

exit(1);

}

for(j=1; j<11; j++)

for(i=1; i<5; i++) p[i-1][j-1] = pwr(j, i);

for(j=1; j<11; j++) {

for(i=1; i<5; i++) printf("%10d ", p[i-1][j-1]);

printf("\n");

}

return 0;

}

/* Возведение чисел в степень. */

pwr(int a, int b)

{

register int t=1;

for(; b; b--) t = t*a;

return t;

}

Программа выводит на экран следующее:

1 1 1 1

2 4 8 16

3 9 27 81

4 16 64 256

5 25 125 625

6 36 216 1296

7 49 343 2401

8 64 512 4096

9 81 729 6561

10 100 1000 10000

Указатель р в главной программе (main()) объявлен как

int (*p)[10]

Следует отметить, что скобки вокруг *р обязательны. Такое объявление означает, что р указывает на массив из 10 целых. Если увеличить указатель р на 1, то он будет указывать на следующие 10 целых чисел. Таким образом, р — это указатель на двухмерный массив с 10 числами в каждой строке. Поэтому р можно индексировать как обычный двухмерный массив. Разница только в том, что здесь память выделена с помощью malloc(), а для обыкновенного массива память выделяет компилятор.

Как упоминалось ранее, в C++ нужно преобразовывать типы указателей явно. Поэтому чтобы данная программа была правильной и в С, и в C++, необходимо выполнить явное приведение типа значения, возвращаемого функцией malloc(). Для этого строчку, в которой указателю р присваивается это значение, нужно переписать следующим образом:

p = (int (*)[10]) malloc(40*sizeof(int));

Многие программисты используют явное преобразование типов указателей для обеспечения совместимости с C++.

Динамическим называется массив, размер которого может меняться во время исполнения программы. Для изменения размера динамического массива язык программирования, поддерживающий такие массивы, должен предоставлять встроенную функцию или оператор. Динамические массивы дают возможность более гибкой работы с данными, так как позволяют не прогнозировать хранимые объёмы данных, а регулировать размер массива в соответствии с реально необходимыми объёмами. В отличие от динамических массивов существуют статические массивы и массивы переменной длины. Размер статического массива определяется на момент компиляции программы. Размер массива переменной длины определяется во время выполнения программы. Отличием динамического массива от массива переменной длины является автоматическое изменение размеров, что не трудно реализуется в случаях его отсутствия, поэтому часто не различают массивы переменной длины с динамическими массивами.

Пример объявления динамического массива на языках C/C++

Одномерный динамический массив:

Создаем массив с 10-ю элементами типа int:

Си:

int *mas = malloc (sizeof(int) * 10);

С++:

int *mas = new int[10];

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

mas[0] = 2; // присвоили значение 2 нулевому элементу массива mas

mas[1] = 7; // присвоили значение 7 первому элементу массива mas

//... и т.д.

Следовательно, если брать такой подход, то вам понадобится около десяти строк кода, чтобы проинициализировать весь массив. Для того, чтобы этого избежать, напишем то же самое в цикле:

for(int i = 0; i < 10; i++){

cin>>mas[i]; // пользователь вводит значение каждого i-ого элемента массива

}

После чего работаем с массивом. Так же его можно вывести на экран:

for(int i = 0; i < 10; i++){

cout << mas[i] << endl;

}

Для освобождения из памяти одномерного динамического массива используем:

Си:

free(mas);

С++: оператор delete:

delete []mas;

Строго говоря, вышеописанная реализация массива не является динамической, т.к. нет изменения размера массива во время работы, а всего лишь массив переменной длины. Возможным решением является realloc, но можно применить только при использовании malloc, но не new. Для того чтобы изменить размер такого массива необходимо объявить ещё один массив нужного размера, скопировать в него все данные и освободить память, занимаемую старым массивом. В С++ библиотечным решением является std::vector. В С89 нет массивов переменной длины, они есть только в С99 (который поддерживают не все компиляторы). Некоторые (довольно старые) компиляторы С++ также не поддерживают

Пример динамического массива на Си

float *array1; // Одномерный массив

int **array2; // Двумерный массив

array1 = (float*) malloc(10 * sizeof(float)); // выделение 10 блоков по sizeof(float) байт каждый

array2 = (int**) malloc(16 * sizeof(int*)); // выделение 16 блоков по sizeof(int*) байт каждый. Сюда будут записаны указатели на одномерные массивы-строки

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

array2[i] = (int*) malloc(8 * sizeof(int)); // выделение 8 блоков по sizeof(int) байт каждый. Это одномерные массивы - строки матрицы.

// Обращение к массиву

array1[i] = 5.0; // Записи эквивалентны. Первая с использованием индекса,

*(array1+i) = 5.0; // вторая с операцией разыменования.

array2[i][j] = 6; // Записи эквивалентны. Первая с использованием индекса,

*(*(array2+i)+j) = 6; // вторая с операцией разыменования.

free(array1); // Важно не забывать возвращать выделенную память системе.

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

free(array2[i]); // Возвращаем память, используемую для строк матрицы.

free(array2); // Возвращаем память, используемую для столбцов матрицы.

Пример динамического массива на С++

float *array1; // Одномерный массив

int **array2; // Многомерный массив

array1 = new float[10]; // выделение 10 блоков размером типа float

array2 = new int*[16]; // выделение 16 блоков размером типа указателя на int

for(int i = 0; i < 16; ++i)

array2[i] = new int[8];

// Работаем с массивами.

delete []array1; // Важно не забывать возвращать выделенную память системе.

for(int i = 0; i < 16; ++i)

delete []array2[i]; // Возвращаем память, используемую для строк матрицы.

delete []array2; // Возвращаем память, используемую для столбцов матрицы.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]