Студопедия

КАТЕГОРИИ:


Архитектура-(3434)Астрономия-(809)Биология-(7483)Биотехнологии-(1457)Военное дело-(14632)Высокие технологии-(1363)География-(913)Геология-(1438)Государство-(451)Демография-(1065)Дом-(47672)Журналистика и СМИ-(912)Изобретательство-(14524)Иностранные языки-(4268)Информатика-(17799)Искусство-(1338)История-(13644)Компьютеры-(11121)Косметика-(55)Кулинария-(373)Культура-(8427)Лингвистика-(374)Литература-(1642)Маркетинг-(23702)Математика-(16968)Машиностроение-(1700)Медицина-(12668)Менеджмент-(24684)Механика-(15423)Науковедение-(506)Образование-(11852)Охрана труда-(3308)Педагогика-(5571)Полиграфия-(1312)Политика-(7869)Право-(5454)Приборостроение-(1369)Программирование-(2801)Производство-(97182)Промышленность-(8706)Психология-(18388)Религия-(3217)Связь-(10668)Сельское хозяйство-(299)Социология-(6455)Спорт-(42831)Строительство-(4793)Торговля-(5050)Транспорт-(2929)Туризм-(1568)Физика-(3942)Философия-(17015)Финансы-(26596)Химия-(22929)Экология-(12095)Экономика-(9961)Электроника-(8441)Электротехника-(4623)Энергетика-(12629)Юриспруденция-(1492)Ядерная техника-(1748)

Структури




Масиви

Посилання

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

Формат оголошення посилання:

тип & ім'я;

 

де тип - це тип величини, на яку вказує посилання, & - оператор посилання, що означає, що наступне за ним ім'я є ім'ям змінної типу посилання, наприклад:

іnt kol;

int & pal = kol; // посилання pal - альтернативне ім'я для kol

const char & CR = ' \ n ': // посилання на константу

 

Для посилання діють наступні правила:

· Змінна-посилання повинна явно ініціалізуватися при її описі, крім випадків, коли вона є параметром функції, описана як extern або посилається на поле даних класу.

· Після ініціалізації посиланню не може бути присвоєна інша змінна.

· Тип посилання повинен збігатися з типом величини, на яку воно посилається.

· Не дозволяється визначати вказівники на посилання, створювати масиви посилань і посилання на посилання.

 

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

Посилання, на відміну від вказівника, не займає додаткового простору в пам'яті і є просто іншим ім'ям величини. Операція над посиланням приводить до зміни величини, на яку вона посилається.

Масив - це впорядкований скінченний набірданих одного типу, які зберігаються в послідовно розташованих комірках оперативної пам'яті і мають спільну назву. З оголошення масиву компілятор одержує інформацію про тип елементів масиву та їх кількість.

Для роботи з масивом його елементи індексуються (нумеруються), а доступ до них здійснюється за допомогою операції взяття індексу. В мові С++ індексація масивів починається з 0, тому елемент із індексом 1 насправді є другим елементом масиву, а індекс першого дорівнює 0. Індекс може бути цілим числом або цілим виразом. Якщо в якості індекса використовується вираз, то спочатку обчислюється вираз, щоб визначити конкретний елемент масиву з яким буде виконуватись робота.

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

int b[3] = {3, 2, 1}; // аналогічно присвоєнням: b[0]=3; b[l]=2; b[2]=l;

 

Якщо початкових значень меньше, ніж елементів в масиві, то елементам, що залишились автоматично надаються нульові початкові значення. Наприклад, елементам масиву b можна присвоїти нульові початкові значення за допомогою оголошення

int b[12] = {3, 2, 1};

 

яке явно надає початкові значення першим трьом елементам масиву і неявно надає нульові початкові значення решті дев’яти елементам, оскільки початкових значень меньше, ніж оголошено елементів масиву.

Однак, по замовчуванню автоматично масив не отримує нульові початкові значення неявно. Треба присвоїти нульові початкові значення хоча б першому елементу для того, щоб автоматично були обнулені всі решта елементів, наприклад:

