Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Posibnyk_C.doc
Скачиваний:
23
Добавлен:
03.11.2018
Размер:
1.56 Mб
Скачать

2.3 Прості змiннi

Змiннi можуть приймати значення констант вiдповiдного типу. Iм’я змiнної позначають за допомогою iдентифiкатора, який являє собою набiр букв латини, цифр i символа пiдкреслювання. Перші версії мови С дозволяли використовувати лише 8 символів для побудови ідентифікаторів, стандарт С90 – до 31, а С99 – до 63. Iм’я повинно починатися з букви або символа підкреслювання. Проте, не варто захоплюватися ні одним, ні двома символами підкреслювання на початку слова, це не буде помилка, але сучасні операційні системи та компілятори С використовують їх для утворення службових слів, тому не слід додавати їм зайвої роботи. Іноді може статися конфлікт імен.

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

З метою запобігання помилок не бажано включати в імена букву l (ель), бо вона подібна на цифру 1 (один). Також, не слід використовувати букви верхнього регістру (великі), хоча вони й дозволені. Практично всі компілятори C розрізняють великі й малі букви, тому два однакові імена, в яких хоча б одна буква відрізняється типом регістру, сприймаються як різні. Не можна будувати імена за допомогою двох слів, розділених пробілом, це – помилка. Не можна, також, використовувати службові слова мови, такі, наприклад, як for, float та інші. Не варто вживати зарезервовані ідентифікатори, наприклад, імена стандартних функцій (printf(), exit(), system() і т. д.), хоча вони й дозволені.

Нижче подано декілька прикладів імен змiнних. Допустимі імена: nafta, dolar_231, syla_strumu, typ_dolota, suma_minus_22, kut_fi, pi, omega, a, x1, aa23c, plast_tysk, t_nafty. Недопустимі імена: Нафта, $231, syla strumu, typ#dolota, suma-22, φ, ω, float, else.

2.4 Оголошення даних

У програмі мовою С оголошенню підлягають іменовані об’єкти: змiннi, масиви, функції, структури, об’єднання, вказiвники, дані перерахункового типу, типи, теги і класи. Не всі об’єкти потребують оголошення, наприклад, на відміну від мови Pascal, С не потребує оголошення міток. Тип кожного об’єкта повинен бути явно оголошеним за допомогою спецiальних описувачiв, які визначають базовий тип даного, клас пам’ятi та модифiкатор. Оголошення можна виконати на внутрiшньому рiвнi (блок) або на зовнiшньому (програмний модуль). Змінні, оголошені на внутрішньому рівні, є локальними, тобто їх час життя та область дії обмежується блоком. На зовнішньому рівні оголошуються глобальні змінні, їхній час життя та область дії поширюються на модуль.

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

Базовi типи даних. Вiд базового типу даних залежить об’єм пам’ятi, який вони займають. Граничні значення змінних відповідних типів визначені в бібліотеках: limits.h, float.h, stdint.h. Специфiкатори базових типiв показанi в таблицi 2.3.

Таблиця 2.3 – Базові типи даних

Тип

Назва типу

Об’єм пам’ятi, байт

char

Символьний

1

int

Цiлий

2

short

Cкорочений (цілий)

2

long

Подовжений (цілий)

4

unsigned

Беззнаковий (цілий)

2

unsigned char

Беззнаковий символьний

1

unsigned short

Беззнаковий короткий (цілий)

2

unsigned long

Беззнаковий довгий (цілий)

4

float

Пересувний

4

double

Подвiйний

8

long double

Подвiйний довгий

10

До перечислених у таблиці 2.3 стандарт С90 додав тип void – порожній, він застосовується там, де зазвичайно повинні знаходитися якісь дані, але в даному випадку вони відсутні. Стандарт С99 додав типи: long long – подвійний довгий (цілий тип для систем, які працюють з 8-байтовою адресацією), _Bool – логічний, _Complex – комплексний та _Imaginary – уявний.

Нагадаємо, що тут розглядається стандарт мови С. Окремі версії мови можуть мати свої власні типи та займати інший об’єм пам’яті. Тоді мова С набуває ширших, але не вужчих, ніж у стандарті, можливостей. Зокрема, практично всі сучасні компілятори надають типу int об’єм пам’яті не 2, а 4 та навіть 8 байт.

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

int k, j;

long double x1;

char c;

float x, y;

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

int k=3, j=25;

char p, s='я';

