- •Структурування обчислень на рівні підзадач Блочна організація програм Принцип модульності програм
- •Поняття підпрограми
- •Принцип локалізації
- •Концепція розподілу пам’яті
- •Процедурне програмування Організація підпрограм
- •Механізм передачі параметрів
- •Різновиди підпрограм
- •Покажчики та посилання
- •Способи передачі параметрів
- •Рекурсія
- •Стандартні бібліотечні модулі.
- •Бібліотечні модулі користувача
- •Компіляція модулів
Покажчики та посилання
Поняття покажчика. Покажчик - це змінна, значенням якої є адреса області пам'яті, в якій зберігається певний елемент даних. Зв'язок елемента даних з покажчиком, який вказує на цей елемент, схематично можна представити таким чином:
покажчик елемент даних
адреса
Формат задання адреси:
базис сегмента : зсув,
де базис сегмента – 16-ве число, що визначає адресу початку сегмента ОП (номер 16-байтового блоку, з якого починається сегмент; кратний 16);
зсув – 16-ве число, що визначає зміщення потрібного байта пам'яті відносно початку сегмента.
Наприклад, 000А:001А.
Такий спосіб запису адреси пов'язаний з тим, що в операційній системі DOS вся пам'ять розбита на сегменти, розміри яких не перевищують 64 Кбайт. Для отримання абсолютної адреси система додає до базису сегмента справа шістнадцятковий нуль (це чотири нулі в двійковій системі), а потім складає його зі зміщенням. Таким способом можна адресувати 1 Мбайт пам'яті.
Для зберігання значення покажчика (адреси) необхідно 4 байти ОП: 2 байти – для базису сегмента, 2 байти – для значення зсуву.
Синтаксис оголошення покажчиків різниться у різних мовах програмування. Так у Pascal покажчики оголошуються наступним чином:
^ базовий тип;
Тут знак “^” треба читати як “посилання на ...”.
Наприклад,
var p, ptr : ^real;
w : ^word;
Ініціалізація покажчиків здійснюється у Pascal, зазвичай, за допомогою операції отримання адреси @ або стандартної функції аddr. Наприклад,
var v: word;
p, w : ^word;
...
v := 5;
p := @v;
w := addr(v);
...
Покажчик може отримати в якості початкового значення також пусте посилання nil. Nil - це зарезервована константа, що позначає посилання, яке ні на що не вказує. Її можна присвоювати покажчику на будь-який базовий тип.
Nil вказує на адресу оперативної пам'яті (0000:0000), за якою свідомо не може бути розміщена ніяка інформація.
Звертання до значення, на яке вказує покажчик, здійснюється через розіменування посилання по формату:
покажчик^.
Наприклад,
w ^ := 56;
writeln (‘Значення дорівнює ’, w ^);
Тут w^ означає елемент даних, на який посилається покажчик w:
w w ^
адреса 56
Таким чином, змінна посилається на значення прямо, а покажчик – опосередковано.
У мові С формат оголошення покажчиків має наступний вигляд:
базовий тип *покажчик;
Наприклад,
int *p, number;
float *ptr, *r;
Кожен покажчик повинен бути оголошений своїм символом *.
Ініціалізація покажчиків у С здійснюється з використанням операції отримання адреси & при визначенні покажчика або за допомогою оператора присвоєння. Наприклад,
-
int n;
int *nPtr = &n;
n = 7;
int n, *nPtr;
n = 7;
nPtr = &n;
Покажчик може отримати в якості початкового значення також пусте посилання null. Макрос null, що є константним нуль-покажчиком, визначений в заголовочних файлах stdlib.h, stddef.h та ін.
Звертання до відповідного значення здійснюється по формату:
*покажчик.
Наприклад,
int n, *p;
n = 7;
*p = 9;
cout << “n: “ << n << endl;
cout << “*p: “ << *p << endl;
Дії над покажчиками. Над покажчиками не визначені які-небудь операції, які б давали результат цього ж типу. І це зрозуміло — адже значеннями покадчиків є адреси тих або інших програмних об'єктів в пам'яті комп’ютера. А оскільки мова програмування високого рівня не містить яких-небудь правил щодо розміщення таких об'єктів в пам'яті комп’ютера (це питання вирішується самим транслятором), то неможливо сформулювати які-небудь розумні правила (операції), за допомогою яких в програмі можна було б визначити адресу одного об'єкту за адресами інших об'єктів.
Тому над покажчиками визначені лише операція присвоєння і деякі операції порівняння.
Особливості реалізації оператора присвоєння. Для присвоєння значення покажчику використовується оператор присвоєння наступного формату:
покажчик := посилальний вираз;
де посилальний вираз задає посилальне значення того ж типу, що і покажчик (посилається на програмні об'єкти того ж типу). При цьому як посилальний вираз може використовуватися:
-
покажчик;
-
функція, значенням якої є покажчик;
-
порожній покажчик (nil, null).
Розглянемо приклад на мові Pascal. Нехай у програмі описані наступні покажчики:
var p,w :^word;
Прослідкуємо зміни їх значень і значень відповідних змінних з покажчиками в результаті послідовного виконання наступних операторів присвоєння :
p^ := 3;
w^ := 58;
p := w;
w := nil;
Для наочності отримані при цьому результати представимо у вигляді схеми (рис. 1).
Рис. 1. Зміна значень покажчиків при виконанні дій
Слід звернути увагу, що в даному прикладі після виконання оператора присвоєння р:= w на об'єкт із значенням 3 не вказує жоден покажчик, тобто він став недоступним для програми. З іншого боку, в результаті виконання цього ж оператора присвоєння не утворюється новий об'єкт із значенням 58, а покажчик р починає посилатися на вже існуючий об'єкт (на який посилається і покажчик w).
Важливо чітко розуміти різницю між покажчиком і значенням об'єкту, на який посилається даний покажчик. Так, якщо замість оператора р:= w у попередньому прикладі виконати оператор р^:= w^, то отримаємо наступний результат (рис. 2):
Рис. 2. Приклад присвоєння значень елементам даних за допомогою покажчиків
Порівняння покажчиків. Над покажчиками визначено дві операції порівняння: = (дорівнює) і ≠ (не дорівнює). Оскільки машинні адреси по суті справи є цілими числами, то над покажчиками можна було б визначити і інші операції порівняння (<, , >, ), але у цьому немає необхідності, оскільки при формулюванні алгоритму нема сенсу використовувати інформацію про те, який з двох програмних об'єктів розташований ближче до початку (кінця) пам'яті, а який далі.
Два покажчика вважаються рівними, якщо вони обидва є порожніми посиланнями або вказують на один і той же об'єкт — у всіх останніх випадках має місце нерівність покажчиків. Наприклад,
var p, w : ^word;
begin
...
if p=nil then w:= p;
...
end;
У мові С можна виводити адреси комірок пам’яті. Відповідні значення виводяться у 16-му вигляді. Наприклад,
#include <iostream.h>
main( )
{ int n, *nPtr;
n = 7;
nPtr = &n;
cout<<“Адреса n:“<<&n<<endl<<“Значення nPtr:“<<nPtr<<endl;
cout<<“Значення n:“<<&n<<endl<<“Значення *nPtr:“<<*nPtr<<endl;
}
Посилання. Посилання – це псевдонім (інше ім’я) змінної. Для нього не резервується місце в ОП. Формат оголошення псевдоніма:
базовий тип &псевдонім.
Кожен псевдонім повинен бути оголошений своїм символом &.
Посилання повинно бути ініціалізоване при його оголошенні. Наприклад,
int n = 5;
int &p = n, x = 3, &y = x;
Як тільки посилання оголошується як псевдонім іншої змінної, всі операції, що виконуються із посиланням, насправді виконуються із самою змінною.