int b[5] = {0}; // аналогічно присвоєнням: b[0]=0; b[l]=0; b[2]=0; b[3]=0; b[4]=0;

 

Синтаксичною помилкою буде задання в списку більшої кількості початкових значень, ніж є елементів в масиві. Наприклад, оголошення масиву

int b[5] = {5, 4, 3, 2, 1, 0};

 

призведе до синтаксичної помилки, оскільки список ініціалізації містить 6 початкових значень, а масив має тільки 5 елементів.

Використання ідентифікатора масива в програмі еквівалентно використанню адреси його першого елемента. Прохід по масиву можна здійснювати за допомогою індексів або за допомогою вказівників.

Незважаючи на те, що в мові С++ вбудована підтримка для типу даних "масив", вона досить обмежена. Фактично є можливість доступу тільки до окремих елементів масиву. Мова С++ не підтримує абстракцію масиву, не існує операцій над масивами в цілому, таких, наприклад, як присвоєння значень одного масива іншому або порівняння двох масивів на рівність. Замість цього потрібно програмувати такі операції за допомогою циклів поелементно.

В мові С++ також використовуються багатовимірні масиви, при оголошенні яких необхідно вказувати праву границю кожного виміру в окремих квадратних дужках. При звертанні до елементів багатовимірного масиву необхідно вказувати індекси для кожного виміру.

Багатовимірні масиви можуть отримувати початкові значення в своїх оголошеннях так само, як і одновимірні масиви. При ініціалізації багатомірного масиву він представляється як масив масивів, при цьому кожен масив знаходиться у своїх фігурних дужках (у цьому випадку ліву розмірність при описі можна не вказувати). Наприклад, двовимірний масив b[2][2] можна оголосити і надати йому початкові значення наступним чином:

int b[][2]={{1, 2},{3, 4}}; //аналогічно присвоєнням: b[0][0]=1; b[0][l]=2; b[1][0]=3; b[1][1]=4;

 

Якщо початкових значень в деякому підрядку не вистачає для їх присвоєння всім елементам рядка масиву, то всім решта елементам рядка, що залишились, присвоюються нульові початкові значення. Наприклад, оголошення

int b[2][2] = {{1, }, {3, 4}};

 

буде означати, що b[0][0] отримує початкове значення 1, b[0][1] отримує початкове значення 0, b[1][0] отримує початкове значення 3 і b[1][1] отримує початкове значення 4.

Якщо зі списку початкових значень забрати всі фігурні дужки навколо кожного підрядка, то компілятор автоматичнонадасть перші початкові значення елементам першого рядка масиву, а наступні – елементам другого рядка масиву. Наприклад, оголошення

int b[2][3] = {1, 2, 3, 4, 5};

 

містить 5 початкових значень. Початкові значення присвоюються першому рядку матриці:

b[0][0] = 1; b[0][1] = 2; b[0][2] = 3;

 

решта – другому рядку. Довільні елементи, що не мають явно заданих початкових значень, автоматично отримують нульові початкові значення. Отже:

b[1][0] = 4; b[1][1] = 5; b[1][2] = 0;

 

Багатовимірні масиви компілятор розглядає як послідовність одновимірних, тому до елементів такого масиву, як і для одновимірних, можна також звертатись через вказівники.

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

В пам'яті комп'ютера елементи масиву з першого до останнього запам'ятовуються в послідовних зростаючих комірках пам'яті. Між елементами масиву в пам'яті розриви відсутні. Елементи масиву з найменшим індексом зберігаються по найменшій адресі пам’яті. Розмір пам’яті, що відводиться для зберігання масиву, обчислюється за формулою:

 

Memory = кількість елементів масиву * розмір одного елемента

 

Багатовимірні масиви в пам'яті комп'ютера зберігаються так, що найбільш правий індекс збільшується першим.

 

 

Приклад 8.

Розглянемо двовимірний масив цілих чисел:

іnt mass [3][2]= { {1, 1}, {0, 2}, {1, 3} };

 

В пам’яті комп’ютера він зберігається у такому виді:

 

00000001 00000000 00000000 00000000 00000001 00000000 00000000 00000000 00000000

 

mass [0][0] mass [0][1]

00000000 00000000 00000000 00000010 00000000 00000000 00000000 00000001 00000000

 

mass [1][0] mass [1][1]

00000000 00000000 00000011 00000000 00000000 00000000

 

mass [2][0] mass [2][1]

 

Масив може бути ініціалізований рядковим літералом. Рядковий літерал - рядок символів, що знаходиться у подвійних лапках. От приклади рядкових літералів:

"Program"

"5"

"" // порожній рядок

 

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

"a multі-lіne \

strіng lіteral sіgnals іts \

contіnuatіon wіth a backslash"

 

Спеціальні символи можуть бути представлені своїми escape-послідовностями, наприклад:

"\nCC\toptіons\tfіle.[c]\a\n"

 

Якщо в тесті програми йдуть підряд два або декілька рядкових літералів, то компілятор з'єднує їх в один рядок. Наприклад, текст "two" "some" породить рядок символів "twosome".

Фактично рядковий літерал являє собою масив символьних констант, в якому останнім елементом завжди є спеціальний символ з кодом 0 (\0). Наприклад, символьний літерал 'A' задає єдиний символ А, а рядковий літерал "А" - масив із двох елементів: 'А' і \0 (порожній символ).

Символи рядка запам'ятовуються в окремих байтах пам'яті. Символ нуль є відміткою кінця рядка. Він невидимий у рядковому виразі, але він додається як останній елемент, коли рядок запам'ятовується.

Якщо спеціфікується розмір масиву, а рядок містить більше символів ніж специфікований розмір, то зайві символи відкидаються. Наприклад, у прикладі char code[3] = "abcd" тільки три перші символи будуть належати масиву code. Символ d і символ з кодом 0 будуть відкинуті.

Якщо рядок коротший, ніж специфікований розмір масиву, то елементи масиву, що залишилися, ініціалізуються нулем (символом \0).

 

Приклад 9.

Розглянемо символьний рядок:

char my[] = "Lab-1";

В пам’яті комп’ютера він зберігається в 6 байтах у такому вигляді:

0100 1100 0110 0001 0110 0010 0010 1101 0011 0001 0000 0000

 

my[0] = 'L' my[1] = 'a' my[2] = 'b' my[3] = '-' my[4] = '1' признак кінця рядка

На відміну від масиву, всі елементи якого однотипні, структура може містити елементи різних типів. В мові C++ структура є видом класу і має всі його властивості, але в багатьох випадках доситатньо використовувати структури так, як вони визначені в мові С:

 

struct [ім'я_типу] {

тип_1 елемент _1:

тип_2 елемент _2;

тип_n елемент _n;

} [ список_оголошень ];

 

Елементи структури називаються полями структури і можуть мати будь-які типи, крім типу цієї ж структури, але можуть бути вказівниками на неї. Якщо відсутнє ім'я типу, то повинен бути заданий список оголошень перемінних, вказівників або масивів. В цьому випадку опис структури служить визначенням елементів цього списку, наприклад:

struct {

char fіo[30];

int date, code;

double salary;

} clerk, staff[100], *people; // визначення змінної типу структура, масиву

// структур і вказівника на структуру

Якщо список відсутній, опис структури визначає новий тип, ім'я якого можна використовувати надалі поряд зі стандартними типами, наприклад:

 

struct worker {

char fіo[30];

int date, code;

double salary;

}; // опис закінчується крапкою з комою

 

worker clerk, staff[100], *people; // інший спосіб визначення змінної типу струк-

// тура, масиву структур і вказівника на структуру

Ім'я структури можна використовувати відразу після його оголошення (визначення можна дати пізніше) в тих випадках, коли компіляторові не потрібно знати розмір структури, наприклад:

