
C _Учебник_МОНУ
.pdfТипи користувача |
369 |
for(i=0; i<N; i++)
func(s[i]); // Виклик функції func() для кожного студента cout<<"Масив після змін: "<<endl;
for(i=0; i<N; i++) print(s[i]);
getch(); return 0;
}
Результати виконання програми:
Введіть інформацію про студентів: Прізвище: Іванов Курс: 1 Група: ІМ-1.02 Екзамени:
65
87
50
60
65
Прізвище: Петров Курс: 2 Група: ТС-2.01 Екзамени:
90
90
95
60
65
Масив після змін: Прізвище: Іванов Курс: 1 Група: ІМ-1.02
Екзамени: 65 87 50 60 65
Прізвище: Петров Курс: 2 Група: ТС-2.01
Екзамени: 90 90 95 60 65
Приклад 11.2 Створити структуру для роботи з комплексними числами. До структури повинні входити поля для дійсної й уявної частин комплексного числа, а також функції, які задають операції з комплексними числами: перетворювання на тригонометричну форму і навпаки, обчислення кореня n-го степеня. Написати програму, що використовує описану структуру і обчислює корінь n- го степеня з комплексного числа. Число задавати у вигляді a+ib. Як результат роздрукувати всі n значень кореня n-го степеня у формі a+ib.


Типи користувача |
371 |
Приклад 11.3 Задано дві точки зі своїми координатами. Визначити, яка з цих точок є ближча до початку координат, та обчислити відстань поміж ними.
Текст програми:
void __fastcall TForm1::Button1Click(TObject *Sender) { struct Dec
{ double x, y; };
Dec a1={2.0,1.0}; Dec a2={5.0,6.0}; AnsiString S;
double d1,d2; d1=sqrt(a1.x*a1.x+a1.y*a1.y); d2=sqrt(a2.x*a2.x+a2.y*a2.y);
if(fabs(d1-d2) < 1E-6) S = "Відстані є однакові";
else |
|
|
|
if(d1<d2) S = "Точка |
1 |
є ближча до початку координат" ; |
|
else |
S = "Точка |
2 |
є ближча до початку координат"; |
Memo1->Lines->Add(S);
Memo1->Lines->Add("");
double d= sqrt(pow((a1.x-a2.x),2)+pow((a1.y-a2.y),2)); Memo1->Lines->Add("Відстань між точками дорівнює " +
FloatToStrF(d,ffFixed,15,2));
}
Приклад 11.4 Увести відомості про прізвища і дати народження людей і визначити наймолодшого з них.
Текст програми:
__fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner)
{SG1->RowCount=2;
SG1->Cells[1][0]="Прізвище"; SG1->Cells[2][0]="Дата народження";
}
372 |
Розділ 11 |
struct person
{char priz[15]; char birth[10]; }; person p[10];
int n=0;
// Кнопка “Дописати дані”
void __fastcall TForm1::Button1Click(TObject *Sender)
{if(n>10) { ShowMessage("Переповнення масиву"); return; } strcpy(p[n].priz, Edit1->Text.c_str()); strcpy(p[n].birth, Edit2->Text.c_str()); SG1->Cells[0][n+1]=IntToStr(n+1); SG1->Cells[1][n+1]=AnsiString(p[n].priz);
SG1->Cells[2][n+1]=AnsiString(p[n].birth); n++;
SG1->RowCount++;
}
person young(person p[], int n)
{person max_p=p[0]; for(int i=0; i<n; i++)
if(TDate(max_p.birth) < TDate(p[i].birth)) max_p=p[i]; return max_p;
}
// Кнопка “Наймолодша особа”
void __fastcall TForm1::Button2Click(TObject *Sender) { person max=young(p,n);
Edit3->Text=AnsiString(max.priz)+" "+AnsiString(max.birth);
}
Структури дозволяють описати майже всі навколишні об‟єкти. Однак існують певні винятки. Наприклад, припустімо, що структура person має для чоловіків містити найменування військової спеціальності, а для жінок – кількість дітей. Розв‟язок “у лоба” може мати вигляд
struct |
person |
|
{ date |
birth; |
// Дата народження, |
char |
sex; |
// стать (ч/ж), |
char |
wars[20]; |
// військова спеціальність |
int |
kids; |
// і кількість дітей. |
}; |
|
|
Синтаксично начебто все правильно, але виникає можливість описати чоловіка, який народжував дітей (на жінок-військових ми покищо не зважаємо). Щоб уникнути такого становища, слід оголосити поля wars і kids у такий спосіб, щоб вони не могли мати значення водночас, тобто об‟єднати ці поля в одне ціле. Для цього в С++ існують поєднання (union), які докладніше буде розглянуті у наступному підрозділі:
struct person
{date birth; char sex;
union { char wars[20]; int kids; };
};
Типи користувача |
373 |
При використанні об‟єднань водночас розв‟язується й завдання економії пам‟яті. Однак комп‟ютер не відстежує, яке саме з двох полів, wars чи kids, має існувати даного моменту. Для компілятора водночас існують обидва поля.
11.3 Об’єднання (union)
Об‟єднання – формат даних, який може містити різні типи даних, але лише один тип водночас. Можна сказати, що об‟єднання є окремим випадком структури, всі поля якої розташовуються за однією й тією самою адресою. Формат опису об‟єднання є такий самий як і у структури, лише замість ключового слова struct використовується слово union. Але, тоді як структура може містити, скажімо, елементи типу і int, і short, і double, об‟єднання може міс-
тити чи то int, чи short, чи double: union prim
{int x; short y;
double z; };
Обсяг пам‟яті, яку займає об‟єднання дорівнює найбільшому з розмірів його полів. Об‟єднання застосовують для економії пам‟яті у тих випадках, коли відомо, що понад одного поля водночас не потрібно. Часто об‟єднання використовують як поле структури. При цьому до структури зручно включити додаткове поле, яке визначає, який саме елемент об‟єднання використовується даного моменту:
struct
{int type; union id
{ long id_num; char id_ch[20]; };
} priсe;
. . .
if (priсe.type |
== 1) cin >> priсe.id.id_num; |
|
else |
cin >> |
priсe.id.id_ch; |
Тут структура priсe містить ціле поле type та поле id, яке може набувати лише одне зі значень чи то цілого числа id_num, чи то рядка id_ch залежно від значення поля type. У наведеному прикладі ім‟я об‟єднання можна не зазначати, а звертатися безпосередньо до його полів. У цьому разі об‟єднання є анонімним, його елементи стають змінними, розташованими за однією адресою.
struct
{ int type; union
{long id_num; char id_ch[20];
};
} priсe;
. . .
if(priсe.type == 1) cin >> priсe.id_num; else cin >> priсe.id_ch;

