Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

C _Учебник_МОНУ

.pdf
Скачиваний:
199
Добавлен:
12.05.2015
Размер:
11.12 Mб
Скачать

Вказівники. Динамічна пам’ять

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); // Звільнення пам‟яті від масиву

}

220

Розділ 6

Існує можливість звертатися до елементів масиву без індексації за допомогою вказівників. У циклі за допомогою індексу поточний елемент масиву записується як a[i]. Згадаймо, що ім‟я масиву а можна використовувати як вказівник на початок (нульовий елемент) масиву. Тоді, згідно з арифметикою вказівників, a+i – це вказівник на елемент, який міститься на i комірок далі від початку масиву, тобто вказівник на a[i]. Значення елемента a[i] можна записати за допомогою операції розадресації: *(a+i). Якщо у програмі замінити всі звертання до елементів масиву за допомогою індексу на звертання до елементів за допомогою вказівника, то програма першого способу розв‟язання даного прикладу матиме вигляд

void __fastcall TForm1::Button1Click(TObject *Sender)

{int i, j=0, k=0, N=0;

int n=Memo1->Lines->Count; for (i=0; i<n; i++)

{x= StrToFloat(Memo1->Lines->Strings[i]); if(x!=0) N++;

}

SG1->RowCount=N; 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]);

j++;

} }

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

{SG1->Cells[0][i]=*(a+j); if(*(a+i)<0 && i%2!=0) k++;

}

Edit1->Text=IntToStr(k); delete []a;

}

Приклад 6.4 Увести ціле число N та масив з N дійсних чисел у StringGrid і створити новий масив з додатних елементів першого масиву.

Розв‟язок. Оскільки кількість елементів має бути введено з форми, заздалегідь вона є невідома, тому пам‟ять під обидва масиви слід виділяти динамічно.

Текст програми:

// Подія Edit1Change виникає при змінюванні вмісту вікна Edit1. void __fastcall TForm1::Edit1Change(TObject *Sender)

{ int N=StrToInt(Edit1->Text); // Введення кількості елементів масиву

SG1->ColCount=N;

// для визначення кількості комірок у SG1.

}

 

//-------------------------------------------------------------

void __fastcall TForm1::Button1Click(TObject *Sender) { int N=StrToInt(Edit1->Text);

Вказівники. Динамічна пам’ять

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"));

матиме вигляд:

Приклад вигляду форми з відповідною кількістю динамічно створених компонентів на ній наведено ліворуч, а праворуч від нього показано вигляд цієї форми після введення довільних значень елементів динамічно створеного масиву та обчислення суми додатних його елементів.

224

Розділ 6

Текст програми

//-----------------------------------------------------------------

int n;

// Кількість елементів масиву

TEdit *ed[10];

// Масив десяти вказівників на клас TEdit

TLabel *L;

// L – вказівник на клас TLabel

__fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner)

{ ww:

n=StrToInt(InputBox("Розмірність масиву", "Уведіть кількість елементів \n (додатне ціле число до 10-ти)", "5"));

if(n>10 || n<=0)

{ ShowMessage("Уведено некоректне значення!"); goto ww; } for(int i=0;i<n;i++)

{// Створити новий компонент класу TEdit на формі як елемент масиву ed ed[i] = new TEdit(Form1);

L = new TLabel(Form1); // Створення компонента класу TLabel на формі

ed[i]->Parent=GroupBox1;//Для розміщення створених компонентів L->Parent=GroupBox1; // задається їхній предок – компонент GroupBox1

L->Caption=IntToStr(i+1)+"-й елемент"; // Надпис мітки

//Розміщення відносно верхнього краю форми

L->Top=i*30+20; ed[i]->Top=i*30+20;

//Розміщення відносно лівого краю форми

L->Left=10;

ed[i]->Left=80;

ed[i]->Width=80;

// Ширина компонента

ed[i]->Clear();

 

// Очищення вікна

}

// Відповідно до кількості створених компонентів встановлення висоти

GroupBox1->Height=ed[n-1]->Top+30; // GroupBox1 Form1->Height=GroupBox1->Height+40; // та форми

}

//-----------------------------------------------------------------

void __fastcall TForm1::Button1Click(TObject *Sender)

{double S=0, *a = new double [n]; for (int i=0; i<n; i++)

{ a[i]=StrToFloat(ed[i]->Text);

if (a[i]>0) S+=a[i];

}

Edit1->Text=FloatToStr(S); delete []a;

}

//-----------------------------------------------------------------

void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action)

{delete []ed; delete L;

}

Вказівники. Динамічна пам’ять

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.

228

Розділ 6

Робочий вигляд форми після введення матриці та натиснення кнопки “Розв‟язок”:

Текст програми

// Формування “шапки” SG1 індексами рядків і стовпчиків матриці

__fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner)

{for(int i=1;i<=6;i++)SG1->Cells[0][i]=IntToStr(i)+"-й рядок"; for(int j=1;j<=4;j++)SG1->Cells[j][0]=IntToStr(j)+" -й стовпчик";

}

//-------------------------------------------------------------

void __fastcall TForm1::Button1Click(TObject *Sender) { int i, j, rowc=0,k=0; double a[6][4], s=0;

int r[6]={0}; // r – масив кількості нульових елементів рядків матриці for(i=0; i<6; i++)

for(j=0; j<4; j++)

{a[i][j]=StrToFloat(SG1->Cells[j+1][i+1]); if(a[i][j]==0) r[i]++;

}

for(i=0; i<6; i++) // Обчислення кількості рядків без нульових елементів

if(r[i]==0) rowc++;

// r[i]=0

означає, що в і-тому рядку немає нулів

SG2->RowCount=rowc+1;

 

double **b=new double *[rowc];

//Оголошення матриці b

for(i=0; i<rowc; i++) b[i]=new double [4];

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

 

 

if(r[i]==0)

// Якщо в і-тому рядку нулів немає,

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