ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 22.12.2021
Просмотров: 195
Скачиваний: 3
ЗАПИСИ
Запис, або структура, – це об'єднання одного або більш об'єктів (змінних, масивів, покажчиків, інших записів і т.п.). Як і масив, вона є сукупністю даних, але відрізняється від нього тим, що до її компонентів (елементам) необхідно звертатися на ім'я і її різні елементи не обов'язково повинні належати одному типу.
Записи зручно використовувати там, де різноманітні дані, що відносяться до одного і того ж об'єкту, необхідно об'єднувати. Наприклад, учня середньої школи характеризують такі дані: прізвище; ім'я; дата народження; клас; вік.
Оголошення запису здійснюється за допомогою ключового слова struct, за яким йдуть її тип і список елементів, укладених у фігурні дужки. Її можна уявити в такому загальному вигляді:
struct тип{ тип елементу 1 ім'я елементу 1;
………………………………………………….
тип елементу n ім'я елементу n;};
Ім'ям елементу може бути будь-який ідентифікатор. Як і вище, в одному рядку можна записувати через кому декілька ідентифікаторів одного типу. Наприклад:
struct ДАТА { int ДЕНЬ;
int МІСЯЦЬ;
int РІК; };
Нагадаємо, що російські букви використані в ідентифікаторах для кращого сприйняття запису (у мові цього робити не можна).
За фігурною дужкою, що закінчує список елементів, можуть записуватися змінні даного типу, наприклад: struct date{ ...} а, b, с; (при цьому виділяється відповідна пам'ять). При описі без подальшого списку ніякої пам'яті не виділяється, просто задається форма запису. Введене ім'я типу пізніше можна використовувати для оголошення запису, наприклад: struct date day; Тепер змінна day має тип date. При необхідності записи можна ініціалізувати, якщо помістити за оголошенням список початкових значень елементів.
Дозволяється вкладати записи один в інший. Наприклад:
struct УЧЕНЬ { char ПРІЗВИЩЕ [15], ІМ'Я [15];
struct ДАТА ДАТА_НАРОДЖЕННЯ;
int КЛАС, ВІК; } ;
Визначений вище тип ДАТА включає три елементи: ДЕНЬ, MECЯЦ, РІК, що містять цілі значення (int). Запис УЧЕНЬ включає елемент ПРІЗВИЩЕ [15], ІМ'Я [15], ДАТА_НАРОДЖЕННЯ, КЛАС, ВІК, ПРІЗВИЩЕ[15] і ІМ'Я[ 15] – це символьні масиви з 15 компонентів кожен (передбачається, що число букв в прізвищі і імені окремо не перевищує 14; при необхідності це число можна легко збільшити). Змінна ДАТА_НАРОДЖЕННЯ представлена складовим елементом (вкладеним записом) ДАТА (кожній даті народження відповідають день місяця, місяць і рік). Елементи КЛАС і ВІК містять значення цілого типу (int). Після введення типів ДАТА і УЧЕНЬ можна оголосити змінні, значення яких належать цим типам. Наприклад:
struct УЧЕНЬ УЧНІ [50];
Тут визначений масив УЧНІ, що складається з 50 елементів УЧЕНЬ.
У мові СІ дозволено використовувати масиви записів; записи можуть складатися з масивів і інших записів,
Щоб звернутися до окремого компоненту запису, необхідно вказати її ім'я, поставити крапку і відразу за нею написати ім'я потрібного елементу (сформоване таким чином ім'я іноді називають складовим). Наприклад:
УЧНІ [I]. КЛАСС=3;
УЧНІ [I]. ДАТА_НАРОДЖЕННЯ . ДЕНЬ=5;
УЧНІ [I]. ДАТА_ НАРОДЖЕННЯ . МІСЯЦЬ=4;
УЧНІ [I]. ДАТА_ НАРОДЖЕННЯ . РІК= 1989;
Тут перший рядок указує, що І-й учень вчиться в третьому класі, а подальші рядки – його дату народження: 5.04.89. При роботі із записами необхідно пам'ятати, що тип елементу визначається відповідним рядком оголошення у фігурних дужках. Наприклад, масив УЧНІ має тип УЧЕНЬ, РІК є цілим числом і т.д. Оскільки кожен елемент запису відноситься до певного типу, його складове ім'я може з'являтися скрізь, де дозволено використовувати значення цього типу.
Розглянемо приклади програм, що показують, як використовувати записи.
У першій програмі оголошуються запис computer і змінна pibm типу computer. Всі описи і визначення дані перед рядком main( ). Далі буде показано, що в цьому випадку змінна pibm є глобальною. Рядки pibm.model, pibm.mem, pibm.sp викликають звернення до відповідних елементів запису pibm типа computer, яким раніше були привласнені певні значення.
/* Демонстрація запису */
# include <stdio.b>
struct computer { int mem;
int sp;
char model[20];}; /* оголошення запису типу computer, що
складається з трьох елементів: mеm, sp, model */
struct computer pibm= { 512, 1,"ПЭВМ ЕС1840.05”};
/* оголошення і ініціалізація змінної pibm типу computer */
main ()
{
printf(“персональна ЕОМ %s\n\n",pibm.model);
printf(“об'єм оперативної пам'яті-%d К байтів\n”, pibm.mem);
printf("продуктивність-%d млн.операцій в секунду\n”, pibm.sp);
/* виведення на екран значення елементів запису */
}
Результати роботи програми мають вигляд:
персональна ЕОМ ПЕВМ ЕС1840.05
об'єм оперативної пам'яті – 5 12 К байт
продуктивність – 1 млн. операцій в секунду
Друга програма показує використання вкладених записів:
/* Демонстрація вкладених записів */
#include <stdio.h>
struct date { int day;
int month;
int year; };
/* оголошення запису типу date */
struct person { cbar fam[20];
char im[20];
char ot[20];
struct date fl; };
/* оголошення запису типу person; одним з елементів
записи person є запис fl типу date */
main()
{ struct person indl; /*оголошення змінної indl типу person */
printf("вкажіть прізвище, ім'я, по батькові, день,\nмісяць і рік
народження громадянина indl\n”);
scanf(“%s%s%s%d%d%d ", indl.fam, indl.im, indl.ot,
&ind1.f1.day, &indl.f1.month, &indl.f1.year);
/* введення відомостей про громадянина indl*/
printf("\nВідомості про громадянина ind1\n");
printf(“Прізвище, ім'я, по батькові: %s %s %s\n",
indl.fam, indl.im, ind1.ot);
printf(“Рік народження - %d\n", indl. fl. year);
printf("Місяць народження - %d-й\n", ind1.f1.month);
printf(“День народження - %d-й\n", ind1.f1.day);
/* виведення відомостей про громадянина ind1*/
}
Запис типу date (дата) містить три елементи: day (день), month (місяць) з (рік). Запис типу person (людина) містить чотири елементи: fam[20](прізвище im[20] (ім'я), ot[20] (по батькові), f1 (дата народження). Останній з них (f1) – це вкладений запис типу date.
Результати роботи програми:
Вкажіть прізвище, ім'я, по батькові, день,
місяць і рік народження громадянина ind1
Сидоров
Петро
Іванович
3
5
1986
Відомості про громадянина ind1
Прізвище, ім'я, по батькові: Сидоров Петро Іванович
Рік народження – 1986
Місяць народження – 5-й
День народження – 3-й
Третя програма показує використання записів у вигляді елементів масиву pibm. Кожен такий елемент в свою чергу включає такі компоненти: mem (пам'ять), sp (швидкодія), model [20] (модель ЕОМ) :
/* Масиви записів */
#include <stdio.h>
struct computer { int mem, sp;
char model[20]; } pibm[10];
/* оголошення запису типу computer;
оголошення масиву pibm типу computer */
main()
{ int i, j, к, prix;
for(i=0; i<10; i++) {
ргintf(“Введіть відомості про ЕОМ %d і ознаку (0 – кінець;
\n інша цифра - продовження)\n", i);
ргintf(“модель ЕОМ – “);
scanf(“%s”, pibm[i].model);
рrintf("об'єм оперативної пам'яті - ");
scanf(“%d”, &pibm[i].mem);
printf("продуктивність - ");
scanf(“%d”, &pibm[i].sp);
printf(“ознака – “); scanf(“%d”, &priz); k=i;
if(!priz) break;}
/* тут !priz - операція заперечення ознаки priz; break -вихід з циклу for, якщо priz = 0 */
for(i=0; i<10; i++){
printf("\nПро яку ЕОМ ви хочете одержати відомості?\n
( введіть номер від 0 до 9)\n”);
scanf(“%d”, &j);
if ( j>k ) { printf(“Heма відомостей про цю ЕОМ\n ”); continue; }
printf(“ персональна ЕОМ %s\n", pibm[j].model);
printf("об'єм оперативної пам'яті - %d К байтів\n", pibm[j].mem);
рrintf(“продуктивність-%d млн. операцій в секунду\n",pibm[j].sp);
printf("ознака - "); scanf("%d", &priz);
if(!priz) break; }
/* введення відомостей про ЕОМ і занесення в масив pibm
записів типу computer (перший цикл for); виведення на
екран відомостей про ЕОМ (другий цикл for) */ }
Результати роботи програми:
Введіть відомості про ЕОМ 0 і ознака (0 – кінець; інша цифра- продовження)
модель ЕОМ – Zeleron
об'єм оперативної пам'яті – 512
продуктивність – 1
ознака – 1
Введіть відомості про ЕОМ 1 і ознаку (0 – кінець; інша цифра – продовження)
модель ЕОМ – ЕС2000
об'єм оперативної пам'яті – 1024
продуктивність – 1
ознака – 0
Про яку ЕОМ ви хочете одержати відомості?
(Введіть номер від 0 до 9)
2
персональна ЕОМ ЕС2000
об'єм оперативної пам'яті – 1024 До байт
продуктивність – 1 млн. операцій в секунду
ознака – 0
Використання розглянутих програм на практиці навряд чи доцільне. Проте далі, після невеликої модифікації, такі програми можуть виявитися дуже корисними. При цьому масиви записів необхідно організовувати і зберігати у файлах на диску і потім у міру потреби вибирати з них необхідну інформацію.
Унарна операція & дозволяє одержати адресу запису. Припустимо, що задане оголошення:
struct date { int d, m,y; }day;
Тут day – запис типу date, який включає три елементи: d, m і у. Рядок виду struct date *db; встановлює той факт, що db – це покажчик на запис типу date. Тепер для вибору елементів d, m, у запису необхідно використовувати конструкції: (* db).d, (*db).m, (*db).y.
Дійсно, db – адрес запису, * db — сам запис. Круглі дужки тут необхідні, оскільки крапка має вищий, ніж зірочка (*), пріоритет.
Для аналогічних цілей в мові СІ передбачена додаткова операція
-> (два символи А15 і D16). Вона теж вибирає елемент запису і дозволяє представити розглянуті вище конструкції в простішому вигляді: db- >d, db —>m, db —>y. Приклади використання покажчиків на записі і операції - >будут дані далі (див. с.151).
ПОЛЯ І ОБ‘ЄДНАННЯ
Поля і об‘єднання є особливим різновидом записів. Поле — це послідовність сусідніх двійкових розрядів (битий) усередині одного цілого значення. Воно може мати тип signed int або unsigned int і займати від 1 до 16 біт. Поля розміщуються в машинному слові в напрямі від молодших до старших розрядів. Наприклад, запис
struct prim { int a:2; unsigned b:3; int:5;
int с: 1; unsigned d:5; } i, j;
забезпечує розміщення, показане на рис. 41.
Розряди машинного слова
15 |
14 |
13 |
12 |
11 |
10 |
9 |
8 |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
|
|||
D |
с |
Не використовуються |
b |
а |
|
Рис.1 – Структура поля
У полях типу signed крайній лівий біт є знаковим. Наприклад, таке поле шириною 1 біт може тільки зберігати значення -1 і 0, оскільки будь-яка ненульова величина інтерпретуватиметься як -1.
Поля використовуються для упаковки значеннь декількох змінних в одне машинне слово з метою економії пам'яті. У оголошенні полів найчастіше використовується модифікатор unsigned. Вони не можуть бути масивами і не мають адрес, тому до них не можна застосувати унарну операцію & .
Використання полів розглянемо на прикладі такої програми:
/* Демонстрація полів */
#include <stdio h>
struct { unsigned a:l;
unsigned b:l;
unsigned у:1;
unsigned c:2; } f;
/* оголошення змінної f, що містить три
однорозрядних і одне двохрозрядне поле (число,
наступне за двокрапкою, задає кількість розрядів
в полі ) */
main ()
{
int i;
printf(“розмір f =%d байтів\n", sizeof(f));
f.a=f.b=1; /*в поля f.a і f.b записуються одиниці */
for(i=0; i<2; i++) {
f.y=f.a&&f.b;/* обчислюється кон'юнкція f.y змінних f.a i f.b */
printf(“цикл %d; f.y=%d\n”, i, f.y);
f.b=0; } /* в полі f.b записується нуль */
f.c=f.a +!f.b; /*арифметичне складання значення f.a (воно дорівнює
одиниці) і заперечення значення f.b (заперечення нуля
теж дорівнює одиниці); в результаті f.c = 2 */
printf(“f.c=%d", f.c);
}
Оголошення вигляду unsigned а:1; визначає однобітове поле а; у нього можна записати тільки одне з двох значень: нуль або одиницю. Оголошення unsigned c:2, визначає двобітове поле с; у нього вже можна записати одне з чотирьох значень: 0,1, 2 або 3. Функція sizeof(f) дозволяє визначити розмір в байтах одного запису f . Аналогічно з її допомогою можна знаходити і розміри інших об'єктів (змінних, масивів і т.п.).
Звернення до будь-якого поля здійснюється так само, як до елементу запису. Наприклад, f.а – звернення до однобітового поля а.
Результати роботи програми мають вигляд:
розмір f = 2 байти
цикл 0; f.y=1
цикл 1; f.y=0
f.с= 2
Об‘єднання – це деяка змінна, яка може зберігати (у різний час) об'єкти різних типу і розміру. В результаті з'являється можливість роботи в одній і тій же області пам'яті з даними різного вигляду. Для опису об‘єднання використовується ключове слово union (об'єднання), а відповідний синтаксис аналогічний синтаксису записів.
Наступна програма пояснює використання об‘єднань:
/* Демонстрація об‘єднань */
#include <stdio.h>
union r { int ir; float fr; char cr; } z;
/* оголошення об‘єднання z типу r; змінна z достатньо
велика, щоб зберігати найбільший з трьох приведених
типів (тут union – ключове слово об‘єднання */
main()
{ рrintf(“розмір z - %d байтів\n", sizeof(z));
printf("введіть значення z.ir\n");
scanf(“%d%”, &z.ir);
printf(“значення ir = %d\n", z.ir);
рrintf(“введіть значення z.fr\n" );
scanf(“%f", &z.fr);
рrintf(“значення fr =%f\n", z.fr );
printf(“ введіть значення z.сr\n" );
scanf("%ls” &z.cr);
printf("значення cr = %c\n", z.cr);
}
У функції scanf ("%ls", &z.cr); задана специфікація перетворення %ls. Якщо використовувати звичну для одного символу специфікацію %с, то в програму завжди заноситиметься керуючий символ, що відповідає клавіші ВВЕДЕННЯ. Ця клавіша натискалась раніше для введення значення змінної z.fr.
Результати роботи програми мають вигляд:
розмір z = 4 байтів
введіть значення z.ir
7
значення ir : 7
введіть значення z.fr
8.3456678
значення fr = 8.345668
введіть значення z.сr
p
значення cr = р
У мові СІ можна вводити імена для нових типів даних за допомогою ключового слова typеdef (визначити тип). Наприклад, опис typedef int INTEGER; робить слово INTEGER синонімом int. Тепер його можна використовувати в оголошеннях типу, так само як int.
Як приклад розглянемо приведену нижче програму:
/* Приклад визначення типу */
#include <stdio b>
typedef float REAL; /* ім'я REAL робиться синонімом float
(тепер в описах відповідного типу можна
використовувати і float, і BEAL ) */
main()
{ REAL а;
printf( "Ввести значення а\n"),
scаnf(“%f”, &а);
printf(“a=%f”, а);
}
Результати її роботи:
Ввести значення а
9.4567
а= 9.456700
Далі будуть приведені складніші приклади використання опису typedef.