Главная страница Случайная страница КАТЕГОРИИ: АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторикаСоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника |
Адресна арифметика
Якщо p є вказівником, то який би не був тип об’єкта, на який він вказує, операція p ++ збільшує p так, що він вказує на наступний елемент набору цих об’єктів, а операція p += i збільшує p так, щоб він вказував на елемент, віддалений на i елементів від поточного елемента. Ці та аналогічні конструкції формами арифметики вказівників або адресної арифметики мови C++. Проілюструємо можливості мови на прикладі програми розподілу пам’яті. Є дві функції: функція Alloc (n) повертає як своє значення вказівник p, що вказує на першу з n послідовних символьних позицій, які можуть бути використані програмою для зберігання символів; функція Free (p) звільняє зайняту в такий спосіб пам’ять. Отже, керована функціями Alloc і Free пам’ять є стеком або списком, у якому елемент, що вводиться останнім, вилучається першим. Реалізація полягає в тому, щоб функція виділяла відрізки великого символьного масиву (надамо ім’я allocbuf), який є власністю функцій Alloc і Free. Вони працюють із вказівниками, а не з індексами масиву, тому ніякій іншій функції не потрібно знати імен цього масиву. Його можна описати як зовнішній статичний (локальний стосовно вихідного файлу, що містить Alloc і Free) і невидимий за його межами. Іншою потрібною інформацією є, інформація про, яка частина масиву allocbuf уже використана. Для цього використовують вказівник першого вільного елемента – allocp. Коли потрібно функції Alloc виділити місце під n символів, вона перевіряє, чи досить залишилося для цього місця в allocbuf. Якщо так, то Alloc повертає поточне значення allocp (тобто початок вільного блоку), потім збільшує його на n для того, щоб він вказував на наступну вільну область. Функція Free (p) визначає allocp рівним p за умови, що p вказує на позицію всередині allocbuf (див. ПП6.5 на СD). Зазначимо, що вказівник може бути ініційований так само, як і будь-яка інша змінна. Об’єкт null – вираз, який містить адреси визначених раніше даних відповідного типу. Опис static char* allocp = allocbuf; визначає allocp як вказівник на символи і ініціює його так, щоб він вказував на allocbuf, тобто на першу вільну позицію на початку роботи програми. Ім’я масиву є адресою його нульового елемента, що можна записати так: static char* allocp = & allocbuf[0]; За допомогою перевірки if (allocp+n < = allocbuf + allocsize) з’ясовується, чи залишилося досить місця, щоб задовольнити запит на n символів. Якщо достатньо, то нове значення allocp не буде вказувати далі, ніж на останню позицію allocbuf. Якщо запит може бути вдоволено, то Alloc повертає звичайний вказівник. Якщо ж ні, то Alloc повинна повернути деяку ознаку, яка свідчить про те, що більше місця не залишилося. У мові C++ гарантується, що жоден правильний вказівник даних не може мати значення нуль, тому повернення нуля може служити сигналом про ненормальну подію, у цьому випадку про відсутність місця. Однак замість нуля пишемо null (спеціальне значення вказівника). Взагалі цілі числа не можуть присвоюватись вказівникам, а нуль – це особливий випадок. Перевірки if (allocp + n < = allocbuf + aloocsize) і if (p > = allocbuf & & p < allocbuf + allocsize) показують кілька важливих аспектів арифметики вказівників. По-перше, за певних умов вказівники можна порівнювати. Якщо p і q вказують на елементи того самого масиву, то такі відношення, як <, > =, > і т. д., працюють належним чином. Наприклад, p < q справедливо, якщо p вказує на більш ранній елемент масиву, ніж q. Відношення == та! = теж працюють. Довільний вказівник можна порівняти на рівність або нерівність із null. Але ні в чому не можна бути впевненим, якщо використати порівняння під час роботи з вказівниками, які вказують на різні масиви. По-друге, вказівник і ціле число можна додавати і віднімати. Конструкція p + n має на увазі n -й об’єкт за тим, на який p указує в цей момент. Це справедливо, незалежно від того, на який вид об’єктів p повинен вказувати; компілятор сам масштабує n відповідно до опису p розміру об’єктів, які вказують за допомогою p. Наприклад, масштабний множник дорівнює 1 для char, 2 для int і short, Віднімання вказівників теж можливе: якщо p і q вказують на елементи того самого масиву, то p-q – кількість елементів між p і q. Цей факт був використаний для написання варіанта функції StrLen (див. ПП6.6. на СD). Під час опису вказівник p у цій функції ініційований за допомогою рядка s, у результаті чого він вказує на перший символ рядка. У циклі while по черзі перевіряється кожен символ до появи символа кінця рядка ’\0’ (значення 0). Явну перевірку можна опустити, і цикли записати так: while (*p) p++; p вказує на символи, тому оператор p ++ пересуває p щоразу так, щоб він вказував на наступний символ. У результаті вираз p-s обчислює кількість переглянутих символів, тобто довжину рядка. Арифметика вказівників враховує тип змінної. Якби оброблялися змінні типу float, які займають більше пам’яті, ніж змінні типу char, і якби p був вказівником на float, то оператор p ++ пересунув би p на наступне значення типу float. Отже, можна написати інший варіант функції Alloc, яка розподіляє пам’ять для float. Для цього потрібно всюди в Alloc і Free дескриптор char змінити на float. Усі дії з вказівниками автоматично враховують розмір об’єктів. За винятком операцій додавання, віднімання вказівника, цілого числа, віднімання і порівняння двох вказівників уся інша арифметика вказівників є хибною. Заборонено складати два вказівники, множити, ділити, об’єднувати або маскувати, а також додавати до них змінні типу float або double.
|