Тема 7 Структури

Лекція 22

 

 Використання структур

 

Структура — це сукупність різнотипних елементів, яким присвоюється одне ім’я (воно може бути відсутнім), що займає одну ділянку пам’яті. Елементи, що складають структуру, на­зиваються полями.

Змінна типу структура, як і будь−яка змінна, повинна бути описана. Цей опис складається з двох кроків: опису шаблону (тобто складу) або типу структури та опису змінних структур­ного типу.

Синтаксис опису структури має вигляд:

 struct [<ім’я структури>]

{ <тип 1> ім’я поля 1; 

  <тип 2> ім’я поля 2 . . .;

} р1, р2 . . .;

де struct — службове слово;

  <ім’я структури> — ім’я типу структура (може бути відсутнім);

  <тип 1>, <тип 2> — імена стандартних або визначених типів;

  ім’я поля 1, ім’я поля 2,… — імена полів структури;

  р1, р2 . . .; — імена змінних типу структура.

Наприклад, для знаходження середнього бала, отриманого студентами в період сесії з дисциплін «Математика», «Фізика» та «Програмування», визначимо таку структуру:

struct stud

{ char fam [25];            // ПІП

int mat, fiz, prg;          // предмети

float sb;                    // середниій балл 

st1, st2;

Змінні st1 і st2 можна оголосити окремим оператором, наприклад:

struc stud stl st2;.

Ініціювання полів структури слід здійснювати або при її описі, або в тілі програми. При описі структури ініціювання полів виглядає, наприклад, так:

struct stud 

{ char fam [25]; 

int mat,fiz, prg;

float sb;

}

st1 = {"Кравченко Н. С.", 4, 5, 5};

st2 = {"Тесленко А. М.", 3, 4, 5};

Якщо ініціювання виконується в тілі програми, то для звер­нення до імені поля треба спочатку записати ім’я структурної змінної, а потім ім’я поля. Ці обидва записи відокремлюються крапкою і являють собою складене ім’я.

Отже, у випадку появи змінної st1 у програмі для її ініцію­вання можна записати stud st1 = {“Кравченко Н. С.”, 4, 5, 5}; або ініціювання виконується за допомогою складених полів. Роз­глянемо ілюстраційну програму:

#include <iostream.h>

#include <string.h>

#include <stdio.h>

#include <conio.h>

main ( )

{ struct stud     //−−−−−−−−−−−−−−−−−−−− опис структури

  { char fam [20]; 

    int mat, fiz, prg;

    float sb;

  } st1, st2;

  strcpy (st1.fam, "Кравченко Н. С."); 

  st1 .mat = 4;

  st1 .fiz = 5;

  st1 .prg = 5;

  st1.sb = float (st1.fiz + st1.mat + st1.prg)/3;

  st2 = st1; 

  puts (st2.fam);      //−−−−−−−−−−−−−−−− вивід прізвища

  cout << st2.mat << st2.fiz << st2.prg << st2.sb << endl;

  getch();     //затримка екрану

}

У наведеній програмі організується присвоювання всім по­лям структури st1 відповідних значень. Слід зауважити, що поле st1.fam одержує значення шляхом застосування функції strcpy (st1.fam, “Кравченко И. С.”);. Структурна змінна st2 того ж типу, що і st1, тому справедлива операція st2 = st1;.

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

struct 

{ char fam [25];

  int mat, fiz, prg;    

  float sb;

} stl, st2;

Коли при описі структур у деякій функції або в межах ви­димості змінних у різних функціях є багато (але не всі) одна­кових полів, то їх слід об’єднати в окрему структуру. Її можна застосовувати при описі інших структур, тобто поля структури можуть самі бути типу struct. Це називається вкладеністю структур — її можна використати, наприклад, якщо треба обробляти списки студентів та викладачів університету. Студентські списки містять дані: прізвище та ініціали, дата (день, місяць, рік) народження, група та середній бал успішності, а в списках викладачів присутні такі дані: прізвище, ініціали, дата народження, кафедра, посада. У процесі обробки списку студентів і списку викладачів можна оголосити відповідно такі структури:

 

struct stud                     

{ char fio [25];              

  int den, god;                     

  char mes [10];                 

  char grup;                        

  flout sb; } 

struct vykl
{ char fio [25];
int den, god;
char mes [10];
char kaf, dolg;
}

В оголошених типах однакові поля можна об’єднати в ок­рему структуру і застосовувати її при описі інших типів. Поетапно це виглядає так:

struct spd

{ char fio [25];

int den, god;

char mas[10]; }

struct stud

{ spd dr;

char grup;

float sb}

st1, st2;

struct vykl

{ spd dr;

char kaf [10];

char dolg [15];

} pr1, pr2;

У структурах stud і prep для оголошення поля, що містить дані про прізвище і дату народження, використовується раніше описаний тип spd. Тепер до поля fio, den, god, mes можна звер­нутися, використовуючи запис st1.dr.fio, наприклад, при зверненні до функції введення:

gets (st1.dr.fio);

або    gets (pr1.dr.fio);.

Після оголошення структурного типу змінних для роботи з їхніми полями можна застосовувати і покажчики, тоді опис структури матиме вигляд:

struct stud

{ char fam [25]; 