Тут оголошені дві змінні типу int: k та j, які під час оголошення одержать значення відповідно 3 та 25. Далі оголошені дві змінні типу char, з яких змінна p не буде ініціалізована, та – s, яка прийме значення літери кирилиці “я”.

Залежно від характеру зберігання в пам’яті комп’ютера дані, позначені перечисленими тут типами, можна поділити на два сімейства: цілі і дійсні. Розглянемо тип char, він означає літеру, текст. Але в пам’яті зберігається не буква, а її ASCII-код (ASCII – American Standart Code for Information Interchange – американський стандартний код обміну інформацією). Цей код охоплює цілі додатні числа від 0 до 127, його застосовують для зберігання в пам’яті всіх символів вищеописаного алфавіту мови С. За його допомогою можна закодувати 128 символів, для цього достатньо 7 біт, але відводиться 8 біт, тобто цілий байт, який дозволяє кодувати до 256 символів. Враховуючи цю можливість, більшість систем використовують розширені ASCII-коди, де додано символи, наприклад, букви кирилиці.

Слід, однак, зауважити, що, оскільки багато наборів символів перевищує 256 значень (наприклад, японські ієрогліфи), існують також інші системи кодування, зокрема Unicod, яка складає більше 96000 символів. В цих системах тип char займатиме 16, 32 або більше біт. Компілятори, які забезпечують такі типи char у межах цього посібника не розглядаються.

Програмісти часто використовують тип char для зберігання малих чисел від 0 до 255. Наприклад, змінну c, яка приймає значення букви 'a' латини, можна оголосити двома способами: char c='a'; або char c=97; В обох випадках змінну c можна застосовувати у виразах як число цілого типу, яке тут дорівнює 97. Додамо, що ASCII-код букви 'a' дорівнює 97, коди решти малих букв латини зростають на одиницю в алфавітному порядку. Коди букв від '0' до '9' починаються з 48, їх можна застосувати для перетворення коду одноцифрової букви в однорозрядне число, віднявши від коду число 48. Наприклад, код букви '3' дорівнює 51, тоді число 3 дорівнюватиме 51-48.

Застосування типу char є неефективним у тих системах, де довжина адресованої комірки складає 2 та більше байт, бо використовується лише один байт, а решта вільні. Тому деякі компілятори дозволяють записувати в одну велику комірку (наприклад, 8 байт) по декілька літер.

Ціле число типу int – це число, яке не має дробової частини. Вище вже говорилося про те, що константи цілого типу можна представити в програмі в різних системах числення, та незалежно від цього в пам’яті вони будуть зберігатися тільки в двійковій, тобто компілятор перекладе кожне ціле число в двійкову систему числення. Візьмемо, наприклад, число 11. У 8-й системі числення воно дорівнює 013 (1*81+3*80=11), у 16-й – 0xВ (В= десятковому 11). Після перекладу в двійкову систему числення воно дорівнюватиме 1011 (1*23+0*22+1*21+1*20=11). Якщо воно буде записано в двобайтову (16-бітову) комірку пам’яті, то прийме такий вигляд: 0000 0000 0000 1011, тобто старші розряди числа будуть доповнені нулями. Якщо це число буде від’ємним (-11), то в комірці пам’яті найстарший двійковий розряд дорівнюватиме одиниці, а число матиме вигляд: 1000 0000 0000 1011 (у знакорозмірному представленні).

Тип short застосовується в тих випадках, коли приходиться працювати з невеликими числами, за рахунок його застосування можна зекономити пам’ять.

Комірка пам’яті типу long удвічі довша за int, але лише в 16-розрядних комп’ютерах. У 32-розрядних обидва типи: int і long можуть займати по 4 байти, а тип short – 2 байти.

Як бачимо, мова С має аж п’ять цілих типів даних: char, short, int, long та long long. Їх явно забагато, але виникли вони в процесі розвитку обчислювальної техніки і свого часу себе оправдали. Тип long long дозволяє обробляти цілі числа ± 9 223 372 036 854 775 807. Це вже дуже широкий діапазон, тому можна надіятися, що розвиток систем у напрямку зростання розрядності чисел на цьому зупиниться.

Заслуговуть на увагу беззнакові типи (unsigned). Візьмемо, наприклад, тип unsigned (тобто unsigned int, якщо int не вказано, то воно приймається за замовчуванням). У два байти пам’яті можна помістити максимально можливе додатнє число 216 - 1 = 65535. Але знаковий тип використовує перший біт для знака, якщо число від’ємне, то в цьому біті буде записана одиниця, інакше – 0. Тому знаковий тип міститиме лише ±215-1 = ±32767, тобто в два рази менше додатнє або від’ємне число. За замовчуванням приймається саме знаковий тип. За рахунок використання типу unsigned змінна може містити вдвоє більше, правда лише додатнє, число. Цей приклад демонструє особливі властивості мови С, програмісту надається можливість економити пам’ять, навіть хоча б один біт.

