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

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

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

Багатофайлові програми

309

Розв‟язок. У файлі MyLib.h зробимо потрібні оголошення й заголовки фу-

нкцій. Використаємо директиву #define, щоб задати константі k

значення 8.

#ifndef MyLibH #define MyLibH #define k 8

//Оголошення типів matr (“матриця”) і vekt (“вектор”) typedef double matr[k][k], vekt[k];

//Оголошення прототипів функцій

void elem_Matr(matr c);

void elem_Vect(matr c, vekt v); double G(matr c);

#endif

У файлі MyLib.cpp пропишемо визначення функцій, прототипи яких розміщено у файлі MyLib.h.

#pragma hdrstop

#include <math.h> // Долучення математичної бібліотеки

#include "MyLib.h"

#pragma package(smart_init)

// Визначення функції розрахунку елементів матриці void elem_Matr(matr c)

{for(int i=0; i<k; i++) for(int j=0; j<k; j++)

if(sin(i+j)>0)

c[i][j] = pow((i+j+2.)/(7*i+1)+j,4./3)-3.7*(i+j); else

c[i][j] = M_PI*pow( sin(i-j),3);

}

// Визначення функції розрахунку елементів вектора void elem_Vect(matr c, vekt v)

{for(int i=0; i<k; i++) { v[i]=0;

for(int j=0; j<k; j++) v[i]+=c[i][j];

}

}

// Пошук найближчого елемента до середнього арифметичного double G(matr c)

{int ni=0, nj=0, i, j; double sr=0; for(i=0; i<k; i++) for(j=0; j<k; j++)

sr += c[i][j]/pow(k,2); for(i=0; i<k; i++) for(j=0; j<k; j++)

if(fabs(sr-c[i][j])<fabs(sr-c[ni][nj]))

{ ni=i; nj=j; } return c[ni][nj] ;

}

310

Розділ 9

Головний файл проекту Unit1.cpp:

#include <vcl.h> #pragma hdrstop

#include "MyLib.h" // Долучення власної бібліотеки

#include "Unit1.h"

#pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1;

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

__fastcall TForm1::TForm1(TComponent* Owner)

 

: TForm(Owner)

{

 

}

 

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

Глобальне оголошення матриці та вектора --------------

matr a;

vekt x;

void __fastcall TForm1::FormCreate(TObject *Sender)

{// Компоненти Button2 та Button3 стануть невидимими

Button2->Visible = 0; Button3->Visible = 0; // Заповнення фіксованих комірок компонентів StringGrid for(int i=1;i<=k;i++)

{SG1->Cells[0][i] = IntToStr(i) + "-й"; SG1->Cells[i][0] = IntToStr(i) + "-й";;

}}

//------------- Глобальне оголошення матриці та вектора -------------

void __fastcall TForm1::Button1Click(TObject *Sender)

{elem_Matr( a); // Виклик функції обчислення елементів матриці for(int i=0; i<k; i++)

for(int j=0; j<k; j++)

SG1->Cells[j+1][i+1] = FormatFloat("0.000",a[i][j]); Button2->Visible = 1; Button3->Visible = 1;

}

 

Багатофайлові програми

311

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

Виведення елементів вектора -------------------

 

void __fastcall TForm1::Button2Click(TObject *Sender)

 

{elem_Vect(a, x); // Виклик підпрограми обчислення елементів вектора for(int i=0;i<k;i++)

SG2->Cells[0][i] = FormatFloat("0.000",x[i]);

}

//--------------- Виведення значення скаляра ---------------------

// Виведення значення скаляра

void __fastcall TForm1::Button3Click(TObject *Sender) { Edit1->Text = FormatFloat("0.000",G(a));

}

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

Розв‟язок. Матриця називається верхньотрикутною, якщо значення всіх її елементів, розташованих під головною діагоналлю, дорівнюють нулю. Визначник трикутної матриці дорівнює добуткові всіх її діагональних елементів. Отже, для обчислення визначника матриці її слід звести до верхньотрикутної. Для цього треба обчислити коефіцієнти за формулою fi aik / aii і додати до еле-

ментів і-го рядка відповідні елементи k-го рядка, помножені на fi . Процес триває n-1 кроків. Отже, значення елементів трикутної матриці визначаються за

формулою

a

 

a

 

 

aik akj

. Тут a

 

– опорний елемент (він лежить на головній

 

ij

 

kk

 

ij

 

 

 

akk

 

 

 

 

 

 

 

 

 

 

 

діагоналі);

