ВУЗ: Не указан

Категория: Не указан

Дисциплина: Не указана

Добавлен: 22.12.2021

Просмотров: 183

Скачиваний: 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.


8