Типи float, double і long double призначені для дійсних чисел, тобто таких, що складаються з цілої та дробової частин. Між собою вони відрізняються тим, що займають різні об’єми пам’яті. Незалежно від форми представлення (з фіксованою чи пересувною крапкою) кожне дійсне число зберігається у двійковій системі числення, а, оскільки під час перекладу числа в двійковий код іноді відкидаються молодші розряди, то втрачається його точність. Покажемо це на прикладі. Нехай під мантису числа 0,3 буде відведено 16 розрядів. У двійковій системі числення воно дорівнює 0,(0100), тобто маємо періодичний дріб. Тоді в пам’ять буде записано лише 0100010001000100, решта молодших розрядів будуть втрачені, тому воно буде представляти менше за 0,3 десяткове число. Те саме може статися також із цілим числом. Нехай число дорівнює 3,0. У нормалізованому вигляді та представлене в формі з пересувною крапкою воно має вигляд 0,3*101, тобто має таку ж мантису, як у розгляненому вище прикладі. Таким чином, число 3, записане в комірку пам’яті типу float, може не дорівнювати числу 3 типу int. Слід, однак, зауважити, що існує ціла низка прийомів для розробки таких компіляторів, де подібна ситуація контролюється і практично не виникає.

Для запам’ятовування логічних даних типу _Bool достатньо одного біта, де 0 означатиме false, 1 – true, хоча в залежності від розрядності комп’ютера цей тип займе декілька байт.

Класи пам’ятi. Мова С передбачає використання таких специфiкаторiв класiв пам’ятi: extern, static, auto i register. Специфiкатори static i extern застосовуються на зовнiшньому (в окремому модулi, файлi) або внутрiшньому (в блоцi) рiвнi, auto i register – тiльки на внутрiшньому. Оголошення класу extern означає, що така змiнна буде визначена (iнiцiалізована) в iншому мiсцi (модулi) програми, а також, що вона може бути доступною (використаною) до визначення. Змiнну класу static компiлятор iнiцiалiзує нулем, якщо її значення не задано явно пiд час оголошення. Значення змiнних класу static зберiгаються в пам’ятi пiсля виходу з того блоку, де вони оголошенi, i можуть бути повторно використанi. Змiннi класу extern i static помiщаються в сегмент статичних даних програми, auto – в стек, register – у вiльнi регiстри мiкропроцесора, якщо це можливо (є вiльне мiсце). Якщо в оголошеннi функцiй клас не вказаний, то за замовчуванням мається на увазi extern, для iнших даних – auto.

Таблиця 2.4 – Класи пам’яті

Клас пам’ятi

Область дiї

Час життя

extern

програмний блок

програмний блок

static зовнiшнiй

модуль (файл)

програмний блок

static внутрiшнiй

блок

програмний блок

auto

блок

блок

register

блок

блок

Вiд класу пам’ятi залежить час життя i область дiї даних, це показано в таблицi 2.4.

Приклади опису з вказанням класу: extern a; auto int i; Тут оголошенi двi змiннi, змiнна a має клас пам’ятi extern, це означає, що вона буде ініціалізована в iншому програмному модулi, її можна використовувати протягом часу виконання всiєї програми, за замовчуванням їй присвоєно тип int. Змiнна i має тип int, вона доступна лише в тому блоцi, де оголошена. Після завершення виконання цього блоку (виходу з нього) об’єм пам’яті, який займала ця змінна буде звільнений і може бути зайнятий іншою змінною.

Модифiкатоpів є декiлька, вони перечислені нижче.

const, volatile, restrict.

Змiнна типу const не може бути змiнена в процесi виконання програми. Модифiкатор volatile протилежний за змiстом, вiн повiдомляє компiлятор, що ця змiнна може бути змiнена в будь-який момент програмою, пристроєм вводу-виводу або з порта, тому для виразiв, де вона є, не потрiбно застосовувати методи оптимiзацiї, а саму змiнну не слiд завантажувати в машиннi регiстри. Приклад застосування модифікатора:

const float pi=3.1415926;

