Массивы являются разумным подходом к хранению данных, но они имеют серьёзный недостаток: мы должны знать при написании программы, насколько большой массив нам нужен. Компилятор С++ требует, чтобы значение размерности массива было константой, поэтому как правило приходится завышать размерность массива, что приводит к перерасходу памяти.
Таким образом, если до начала работы программы неизвестно, сколько в массиве будет элементов, то следует использовать динамические массивы. Динамические массивы создают с помощью операции new, при этом необходимо указать тип и размерность, например:
int n;
… cin >> n;
float *a = new float [n];
В последней строке описан указатель на вещественную величину, которому присваивается адрес начала непрерывной области динамической памяти, выделенной с помощью операции new. Операционной системой выделяется столько памяти, сколько необходимо для хранения n величин типа float. При этом, величина n естественно может быть переменной.
Динамические массивы нельзя при создании инициализировать, и они не обнуляются. Преимущество динамических массивов состоит в том, что их размерность может быть переменной, т.е. объём памяти выделяемой под массив, определяется не программистом, а на этапе выполнения программы. Доступ к элементам динамического массива осуществляется точно так же, как к статическим, например, к элементу номер 5 приведённого выше массива можно обратиться как а[5] или *(а+5).
Если динамический массив в какой-то момент работы программы перестаёт быть нужным и мы собираемся впоследствии использовать выделенную под него память повторно, необходимо освободить её с помощью операции delete [ ], например: delete [ ] a;. Размерность массива при этом не указывается, но квадратные скобки обязательны.
Рассмотрим пример, демонстрирующий использование операции динамического выделения памяти. Программа вычисляет сумму элементов массива.
int main() {
int N, i, sum=0;
cout << "Vvedite kol-vo elementov massiva: "; cin >> N;
int *mas = new int [N];
for(i=0; i<N; i++) {
cout << "Vvedite element " << i << ": ";
cin >> mas[i];
}
for(i=0; i<N; i++) {
sum = sum + mas[i];
}
cout << "\nSumma elementov massiva: " << sum << endl;
delete [ ] mas;// эта строка не обязательна, поскольку программа закончила работу
getch(); return 0; }
Время жизни динамического, как и любой динамической переменной, - с момента выделения памяти до момента её освобождения. Область действия зависит от места описания указателя, через который производится работа с массивом. Область действия и время жизни указателей подчиняется общим правилам для переменных.
В приведённом примере мы применили операцию освобождения выделенных участков памяти delete [ ], которая на самом деле (в данном случае) и не нужна, так как память автоматически освобождается после завершения программы. Однако предположим, что мы используем операцию new в функции. Если функция использует локальную переменную-указатель на память, выделенную с использованием new, то указатель будет уничтожен по окончании работы функции, но память, в случае отсутствия delete [ ], останется выделенной и при этом недоступной из программы. Поэтому освобождение памяти после того, как она была использована и больше не требуется, является хорошим тоном. При этом надо быть внимательными и не использовать указатели на освобождённую ранее память.
Д/З
| Написать программу, которая позволяет вводить динамический вещественный массив и с помощью "возвращающей" функции определять сумму его элементов, расположенных правее последнего отрицательного элемента. В случае исключительной ситуации должно выводиться соответствующее сообщение. Функция должна возвращать соответствующее значение, если она вычислила сумму элементов правее последнего отрицательного, если в массиве нет отрицательных элементов и если отрицательный элемент последний.
|
Ответ
| int N;
float sumppo(float arr[], int N);
int main() {
int i;
cout << "Vvedite kol-vo elementov massiva: "; cin >> N;
float *mas = new float [N];
for(i=0; i<N; i++) {
cout << "Vvedite element " << i << ": ";
cin >> mas[i];
}
if((sumppo(mas, N)) >= 0.)
cout << "\n Summa elementov pravee posl. otricatelnogo: " << sumppo(mas, N);
if((sumppo(mas, N)) == -1)
cout << "\n V massive net otricat. elementov!";
if((sumppo(mas, N)) == -2)
cout << "\n Otricatelniy element posledniy!";
delete [] mas;
getch(); return 0;
}
//---------------------------------------------------------------------------
float sumppo(float arr[], int N) {
float sum = 0, res;
int k=0;
for(int j=N-1; j>=0; j--) {
if(arr[j] < 0) { k++; break; }
sum = sum + arr[j];
}
if(k == 0) res = -1;
if(k == 1 && arr[N-1] < 0.) res = -2;
if(k == 1 && arr[N-1] >= 0.) res = sum;
return res;
}
|
Естественно можно осуществлять динамическое выделение памяти и для многомерных массивов. Существует несколько способов решения этого вопроса. Более универсальный и безопасный способ выделения памяти под двумерный массив заключается в том, что обе его размерности задаются на этапе выполнения программы. Рассмотрим пример.
int main() {
int Nstr, Nstb, i, j;
cout << "Vvedite kol-vo strok i stolbcov: ";
cin >> Nstr >> Nstb;
int **mas = new int *[Nstr];// 1
for(i=0; i<Nstr; i++)// 2
mas[i] = new int [Nstb];// 3
for(i=0; i<Nstr; i++)
for(j=0; j<Nstb; j++) {
cout << "Vvedite element stroki " << i << ", stolbca " << j << ": ";
cin >> mas[i][j];
}
…
Здесь, в операторе 1 объявляется переменная типа "указатель на указатель на int" и выделяется память под массив указателей на строки массива. В операторе 2 организуется цикл для выделения памяти под каждую строку массива. В операторе 3 каждому элементу массива указателей на строки присваивается адрес начала участка памяти, выделенного под строку двумерного массива. Каждая строка состоит из Nstb элементов типа int.
Д/З
| Допишите приведенную выше программу, чтобы она позволяла выводить на экран введённую матрицу в отформатированном наглядном виде с помощью функции. При передаче массива в функцию используйте указатели, а размерность массива передавайте по ссылке. Применение глобальных переменных запрещено.
|
Ответ
| …
#include <iomanip>
using namespace std;
//---------------------------------------------------------------------------
void show(int** ptr, int& Kstr, int& Kstb);
int main() {
int i, j, Nstr, Nstb;
cout << "Vvedite kol-vo strok i stolbcov: ";
cin >> Nstr >> Nstb;
int **mas = new int *[Nstr];
for(i=0; i<Nstr; i++)
mas[i] = new int [Nstb];
for(i=0; i<Nstr; i++)
for(j=0; j<Nstb; j++) {
cout << "Vvedite element stroki " << i << ", stolbca " << j << ": ";
cin >> mas[i][j];
}
show(mas, Nstr, Nstb);
delete [] mas;
getch(); return 0;
}
//---------------------------------------------------------------------------
void show(int** ptr, int& Kstr, int& Kstb) {
int i, j;
cout << "\nVvedena matrica: " << endl;
for(i=0; i<Kstr; i++) {
for(j=0; j<Kstb; j++)
cout << setw(3) << ptr[i][j];
cout << endl;
}
}
|
Лекция 8(17 стр.)