i,

j, k

 

індекси рядків та стовпчиків матриці, n – вимірність матри-

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

Створимо заголовний файл Det.h, який міститиме перейменування типу матриця matr і дві функції: зведення матриці до верхньотрикутної triangular() і обчислення визначника determinant().

У заголовному файлі Det.h уведемо потрібні оголошення й заголовки функцій:

#ifndef DetH #define DetH

//Описання типу матриці (вказівник на двовимірний масив) typedef float** matr;

//Прототипи функції, які можуть бути викликані в програмі

void triangular (matr a, int, int); /*Зведення матриці

до верхньотрикутної */ float determinant (matr, int); //Обчислення визначника

#endif

Для поставленого завдання щодо обчислення визначника, можна в заголовному файлі оголосити прототип лише функції determinant(), яка безпосе-

312

Розділ 9

редньо обчислює визначник. Але функцію triangular()може бути використано для розв‟язання якихось інших завдань (приміром, при розв‟язуванні системи лінійних рівнянь), тому є сенс розмістити її також у заголовному файлі (для підвищення його універсальності) і у разі потреби долучити його до іншої програми.

Файл Det.cpp містить визначення функцій, прототипи яких розміщено у файлі Det.h. Обидві функції й тип може бути використано у кожній програмі, до якої буде залучено заголовний файл Det.h. Окрім того, файл Det.cpp містить визначення функції change(), яка викликатиметься у функції determinant() і буде недоступною в інших файлах, і змінну znak, яка буде глобальною для файла Det.cpp, але не буде приступною в інших файлах.

Функція triangular() має три параметри: матриця a, розмір матриці n і індекс опорного елемента k (індекс обчислюваного рядка). Оскільки матриця завжди передається з доступом для змінювання, функція triangular() обчислює нові значення елементів матриці за формулою

a

a

 

 

aik akj

,

ij

 

 

ij

 

akk

 

 

 

 

 

 

де k – індекс опорного елемента, який є параметром функції.

Функція change()має також три параметри: матриця a, розмір матриці n та індекс рядка, який міняється місцем з будь-яким рядком k. Виконується пошук рядка з ненульовим елементом у стовпчику k. Якщо такий елемент знайдено, виконується переставляння рядка з індексом k і рядка, який містить знайдений ненульовий елемент, і змінюється знак визначника. Після цього виконування функції можна припинити, оскільки подальший пошук не має сенсу.

Функція determinant() має два параметри – матрицю a та її розмір n.

#pragma hdrstop #include "Det.h"

#pragma package(smart_init)

//Глобальне оголошення змінної znak, яка буде зберігати знак визначника int znak;

//Визначення функції заміни рядків матриці

void change(matr a, int n, int k)

{for(int j=0;j<n-k;j++)// Переглядання рядків, розміщених нижче рядка

//з індексом k.

if(a[k+j][k]!=0)

// Якщо у стовпчику k знайдено ненульовий елемент,

{ znak=-znak;

// змінити знак визначника на протилежний

for(int i=0; i<n; i++) // і переставити рядки з індексами k та k+j.

{float z = a[k][i]; a[k][i] = a[k+j][i]; a[k+j][i] = z;

}

// Якщо один раз рядки переставлено,

return;

// продовжувати пошук немає сенсу.

}

}

Багатофайлові програми

313

void triangular(matr a, int n, int k) // Визначення функції triangular()

{for(int i=k+1; i<n; i++)

{ float koef = a[i][k]/a[k][k];// Обчислення коефіцієнта

for(int j=0; j<n; j++) // Обчислення елементів в обраному рядку a[i][j] = a[i][j] - a[k][j]*koef;

}

}

// Визначення функції обчислення визначника матриці float determinant(matr a, int n)

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

{ if(a[i][i]==0) // Якщо опорний елемент дорівнює нулю, change(a, n, i); // викликати функцію переставляння рядків матриці

triangular(a, n, i);// Обчислення стовпчика трикутної матриці

}

float det=1;

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

det *= a[i][i];

// Перемноження діагональних елементів

if(znak<0) det=-det;

// Змінення знака визначника

return det;

 

}

Головний файл проекту Unit1.cpp.

#include <vcl.h> #pragma hdrstop #include "Unit1.h"

#include "Det.h" // Долучення створеного заголовного файла Det.h

#pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1;

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

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

{

}

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

314