Тут оголошена змінна pi типу float, під час оголошення задано її значення 3.1415926, яке не може бути зміненим під час виконання програми. У випадку спроби його змінити компілятор видасть помилку.

Кваліфікатор restrict доданий стандартом С99, він застосовується до вказівників, що вказують на об’єкти (наприклад, масиви даних), якими зайняті області пам’яті гарантовано не перекриваються іншими даними.

cdecl, pascal, asm, fortran.

Цi модифiкатори дозволяють компонувати програму з модулiв, написаних рiзними мовами. Модифiкатор cdecl застосовується для оголошення функцiї, написаної мовою С i означає, що вона може бути викликана з програми мовою Паскаль. Модифiкатори pascal, asm i fortran означають, що iдентифiкатори змiнних або функцiй, які мають цi модифікатори, знаходяться в програмах, написаних мовами вiдповiдно Паскаль, Асемблер чи Фортран.

near, far, huge.

Ці модифікатори призначені для використання переважно в ранніх версіях мови С які працювали з 16-розрядними комп’ютерами. За їх допомогою можна задавати модель пам’ятi, вiдмiнної вiд обраної компiлятором малої моделi (small), якщо вона явно не вказана.

Архiтектура мiкропроцесорiв, починаючи з типiв 8086/8088, передбачала розбиття оперативної пам’ятi на сегменти об’ємом по 64 Кбайт. При цьому адреса об’єкта, що там знаходиться, складалася з одного машинного слова довжиною 2 байти (стандартно) для задання змiщення вiдносно початку сегмента. Вживаючи модифiкатори, можна було зайняти декiлька сегментiв (вийти за межі одного сегмента), але тодi адреса складатиметься з двох слiв сумарною довжиною 4 байти, оскiльки вказується ще й адреса сегмента, що спричинить збiльшення об’єму пам’ятi та часу виконання програми. Задаючи відповідну модель пам’яті, програміст мав можливість економити ресурси комп’ютера.

Застосування модифiкаторiв для одержання рiзних моделей пам’ятi показано в таблицi 2.5.

Таблиця 2.5 – Моделі пам’яті

Модель пам’ятi

Модифiкатор для

Об’єм команд

Об’єм даних

Об’єм масивiв

функцiй

даних

tine

все в одному сегментi до 64 Кбайт

small

near

near

64 Кбайт

64 Кбайт

до 64 Кбайт

medium

far

near

до 1 Мб

64 Кбайт

до 64 Кбайт

compakt

near

far

64 Кбайт

до 1 Мб

до 64 Кбайт

large

far

far

до 1 МБ

до 1 Мб

до 64 Кбайт

huge

far

huge

до 1 МБ

до 1 Мб

до 1 Мб

Приклад застосування модифiкатора: char huge a[100000]. Тут оголошено масив а символьного типу, кожний елемент масиву займає 1 байт, а весь масив – 100 000 байт пам’яті. Оскільки довжина сегмента дорівнює лише 64 Кбайти, то масив виходить за його межі, тому вимагається модель пам’яті huge.

Зауважимо, що сучасні комп’ютери мають 4-байтову (32-розрядну), а найновіші – 8-байтову адресацію. Тому відпадає необхідність в обмеженні об’єму пам’яті для даних та функцій різними моделями пам’яті. Разом з тим, в експлуатації ще знаходиться значна кількість комп’ютерів та програм, в яких використовувалася 16-розрядна адресація, тому застосування модифікаторів може бути вигідним.

В оголошенні необхідно вказати хоча б щось одне: базовий тип, клас або модифікатор. Якщо базовий тип явно не оголошений, то за замовчуванням приймається int (крім стандарту С99).

Мова С дозволяє виконувати ініціалізацію змінних під час їх оголошення, наприклад, вираз float x=23.456; означає, що під час компіляції програми змінній x буде виділена пам’ять довжиною 4 байти і туди буде записано число 23,456. За замовчуванням змінна x матиме клас пам’яті auto, а модель пам’яті small.

Тип даних можна змінювати в ході виконання програми. Нехай, наприклад, маємо такі оголошення змінних:

int n=48, k, s, w;

char c='a', b='2', d;

float p=35,64;

Тоді після виконання операторів присвоєння:

k=p;

s=c;

w=b;

d=n;

матимемо такі значення:

k=35 – дробова частина числа буде втрачена;

s=97 – ASCII-код букви 'а' шрифтом латини;

w=50 – ASCII-код символа '2';

d='0', бо ASCII-код символа '0' дорівнює 48.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]