C _Учебник_МОНУ
.pdfВказівники. Динамічна пам’ять |
219 |
|
|
|
|
for(i=0; i<n; i++)// Зчитування у циклі чисел з Memo1 |
|
|
{ x= StrToFloat(Memo1->Lines->Strings[i]); |
|
|
if (x!=0) N++;} |
// й обчислення кількості ненульових чисел. |
|
SG1->RowCount=N; |
// Встановлення кількості рядків у SG1 |
|
float *a=new float[N]; |
// Виділення пам‟яті під динамічний масив |
|
for(i=0; i<n; i++) |
|
|
{ x= StrToFloat(Memo1->Lines->Strings[i]); |
|
|
if(x!=0) |
// Записування ненульових чисел до масиву |
|
{a[j]=StrToFloat(Memo1->Lines->Strings[i]); SG1->Cells[0][j]=a[j];
//Збільшення індекса елемента масиву.
j++;
}
}
//Обчислення кількості від‟ємних
//елементів з непарними індексами. for(i=0; i<N; i++)
if(a[i]<0 && (i+1)%2!=0) k++; Edit1->Text=IntToStr(k);
//Звільнення пам‟яті від масиву. delete []a;
}
Другий спосіб розв‟язання з використанням функції calloc(): void __fastcall TForm1::Button1Click(TObject *Sender)
{int i, j=0; int k=0;
int n=Memo1->Lines->Count; int N=0; float x;
for (i=0; i<n; i++)
{x= StrToFloat(Memo1->Lines->Strings[i]); if (x!=0) N++;
}
SG1->RowCount=N;
// Виділення пам‟яті під динамічний масив
float *a=(float*)calloc(N, sizeof(float)); for(i=0; i<n; i++)
{x= StrToFloat(Memo1->Lines->Strings[i]); if(x!=0)
{ a[j]=StrToFloat(Memo1->Lines->Strings[i]);
j++;
}}
for(i=0; i<N; i++)
{ SG1->Cells[0][i]=a[i]; // Виведення масиву до SG1 if(a[i]<0 && (i+1)%2!=0) k++;
}
Edit1->Text=IntToStr(k);
free (a); // Звільнення пам‟яті від масиву
}
Вказівники. Динамічна пам’ять |
221 |
|
|
SG1->ColCount=N;
//Виділення пам‟яті під масив а; у цей момент ще неможна виділити пам‟ять
//під масив b, оскільки кількість його майбутніх елементів ще є невідома. float *a=new float[N];
int int i, k=0, j=0;
for(i=0; i<N; i++) a[i]=StrToFloat(SG1->Cells[i][0]); for(i=0; i<N; i++) if(a[i]>0) k++;
//Виділення пам‟яті під масив b
float *b=new float[k]; SG2->ColCount =k; for(i=0; i<N; i++)
if(a[i]>0){b[j]=a[i]; j++;} for(i=0; i<k; i++) SG2->Cells[i][0] =
FloatToStr(b[i]);
delete []a; delete []b;
}
Приклад 6.5 Увести масив з 10-ти цілих чисел і створити з нього два нових масиви: перший масив з непарних елементів, а другий – з парних.
Розв‟язок. Кількість елементів вихідного масиву є відома (10), тому цей масив у програмі буде оголошено в звичайний спосіб: int a[10];. Два нових масиви b1 та b2 доцільно створити динамічно, оскільки кількість елементів цих масивів n1 та n2 буде обчислено у програмі.
Текст програми
void __fastcall TForm1::Button1Click(TObject *Sender)
{int a[10];
int i, n1=0, n2=0, j1=0, j2=0;
for(i=0; i<10; i++) a[i]=StrToInt(SG1->Cells[i][0]); for(i=0; i<10; i++)
if(a[i]%2!=0) n1++; |
// Обчислення кількості непарних елементів n1 |
else n2++; |
// та кількості парних елементів n2. |
SG2->ColCount=n1; |
// Встановлення потрібної кількості комірок |
SG3->ColCount=n2; |
// у компонентах для виведення створюваних масивів. |
222 |
Розділ 6 |
int *b1 = new int [n1], *b2 = new int [n2]; for(i=0; i<10; i++) // Формування масивів b1 та b2 if(a[i]%2!=0){ b1[j1]=a[i]; j1++;}
else { b2[j2]=a[i]; j2++;}
//Виведення масивів в окремих циклах, оскільки масиви мають різну кількість елементів for(i=0; i<n1; i++) SG2->Cells[i][0]=IntToStr(b1[i]);
for(i=0; i<n2; i++) SG3->Cells[i][0]=IntToStr(b2[i]);
//Звільнення пам‟яті від b1 та b2
delete []b1; delete []b2;
}
Приклад 6.6 Увести дійсні числа в Memo і створити масив з тих чисел, модуль яких є менше за 10. Для обчислення середнього арифметичного додатних елементів створеного масиву організувати окрему функцію.
Текст програми:
//Функція обчислення середнього
//арифметичного додатних елементів масиву double sr_dod(double a[], int n)
{ double s=0; int i,k=0; for (i=0; i<n; i++)
if (a[i]>0) {s+=a[i]; k++;} return s/k;
}
//Кнопка “Розв‟язок”
void __fastcall TForm1::Button1Click (TObject *Sender)
{// N – кількість усіх чисел у Memo1 int N=Memo1->Lines->Count; int i, k=0, j=0;
double x;
for (i=0; i<N; i++)
{ x=StrToFloat(Memo1->Lines->Strings[i]);
if(fabs(x)<10) k++; |
// k – кількість чисел, які за модулем є менше за 10 |
}
Edit1->Text=IntToStr(k);
double *a = new double [k]; // Оголошення динамічного масиву // Введення елементів динамічного масиву з Memo1
for (i=0; i<N; i++)
{ x=StrToFloat(Memo1->Lines->Strings[i]); if (fabs(x)<10) { a[j]=x; j++; }
}
StringGrid1->RowCount=k; // Встановлення кількості рядків у StringGrid1 for (i=0; i<k; i++) // Виведення створеного масиву
StringGrid1->Cells[0][i]=FormatFloat("0.0",a[i]);
double sum= sr_dod(a, k); // Обчислення суми додатних елементів масиву
Edit2->Text=FormatFloat("0.0", sum);
delete []a; // Звільнення пам‟яті від масиву
}
Вказівники. Динамічна пам’ять |
223 |
|
|
Приклад 6.7 Надати можливість уведення цілого числа (від 1 до 10) та динамічно створити і розмістити на формі відповідну кількість компонентів для введення елементів динамічно створюваного масиву і подальшого обчислення суми додатних елементів цього масиву.
Розв‟язок. Як приклад динамічного створювання та розміщування компонентів на формі розглянемо створення певної кількості Edit-ів та Label-ів. Причому наведемо два різні підходи для роботи зі створеними компонентами як з масивом і як з окремими об‟єктами. Аналогічним чином можна працювати з будь-якими компонентами.
Окрім зазначених алгоритмів динамічного створювання компонентів у цій програмі застосовано діалогове вікно InputBox() для введення цілого числа, синтаксис функції формування якого є такий:
AnsiString InputBox(AnsiString Caption, AnsiString Prompt, AnsiString Default);
де Caption – текст надпису вікна;
Prompt – пояснювальний текст (підказка) у вікні;
Default – пропоноване значення для введення, з яким можна погодитись або змінити його на нове значення.
Вікно введення, створене у програмі командою
int n=StrToInt(InputBox("Розмірність масиву", "Уведіть кількість елементів \n (додатне ціле число до 10-ти)", "5"));
матиме вигляд:
Приклад вигляду форми з відповідною кількістю динамічно створених компонентів на ній наведено ліворуч, а праворуч від нього показано вигляд цієї форми після введення довільних значень елементів динамічно створеного масиву та обчислення суми додатних його елементів.
Вказівники. Динамічна пам’ять |
225 |
|
|
6.7 Динамічні двовимірні масиви (матриці)
Двовимірний динамічний масив з m рядків і n стовпчиків займає в пам‟яті сусідні m*n комірок, тобто зберігається так само, як і одновимірний масив з m*n елементів. При розміщенні елементи двовимірних масивів розташовуються в пам‟яті підряд один за одним з першого до останнього без проміжків у послідовно зростаючих адресах пам‟яті. Наприклад, дійсний масив 3×5 зберігається у пам‟яті в такий спосіб:
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
0-й рядок |
|
|
1-й рядок |
|
|
2-й рядок |
|
||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
У такому масиві перші п‟ять елементів належать до першого рядка, наступні п‟ять – до другого і останні п‟ять – до третього.
Нагадаємо, що a – вказівник на початок масиву, тобто на елемент a[0][0]. Щоб звернутися, наприклад, до елемента a[1][3], слід “перестрибнути” від початку масиву через 5 елементів нульового рядка й 3 елементи першого рядка, тобто написати: *(a+1*5+3). У загальному випадку до елемента a[i][j] можна звернутися в такий спосіб: *(a+i*5+j). Але цей спосіб роботи з двовимірним масивом є не надто зручний, тому що в програмі при звертанні до елемента масиву доводиться розадресовувати вказівник і обчислювати індекс елемента.
Оголосити дійсний динамічний масив 3×5 можна як одновимірний з 15-ти елементів:
float *a=new float [3*5];
чи то
float *a=(float *)сalloc(3*5, sizeof(float));
Пам‟ять від створеного в такий спосіб масиву очищується за допомогою операцій відповідно delete й free:
delete []a;
чи то
free(a);
Розглянемо інший спосіб роботи з динамічним двовимірним масивом. Для цього розмістимо в пам‟яті машини матрицю 3 5:
a |
0 1 2 3 4 |
0
1
2
При цьому буде виділено пам‟ять під кожний рядок матриці окремо, тобто буде утворено три різні одновимірні масиви. Адреси нульових елементів цих масивів зберігатимуться в допоміжному масиві a (пам‟ять під нього слід виділити
226 |
Розділ 6 |
заздалегідь). Елементами цього масиву будуть адреси дійсних чисел, тому вони матимуть тип “вказівник на дійсне число”, тобто float . Нагадаємо, що загальний вигляд оголошення вказівника на динамічний масив є такий:
<тип елемента> * <ім‟я масиву>;
Тоді при оголошенні масиву а слід записати дві зірочки: float ** a = new float* [3];
//Оголошення й розміщення в пам‟яті допоміжного масиву з 3-х елементів типу float* for(int i=0; i<3; i++) a[i] = new float [5];
//У циклі виділяється пам‟ять під 3 масиви по 5 елементів (рядки матриці) й адреси
//нульових елементів цих масивів записуються у відповідні елементи масиву a
Після цього можна працювати з матрицею як зі звичайним двовимірним масивом, звертаючись до кожного елемента за його індексом, наведеним у квадратних дужках: a[i][j], – що є більш природним і зручним, аніж попередній спосіб.
Аналогічне є оголошення за допомогою сalloc():
float a = (float *) calloc (3, sizeof(float*)); for (int i=0; i<3; i++)
a[i] = (float*) calloc (5, sizeof(float));
Приклад 6.8 Увести кількість рядків і стовпчиків матриці та елементи самої матриці. Обчислити добуток її додатних елементів.
Розв‟язок. Оскільки кількість рядків та стовпчиків матриці заздалегідь є невідомі, матрицю доцільно організувати динамічно.
Наведемо два способи розв‟язування.
П е р ш и й с п о с і б
Пам‟ять виділяється під кожний рядок матриці окремо. При роботі з елементами матриці явно зазначаються обидва індекси (як при роботі з елементами нединамічної матриці), що вважається більш зручним.
Текст програми: int m, n;
// Кнопка “Прийняти”
void __fastcall TForm1::Button1Click(TObject *Sender) { m = StrToInt(Edit1->Text); // Введення розмірності матриці
n = StrToInt(Edit2->Text);
StringGrid1->RowCount = m; StringGrid1->ColCount = n;
}
//Кнопка “Розв‟язок”
void __fastcall TForm1::Button2Click(TObject *Sender) { double p=1;
Вказівники. Динамічна пам’ять |
227 |
|
|
float **a = new float* [m]; // Виділення пам‟яті під допоміжний масив // Виділення пам‟яті під кожний рядок матриці окремо
for(int i=0; i<m; i++) a[i]=new float[n]; for(int i=0; i<m; i++)
for(int j=0; j<n; j++)
{ a[i][j]=StrToFloat(StringGrid1->Cells[j][i]); if(a[i][j]>0) p*=a[i][j]; // Обчислення добутку додатних елементів
}
Edit3->Text=FloatToStr(p); for(int i=0; i<m; i++) delete []a[i];
delete []a;
}
Д р у г и й с п о с і б
Змінюється лише Button2Click “Розв‟язок”. Пам‟ять виділяється одразу під увесь двовимірний масив, звертання до елементів матриці виконується за допомогою одного індексу, який обчислюється залежно від індексів рядка та стовпчика. Звертатимемося до елементів масиву за допомогою вказівника, тобто для доступу до елемента матриці використовуватимемо операцію розадресації вказівника.
Текст програми:
void __fastcall TForm1::Button2Click(TObject *Sender) { double p=1;
float *a = new float [m*n]; // Виділення пам‟яті під увесь масив одразу;
// інакше це можна записати так: float *a = (float*)calloc(m*n, sizeof(float)); for(int i=0; i<m; i++)
for(int j=0; j<n; j++)
{ *(a+i*n+j)=StrToFloat(StringGrid1->Cells[j][i]);
//При звертанні до елементів використовується вказівник і обчислюється індекс if(*(a+i*n+j)>0) p *= *(a+i*n+j);
//За допомогою операції індексації це можна записати так:
//if (a[i*n+j]>0) p *= a[i*n+j];
}
Edit3->Text=FloatToStr(p); free(a);
}
Приклад 6.9 Увести цілочисельну матрицю 6 4 і створити нову матрицю з тих рядків уведеної матриці, які не містять нульових елементів.
Розв‟язок. На відміну від першої матриці, друга матриця буде динамічною, оскільки кількість її рядків заздалегідь є невідома. Для обчислення кількості нульових елементів кожного рядка організуємо тимчасовий допоміжний масив r. Кількість рядків другої матриці визначатимемо як кількість ненульових елементів масиву r і у нову матрицю будемо копіювати лише ті рядки першої, для яких r=0.