374 |
Розділ 11 |
Приклад 11.5 Створити програму для опрацювання даних про людей: прізвище, ім‟я, стать, а також дівоче прізвище для жінок та ознаку служби в лавах Збройних Сил для чоловіків.
Розв‟язок. У програмі передбачено змінювання вигляду форми залежно від вибору особи статі, дані якої вводитимуться: для жінок виводитиметься вікно Edit3 для введення дівочого прізвища, а для чоловіків – компонент RadioGroup2 для вибору ознаки служби в армії. Програмний код для такої видозміни форми записано у функції відгуку події RadioGroup1Click(), тобто ця програма спрацьовуватиме автоматично при виборі особи статі.
При введенні даних особи жіночої статі вікно форми матиме вигляд
При перегляданні даних вікно форми матиме вигляд
Текст програми: struct osoba
{AnsiString prizv, imja; bool st;
union |
// Об‟єднання може зберігати |
{ char VirgSername[25]; // чи то дівоче прізвище жінки, |
|
bool ArmySrv; |
// чи ознаку служби в Збройних Силах для чоловіків |
} P; |
|
} ; |
|
osoba ch[30]; |
// Масив із 30-ти структур |
int i=0; |
// Кількість введених даних |
Типи користувача |
375 |
//При обиранні статі особи відбуватиметься приховування зайвих компонентів та
//виведення потрібних компонентів для введення відповідних даних
void __fastcall TForm1::RadioGroup1Click(TObject *Sender)
{if(RadioGroup1->ItemIndex==0)
{ch[i].st=0; RadioGroup2->Visible=0; Edit3->Visible=1; Label3->Visible=1; }
else
{ch[i].st=1; RadioGroup2->Visible=1; Label3->Visible=0; Edit3->Visible=0; }
}
//-----------------------------------------------------------
// Кнопка “Ввести дані”
void __fastcall TForm1::Button1Click(TObject *Sender)
{ch[i].prizv=Edit1->Text; ch[i].imja=Edit2->Text; ch[i].st=RadioGroup1->ItemIndex;
if(ch[i].st) ch[i].P.ArmySrv=RadioGroup2->ItemIndex; else strcpy(ch[i].P.VirgSername,Edit3->Text.c_str()); i++;
}
//-----------------------------------------------------------
// Кнопка “Переглянути усі відомості”
void __fastcall TForm1::Button2Click(TObject *Sender)
{SG1->RowCount=i; for(int k=0;k<i;k++)
{SG1->Cells[0][k]=ch[k].prizv; SG1->Cells[1][k]=ch[k].imja; if(ch[k].st)
{SG1->Cells[2][k]="чоловіча"; if(ch[k].P.ArmySrv)SG1->Cells[3][k]="ні";
else SG1->Cells[3][k]="так";
}
else { SG1->Cells[2][k]="жіноча";
SG1->Cells[3][k]=ch[k].P.VirgSername;
} } |
} |
11.4 Перерахування (enum)
При написанні програм часто виникає потреба у визначенні наперед відомої кількості іменованих констант, які мають мати різні значення (при цьому конкретні значення можуть бути неважливими). Для цього зручно користуватися типом перерахування enum, всі можливі значення якого задаються списком цілочисельних констант:
enum [<ім‟я_типу>] {<список_констант>};
Ім‟я типу задається в тому разі, якщо у програмі потрібно визначати змінні цього типу. Змінним перераховного типу можна присвоювати кожне значення зі списку констант, зазначених при оголошуванні типу. Імена перераховних констант мають бути унікальними. Перераховні константи подаються й опра-
376 |
Розділ 11 |
цьовуються як цілі числа і можуть ініціалізуватися у звичайний спосіб. Окрім того вони можуть мати однакові значення. За відсутності ініціалізації перша константа обнулюється, а кожній наступній присвоюється значення на одиницю більше, аніж попередній.
enum week { sat=0, sun=0, mon, tue, wed, thu, fri } rоb_den;
Тут описано перерахування week з відповідною множиною значень і оголошено змінну rоb_den типу week. Перераховні константи sat та sun мають значення 0, mon – значення 1, tue – 2, wed – 3, thu – 4, fri – 5.
До перераховних змінних можна застосовувати арифметичні операції й операції відношення, наприклад:
enum days {sun, mon, tue, wed, thu, fri, sat}; days day1 = mon, day2 = thu;
int diff = day2 – day1;
cout << "Різниця у днях: " << diff << endl; if(day1 < day2)
cout << "day1 настане раніш, аніж day2 \n";
Арифметичні операції над змінними перераховних типів зводяться до операцій над цілими числами. Проте, не зважаючи на те, що компіляторові відомо про цілочисельну форму подання перераховних значень, варто використовувати цей факт надто обережно. Якщо спробувати виконати присвоювання
day1 = 5;
компілятор видасть повідомлення (хоча компіляція відбудеться без помилок). Рекомендовано без нагальної потреби не використовувати цілочисельну інтерпретацію перераховних значень.
Значення перераховним константам можна встановлювати явно, ініціалізуючи їх при оголошенні, причому значення мають бути лише цілими числами, наприклад:
enum {first, second = 100, third};
У цьому разі first за замовчуванням дорівнює 0, а наступні неініціалізовані константи перерахування перевищують своїх попередників на 1. Приміром, third матиме значення 101.
Істотним недоліком типів перерахування є те, що вони не розпізнаються засобами введення-виведення С++. При виведенні такої змінної виводиться не її формальне значення, а її внутрішнє подання, тобто ціле число. Наведемо приклад програми, яким можна скористатись за потреби виведення значень таких змінних у зрозумілому для сприйняття вигляді.
#include <iostream> #include <conio.h> #include <string> using namespace std;
enum day {mon=1, tue, wed, thu, fri, sat, sun}; string dayToString(const day& one)
{ string arr[]={"Monday", "Tuesday", "Wednesday", "Thursday", "Friday","Saturday","Sunday"};
return arr[one-1]; }
Типи користувача |
377 |
day intToDay(int one)
{return static_cast<day>(one); } int main()
{int numb;
cout << " Enter number of day (1,2,3,4,5,6 or 7): "; cin >> numb;
day one = intToDay(numb);
cout << dayToString(one) << '\n';
getch(); return 0;
}
Використаний у функції intToDay() оператор static_cast має такий формат: static_cast < тип > ( вираз )
і перетворює без жодних перевірок відповідності під час виконання програми вираз до зазначеного типу. У нашому разі відбуватиметься перетворення введеної цілої змінної one до перерахованого типу day.
Інші приклади програм із використанням типу enum наведено у підрозд. 13.7 (див. приклади 13.11 – 13.14).
11.5 Множини (Set)
Множина – це група елементів, яка асоціюється з її ім‟ям і з якою можна порівнювати інші величини, щоб визначати їхню належність до цієї множини. В окремих випадках множина може бути порожньою.
Множину в C++ Builder реалізовано як шаблон класу, визначений у заголовному файлі <sysset.h>.
Оголошується множина оператором:
Set <type, minval, maxval> змінні;
Параметр type визначає тип елементів множини, зазвичай типу int, char чи enum. Параметри minval та maxval визначають мінімальне й максимальне значення елементів множини типу unsigned char. Мінімальне значення завжди має бути не менше за 0, а максимальне – не перевищувати 255.
Наприклад,
Set <char, 'A', 'Z'> s1;
оголошує змінну s1 множиною всіх заголовних літер латиниці.
Ініціалізація множини здійснюється за допомогою долучення елемента до множини операцією <<, а вилучення елементів з множини – операцією >>. Наприклад:
s1 << 'A' << 'B' << 'C' << 'Z';
долучає до множини s1 символи 'A', 'B', 'C', 'Z', а операція s1 >> 'B' >> 'C';
вилучає з множини s1 символи 'B', 'C'.
Для переглядання значень, записаних у множині, можна скористатися методом Contains(<значення>), який дає результат true, якщо певне значення записано у множині, і false, – якщо воно є відсутнє у множині.
378 |
Розділ 11 |
Наведений далі приклад показує, в який спосіб можна вивести на екран усі значення, записані у множині:
AnsiString s=""; char c; Set <char, 'A', 'Z'> s1; s1 << 'A' << 'B' << 'Z'; for(c='A'; c<='Z'; c++)
if(s1.Contains(c)) |
s = s + AnsiString(c)+" "; |
Edit1->Text = s ; |
//s = "A B Z" |
Ще один приклад є аналогічний до попереднього, але в ньому у множині записуються цілі додатні числа:
AnsiString s = ""; char c; Set <short int, 0, 200> f; f << 1 << 5 << 19 << 119; f << 114;
for (int i=1; i<=200; i++)
if (f.Contains(i)) |
s += IntToStr(i) + " "; |
Edit1->Text = s ; |
//s = "1 5 19 114 119" |
Окрім розглянутого методу Contains(), існують метод очищення множини Clear()і метод Empty(), який визначає, чи не є множина порожньою (табл. 11.1).
|
|
Таблиця 11.1 |
|
Методи роботи з множинами |
|
|
|
|
Формат методу |
|
Опис |
Set& Clear(); |
|
Очищення заданої множини |
bool Contains(T el); |
|
Перевірка наявності у множині елемента el |
bool Empty(); |
|
Перевірка того, чи не є множина порожньою |
Подані нижче оператори оголошують множину S, елементами якої є дані типу перерахування E: red, yellow, green:
enum E (white, red, yellow, green); Set <E, red, green> S;
Поширені у застосовуванні операції для множин наведені в табл. 11.2.
|
|
Таблиця 11.2 |
|
Операції роботи з множинами |
|
|
|
|
Операція |
Формат |
Опис |
- |
Set operator – (Set& rhs); |
Із заданої множини вилучаються |
-= |
Set operator –= (Set& rhs); |
елементи множини rhs |
* |
Set operator * (Set& rhs); |
Перетин множин, тобто спільні |
*= |
Set operator *= (Set& rhs); |
елементи заданої множини та rhs |
+ |
Set operator + (Set& rhs); |
До заданої множини долучаються |
+= |
Set operator += (Set& rhs); |
елементи множини rhs |
== |
bool operator ==(Set& rhs); |
Еквівалентність і нееквівалентність |
!= |
bool operator!=(Set& rhs); |
двох множин: заданої та rhs |