Розділ 9

int N; // Глобальна змінна для розмірності матриці

// Введення розмірності матриці і встановлення розмірів компонентів StringGrid void __fastcall TForm1::Button1Click(TObject *Sender)

{if(Edit1->Text=="")

{ShowMessage("Введіть розмірність матриці"); return; }

N=StrToInt(Edit1->Text); SG1->RowCount=N; SG1->ColCount=N;

SG2->RowCount=N;

SG2->ColCount=N;

}

 

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

 

// Обчислення визначника

void __fastcall TForm1::Button2Click(TObject *Sender)

{ if(N==0){ ShowMessage("Введіть розмірність матриці");return;}

matr a=new float*[N];

// Виділення пам‟яті під матрицю

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

a[i]= new float[N];

randomize();

 

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

 

for(int j=0; j<N; j++)

 

{ a[i][j]=random(10)-5; //Заповнення матриці випадковими числами

SG1->Cells[j][i]=FloatToStr(a[i][j]);

}

Edit2->Text=determinant(a, N);// Виклик функції обчислення визначення for(int i=0; i<N; i++) // Виведення верхньотрикутної матриці for(int j=0; j<N; j++)

SG2->Cells[j][i]=FormatFloat("0.0", a[i][j]);

}

Приклад 9.3 Увести масив координат і нарисувати за числами цього масиву ламану. Створити проект, який містить три форми. На основній формі вводиться масив координат. Друга форма повідомляє про умову прикладу. Третя форма – полотно для рисування ламаної.

Розв‟язок. На першій формі розмістимо StringGrid1 (для спрощення перейменуємо його на SG1) та кнопки для автоматичного заповнення масиву випадковими числами чи то довільними числами користувачем. Окрім того, перша форма містить кнопки “Про програму”, при клацанні на яку з‟являється друга форма з умовою завдання, і “Нарисувати ламану”, при клацанні на яку відкривається третя форма з нарисованою ламаною.

Перша форма (Form1) відповідає Unit1.cpp, друга (“Про програму” –

About) – Unit2.cpp, третя (Form3) – Unit3.cpp.

Для створення форми AboutBox слід в меню File / New / Other (Файл / Новий / Інше) обрати вкладку Forms (Форми) і клацнути двічі на AboutBox.

Для створення третьої форми слід в меню File / New (Файл / Новий) обрати Form (Форма).

Після створення трьох форм проект слід зберегти (File / Save All). Якщо проект було збережено раніше, треба долучити нові форми до проекту:

Project / Add to project і обрати імена Unit2 і Unit3.

Багатофайлові програми

315

Для виклику у початковій програмі другої й третьої форм слід долучити відповідні заголовні файли Unit2.h і Unit3.h до Unit1.h. Для цього можна виконати команду File / Include Unit Hdr і обрати потрібні файли або власноруч написати на початку файла Unit1.cpp:

#include "Unit2.h" #include "Unit3.h"

Глобальна змінна а оголошена зі словом extern у Unit3.h. Оскільки цей файл долучено до Unit1.cpp, то змінна а в ньому є відома (навпаки зробити не можна). Визначення цієї змінної може бути розміщено як в Unit1.cpp, так і в Unit3.cpp. В даному прикладі визначення масиву а розміщено в Unit1.cpp.

Слід звернути увагу, що для виклику форм використовуються функції Show() та ShowModal(). Різниця поміж ними полягає в тому, що перша просто відкриває ще одну форму, при цьому завжди є можливість перемкнутися до першої форми. Друга відкриває форму, і перемкнутися до інших форм, допоки відкрито цю форму, є неможливо.

Масив а заповнюється значеннями в Unit1, а використовується – в Unit3.

Файл Unit1.cpp:

#include <vcl.h> #pragma hdrstop #include "Unit1.h"

#include "Unit2.h" // Долучити файл з другою формою #include "Unit3.h" // Долучити файл з третьою формою

#pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1;

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

__fastcall TForm1::TForm1(TComponent* Owner)

:TForm(Owner)

{SG1->Cells[0][1]="x"; SG1->Cells[0][2]="y";

for(int i=1; i<SG1->ColCount; i++) SG1->Cells[i][0]=IntToStr(i);

}

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

int a[2][10];

// Визначення масиву координат (глобальна змінна)

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

Випадкові числа ---------------------------

void __fastcall TForm1::Button1Click(TObject *Sender)