  int mat, fiz, prg;  

  float sb;

} st1, *pst;

Доступ до полів може здійснюватися двома способами:

з використанням операції розіменування «*», тобто

gets ((*pst).fam);    (*pst).fiz = 5;

з використанням покажчика *−>*, наприклад,

gets (pst −> fam);      pst−> fiz = 5; тощо.

Крім того, до полів змінної st1 можна звертатися, вказую­чи поля через операцію «.», як це робилося раніше.

Дані типу структура можна об’єднати в масиви, тоді для розглянутого вище ілюстраційного прикладу з урахуванням кількості студентів, структуру можна записати так:

struct stud

{ char fam [20];

  int mat, fiz, prg;

  float sb;

} spis[15], *sp = &spis[0];.

У випадку, коли масив описується десь у тексті програми, тобто не саме після опису структури, його можна оголосити у вигляді: stud spis [15];масив типу структура з імям stud, що містить відповідну інформацію про групу із 15 студентів.

Доступ до елементів масиву типу структура здійснюється із застосуванням індексу або через покажчик−константу, яким є ім’я масиву, тобто одним з таких способів:

strcpy (spis[1].fam, ” “);

spis[1].fiz = 5;

або

strcpy ((sp + 1) −> fam, ” “);

(sp + 1) −> fiz = 5;

або

strcpy ((*(spis + 1)).fam, ” “);

(*(sp + 1)).fiz = 5;.

У останньому виразі (*(spis + 1)).fiz = 5; потрібна зовнішня пара дужок, тому що операція «.» («крапка») має пріоритет вище, ніж операція розіменування «*».

Поля структури можуть також бути масивами. Наприклад, у розглянутій структурі stud можна оцінки з різних предметів об’єднати в масив. Тоді структуру слід описати у вигляді:

struct stud1

{ char fam [25]; 

int pred [3]; 

float sb 

} spis[15], *ps = &spis[0];.

Звернення до полів здійснюватиметься одним із способів:

((*ps).fam)

(ps−>pred [0]),

наприклад,

gets ((*ps).fam);

       сіn >> ps −> pred[0] >> ps −> pred[1] >> ps −> pred[2];

або   сіn >> ps −> *(pred + 0) >> ps −> *(pred + 1) >> ps −> *(pred + 2).

Доцільно також зазначити, що бібліотека stdlib.h містить спеціальні функції для пошуку та сортування структурних змінних.

Розглянемо використання структурного типу на прикладах.

Приклад Увести в комп’ютер відомість успішності групи сту­дентів, які здали сесію з дисциплін «Математика», «Фізика» і «Програмування», та обчислити:

середній бал кожного студента;

середній бал групи за кожним предметом;

вивести на екран прізвища відмінників з програмування.

Розглянемо перший варіант реалізації постав­леної задачі, що може мати вигляд:

// Р8_1_ 1.СРР — обробка відомості успішності групи студентів

 

//−−−−−−−−−−−−−−−−−−−−−−−−використання даних типу структура

 

#include <iostream.h>

#include <string.h>

#include <conio.h>

void main()

{ const n = 5;     //n — кількість студентів 

int і

float sm, sf, sp;

/* sm, sf.sp — сумма оцінок групи відповідно по матиматиці, физиці, програмуванню */

struct stud

{ char fam[25];  

int mat, fiz, prg; 

float sb;

} ved[n];       //ved[n] — масив студентів (відомість)  

sm = sf = sp = 0; 

//−−−− ввод и обробка інформації про студентів і їх успішність

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

{ cout <<"*** Введіть інформацію про "<< (i+1) << " студента\n";  

{ cout<<<<"Введіть прізвище і ініціали\n";   

gets(ved[i]. fam);   

cout <<"Оцінки по матим., физиці и програм.\n";    

cin >> ved[i].mat >> ved[i].fiz >> ved[i].prg;//−−−−−−−−−−−−−−−−−−−−− средній бал студента за сесію   

ved[i].sb = (float(ved[i].mat + ved[i].fiz + ved[i].prg))/3;//−−−−−−−−−−−−−−−−−−−−− сумування оцінок в групі по предметах   

sm += ved[i].mat;    

sf += ved[i].fiz;    

sp += ved[i].prg; 

}

}

//−−−−−−−−−−−−−−−−−−−−− вивід результатів

cout << ''\n******* Результати сесії\n";

cout.precision(3);

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

cout<<i+1<< " "<< ved[i].fam << " матем. = " << ved[i].mat << " физика = "<< ved[i].fiz << "програм. = " <<ved[i].prg << " ср. балл = " << ved[i].sb << "\n";

cout << "\n\nСередній балл групи по матиматиці = "<< sm/n; 

cout << "\nСередній балл групи по физиці = "<< sf/n;

cout << "\nСередній балл групи по програмуванню = "<<sp/n;

cout << "\n\n***** Відмінники по програмуванню: \n"; 

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

if (ved[i].prg == 5) cout << ved[i].fam <<"\n"; 

getch ();

}