struct Lіst;. // оголошення структури Lіst

struct Lіnk{

Lіst *p; // вказівник на структуру Lіst

Lіnk *prev. *succ; // вказівник на структуру Lіnk

}:

struct Lіst { / * визначення структури Lіst * / };

 

Це дозволяє створювати зв'язані списки структур.

Для ініціалізації структури значення її елементів перелічують через кому у фігурних дужках у порядку їхнього опису:

struct{

char fio[30];

int date, code;

double salary;

}worker = {"Іваненко", 31, 215, 1400.55};

 

При ініціалізації масивів структур треба брати у фігурні дужки кожен елемент масиву:

struct complex{

float real, іm;

} compl [2][3] = {

{{1,1}, {1,1}, {1,1}}, // рядок 1, тобто цє масив compl[0]

{{2,2}, {2,2}, {2,2}} // рядок 2. тобто це масив compl[1]

};

 

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

Доступ до полів структури виконується за допомогою операцій вибору: "." (крапка) - при звертанні до поля через ім'я структури і "->" - при звертанні через вказівник, наприклад:

worker clerk, staff[100], *people;

...

clerk. fіo = "Іваненко";

staff[8].code = 215;

people ->salary = 1400.55;

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

struct А {іnt а; double х;};

struct B {А а; double х;} х[2];

х[0].а.а = 1;

х[1].х = 0.1;

Як видно з прикладу, поля різних структур можуть мати однакові імена, оскільки в них різна область видимості. Більше того, можна оголошувати в одній області видимості структуру та інший об'єкт (наприклад, змінну або масив) з однаковими іменами.

В пам'яті комп’ютера під кожний елемент структури виділяється визначений відповідно до типу цього елемента об’єм памяті. Елементи в пам'яті зберігаються в тому ж порядку, в якому вони були представлені в описі структури.

Розмір змінної структурного типу не можна обчислити просто як суму його елементів, тому що змінні певних типів мають вирівнюватись в пам'яті комп’ютера по деяким залежним від реалізації границям, наприклад, повинні бути вирівняні по границі слова. Це може призводити до "дірок" в структурі. Значення в таких "дірках" невизначені. Навіть якщо значення двох змінних одного й того ж структурного типу дійсно рівні між собою, то не обов’язково, що при порівнянні вони виявляться рівними один одному, оскільки малоймовірно, що невизначені "дірки" містять однакові значення. Отже, порівняння структур є синтаксичною помилкою через різні вимоги по вирівнюванню в різних системах.

 

Приклад 10.

Розглянемо структуру:

struct ех{

double d;

char k[5];

struct koor { int x, y;} ab;

bool b;

char c;

} rec = {2,"my",{4,5},true,'9'};

Визначимо представлення в пам'яті комп’ютера окремо кожного поля:

 

1). Представлення дійсної змінної: double d = 2;

2 10 = 2,0 10 = 2,0 16 = 0010, 0000 2

Нормалізація: 001, 0 0000 * 20001

Мантиса: m=0 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 000

Зміщений порядок: е = 102310 + 110 = 1024 10 = 400 16 = 100 0000 0000 2

Знак: s=0

Зборка за схемою:

 

1біт 11 біт 52 біта
s e m
  100 0000 0000 0 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 000

 

В 16- ковій системі числення:

0 100 0000 0000 0 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 000 2 =

4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 16

В пам’яті комп’ютера буде зберігатися у зворотному порядку розміщення байт числа. Результат в 16- ковій системі числення: 00 00 00 00 00 00 00 40

 

2). Представлення символьного рядка: char k[5] = "my";

В пам’яті комп’ютера він зберігається в такому вигляді:

0110 1101 0111 1001 0000 0000 0000 0000 0000 0000

 

my[0] = 'm' my[1] = 'y' my[2] = '\0' my[3] = '\0' my[4] = '\0'

код символа: код символа: признак признак признак

10910 = 6D16 12110 = 7916 кінця рядка кінця рядка кінця рядка