{randomize();

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

{a[0][i]=random(500)+5;

a[1][i]=random(400)+5; for(int j=0; j<2; j++)

SG1->Cells[i+1][j+1]=a[j][i];

}

}

316

Розділ 9

//------------------ Зчитати масив -----------------------------

void __fastcall TForm1::Button2Click(TObject *Sender)

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

for(int i=0; i<2; i++)a[i][j]=StrToInt(SG1->Cells[j+1][i+1]);

}

//------------------- Нарисувати ламану -------------------------

void __fastcall TForm1::Button3Click(TObject *Sender)

{ Form3->Show();

}

// Показати третю форму

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

Про програму -----------------------------

void __fastcall TForm1::Button4Click(TObject *Sender) { AboutBox->ShowModal(); }

Вікно основної форми:

Файл Unit2.cpp:

#include <vcl.h> #pragma hdrstop #include "Unit2.h" #pragma resource "*.dfm" TAboutBox *AboutBox;

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

__fastcall TAboutBox::TAboutBox(TComponent* AOwner) : TForm(AOwner)

{

}

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

void __fastcall TAboutBox::OKButtonClick(TObject *Sender) { Close();

}

Вікно другої форми “Про програму”:

 

Багатофайлові програми

317

Файл Unit3.h:

 

#ifndef Unit3H

 

#define Unit3H

 

#include <Classes.hpp>

 

#include <Controls.hpp>

 

#include <StdCtrls.hpp>

 

#include <Forms.hpp>

 

class TForm3 : public TForm

 

{ __published: // IDE-managed Components

 

TButton *Button1;

 

TButton *Button2;

 

void __fastcall Button1Click(TObject *Sender);

 

void __fastcall Button2Click(TObject *Sender);

 

private:

// User declarations

 

public:

// User declarations

 

__fastcall TForm3(TComponent* Owner);

 

}; //------------------------------------------------------------

extern PACKAGE TForm3 *Form3; //------------------------------------------------------------

extern int a[2][10]; //Оголошення (не визначення!) масиву координат

#endif

Файл Unit3.cpp:

#include <vcl.h> #pragma hdrstop #include "Unit3.h"

#pragma package(smart_init) #pragma resource "*.dfm" TForm3 *Form3;

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

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

{

}

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

Нарисувати ламану за координатами (числами масиву) -------

void __fastcall TForm3::Button1Click(TObject *Sender)

{ Canvas->MoveTo(a[0][0],a[1][0]);

// Перейти у першу точку

Canvas->Pen->Color=clRed;

// і встановити червоний колір.

for(int i=1; i<10; i++)

// Послідовно у циклі

 

Canvas->LineTo(a[0][i],a[1][i]); // з‟єднати лініями всі точки.

}

 

 

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

Вихід ----------------------------------

 

void __fastcall TForm3::Button2Click(TObject *Sender) { Close();

}

318

Розділ 9

Вікно третьої форми з нарисованою ламаною:

Приклад 9.4 Створити багатофайловий проект для опрацювання раціональних дробів і обчислення найбільшого спільного дільника і найменшого спільного кратного. Надати такі можливості: скорочення дробів, обчислення спільного знаменника двох дробів, порівняння на рівність/нерівність та більше/менше, додавання, множення й ділення дробів.

Розв‟язок. Раціональний дріб може бути подано двома цілими числами: чисельником і знаменником. Більшість операцій з раціональними дробами (порівняння, додавання, множення тощо) виконуються за іншими, більш складними, правилами, аніж відповідні операції з цілими числами та десятковими дробами. Тому доречно створити заголовний файл з прототипами функцій, які виконують деякі з зазначених операцій, а потім, за потреби їхнього використання, залучати цей файл до різних проектів.

При опрацюванні раціональних дробів багато операцій потребують обчислення спільного знаменника, який є найменшим спільним кратним знаменників двох дробів. Окрім того, інколи виникає потреба визначити найбільший спільний дільник цілих чисел. Тому буде корисним створити функції, які обчислюють НСД (найбільший спільний дільник) та НСК (найменше спільне кратне). Однак, оскільки ці функції не пов‟язані безпосередньо з опрацюванням дробів, є сенс створити окремий заголовний файл, який міститиме оголошення цих двох функцій. Назвемо цей файл mat.h. Його вміст буде таким:

#ifndef matH #define matH

int nsd(int, int);

// Найбільший спільник дільник

int nsk(int, int);

// Найменше спільне кратне

#endif

 

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