Результат в 16- ковій системі числення: 6D 79 00 00 00

 

3). Представлення структури: struct koor { int x, y;} ab = {4,5};

Додатнє число 4 типу int в пам'яті комп’ютера зберігається в прямому двійковому коді і займає 4 байти: 410 = 416 = 01002 0000 0000 0000 0000 0000 0000 0000 0100

В пам’яті комп’ютера цілі числа зберігаються у зворотному порядку розміщення байт числа:

0000 0100 0000 0000 0000 0000 0000 0000

Результат в 16-ковій системі числення: 04 00 00 00.

Додатнє число 5 типу int в пам'яті комп’ютера зберігається в прямому двійковому коді і займає 4 байти: 510 = 516 = 01012 0000 0000 0000 0000 0000 0000 0000 0101

В пам’яті комп’ютера цілі числа зберігаються у зворотному порядку розміщення байт числа:

0000 0101 0000 0000 0000 0000 0000 0000

Результат в 16-ковій системі числення: 05 00 00 00.

Отже, структура в пам’яті комп’ютера зберігається в такому вигляді: 04 00 00 00 05 00 00 00

 

4). Представлення логічної змінної: bool b = true;

В пам’яті комп’ютера змінна b зберігається як така послідовність біт: 0000 0001.

В 16-ковій системі числення: 01

 

5). Представлення символьної змінної: char c = ’9’;

За системою ASCIІ: символ ’9’ має порядковий номер 5710 = 3916 = 001110012

Отже, цей символ в пам’яті комп’ютера буде представлений як послідовність 0011 1001.

В 16-ковій системі числення: 39

Елементи в пам'яті зберігаються в тому ж порядку, в якому вони були представлені в описі структури: представлення дійсної змінної (sizeof(double) = 8 байт), далі представлення символьного рядка (sizeof(char k[5]) = 1 * 5 = 5 байт), далі представлення структури типу koor (sizeof(koor) = 4 * 2 = 8 байт), далі представлення логічної змінної (sizeof(bool) = 1 байт), далі представлення символьної змінної (sizeof(char) = 1 байт).

Сумування довжин всіх полів: 8 + 5 + 8 + 1 + 1 = 23 байта. Насправді, довжина структури sіzeof (ех) дорівнює 32 байта, а не 23 байта, як можна було б очікувати. Причина цього полягає в тому, що деякі поля певних типів вирівнюються в пам'яті комп’ютера по границі слова (або подвійного слова, або півслова):

вирівнювання вирівнювання по довжині

double d char k[5] по довжині слова struct koor bool char подвійного слова

00 00 00 00 00 00 00 40 6D 79 00 00 00 CC CC CC 04 00 00 00 05 00 00 00 01 39 CC CC CC CC CC CC

└ 1 слово ┘└ 2 слово ┘ └ 3 слово ┘└─ 4 слово ─┘└ 5 слово ┘└ 6 слово ┘└─ 7 слово ─┘└─ 8 слово ─┘

 

Отже, остаточно, структура rec в пам’яті комп’ютера в 16-ковій системі числення зберігається в 32 байтах в такому вигляді:

00 00 00 00 00 00 00 40 6D 79 00 00 00 CC CC CC 04 00 00 00 05 00 00 00 01 39 CC CC CC CC CC CC

 

В процесі програмування неминуче виникає проблема економії простору пам'яті.

На рівні типів даних є два способи вирішення цієї проблеми:

1) розміщення в байті більше одного невеликого об'єкта;

2) використання одного й того ж простору для зберігання різних об'єктів у різний час.

Першого можна досягти за допомогою використання бітових полів, другого - через використання об'єднань




Поделиться с друзьями:


Дата добавления: 2014-01-05; Просмотров: 481; Нарушение авторских прав?; Мы поможем в написании вашей работы!


Нам важно ваше мнение! Был ли полезен опубликованный материал? Да | Нет



studopedia.su - Студопедия (2013 - 2024) год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! Последнее добавление




Генерация страницы за: 0.105 сек.