Перейти до вмісту

Вказівник

Матеріал з Вікіпедії — вільної енциклопедії.

Вказівни́к[1], пока́жчик або пока́зник, іноді також посилання[2] (англ. pointer або reference) — тип даних у комп'ютерних мовах програмування, об'єкт програми, що містить адресу в пам'яті комп'ютера іншого об'єкта.

Вказівники разом з операцією їх розіменування (англ. dereference operator) були винайдені Катериною Логвинівною Ющенко в 1955 р.[3] в адресній мові програмування. За термінологією Ющенко розіменування вказівника називалося «штрих-операцією». Закордонні вчені довгий час вважали[джерело?], що вказівники винайшов у 1964-ому році Гарольд Лоусон[en].

Формальний опис

[ред. | ред. код]

У інформатиці вказівник — це різновид посилання, але окремі мови програмування можуть вводити власну інтерпретацію цього поняття.

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

Сукупністю даних (англ. aggregate) є група примітивів, які логічно послідовні в пам'яті і розглядаються сумісно як єдині дані (наприклад, сукупністю можуть бути 3 логічно послідовні байти, значення яких, являє собою 3 координати точки в просторі). Коли сукупність складається з примітивів однакового типу, сукупність називається масивом; у деякому розумінні, багатобайтовий примітив word є масивом байтів, а в деяких програмах він використовується саме так.

У контексті цих визначень, byte є найменшим примітивом; кожна адреса в пам'яті визначає окремий байт. Адреса пам'яті початкового байту даних розглядається як адреса (або базова адреса пам'яті) всієї сукупності даних.

Вказівник на пам'ять (або просто вказівник) це примітив, значення якого за призначенням використовується як адреса пам'яті; це означає що вказівник вказує на адресу пам'яті. Це також означає, що вказівник вказує на дані [у пам'яті], якщо значення вказівника вказує на адресу даних у пам'яті.

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

Посилання служить як вид перенаправлення: значення вказівника визначає яка адреса пам'яті (тобто, які дані) використовуються під час обчислення. Оскільки перенаправлення є фундаментальним аспектом алгоритмів, вказівники часто вважаються фундаментальним типом даних у мовах програмування; у статично (або сильно) типізованих мовах програмування, тип вказівника визначає тип даних, на які посилається вказівник.

Операції з вказівниками

[ред. | ред. код]

Мови програмування, у яких передбачений тип вказівник, містять зазвичай дві основні операції над ними: присвоювання і розіменування. Операція присвоювання записує в значення вказівника певну адресу в пам'яті комп'ютера.

Розіменування вказівника

[ред. | ред. код]

Розіменування є частковим випадком так званої «штрих-операції» адресного програмування.

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

У мові програмування С:

double a = 5; /* оголошення дійсної змінної подвійної точності */
double *pa;   /* оголошення вказівника на дійсну змінну, вираз `double *` визначає тип, `pa` — ім'я вказівника */
pa = &a;      /* присвоєння вказівнику адреси змінної `a`. `pa` тепер вказує на `a` */
*pa = 10;     /* присвоєння значення за адресою, на яку вказує `pа`. `*a` — операція розіменування вказівника */

У результаті змінна a отримує значення 10.

Для пришвидшення обробки абстрактних типів даних багатократне розіменування було апаратно реалізовано як групова операція (з Ф-операцією операція модернізації адрес в ЕОМ «Київ») процесорів низки комп'ютерів: ЕОМ «Київ», «М-20», «Дніпро», сімейств (ВЕЛМ (ВЕЛМ-2, ВЕЛМ-3, ВЕЛМ-3М та ВЕЛМ-4), «Мінськ», «Урал» тощо. Це дозволило отримувати доступ до довільного елемента списку через виконання процесором лише однієї операції: адресації вищих рангів, яка є n-кратним застосуванням операції розіменування вказівника.[джерело?]

Масиви C/C++

[ред. | ред. код]

У мовах програмування C/C++ індексування масивів формально визначено через арифметику вказівників; тобто, специфікація вимагає, щоб array[i] було тотожним *(array + i)[4]. Отже в С/C++ імена масивів можна розглядати як вказівники на початкові елементи масиву, а елементи масиву як послідовні ділянки пам'яті (без прогалин)[4]. Водночас синтаксис для доступу до елементів є тотожним до того, який можна використовувати для розіменування вказівників. Наприклад, масив array можна оголосити і використати так:

int array[5];      /* Оголошуємо 5 суміжних цілих чисел */
int *ptr = array;  /* Масиви можна використовувати як вказівники */
ptr[0] = 1;        /* Вказівники можна індексувати використовуючи синтаксис масивів */
*(array + 1) = 2;  /* Масиви можна розіменовувати, використовуючи синтаксис вказівників */
*(1 + array) = 2;  /* Додавання вказівників комутативне */
2[array] = 4;      /* Оператор індексування комутативний */

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

Ім'я масиву має тип вказівника, але не є вказівником — вказівник містить адресу, масив — елементи масиву. Як наслідок, хоча більшість операторів на масивах і вказівниках тотожні, оператор sizeof повертає для них різні значення. У цьому прикладі, sizeof(array) видасть 5*sizeof(int) (розмір масиву), тоді як sizeof(ptr) видасть sizeof(int*), розмір власне вказівника. Також справедливим є ptr = array але помилковим array = ptr.

Початково масив можна ініціалізувати так:

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

Якщо вважати, що array розташований у пам'яті за адресою 0x1000 на 32-бітній little-endian машині, тоді пам'ять міститиме такі значення (адреси вказані в шістнадцятковій системі):

0 1 2 3
1000 2 0 0 0
1004 4 0 0 0
1008 3 0 0 0
100C 1 0 0 0
1010 5 0 0 0

Представлені тут п'ять цілих: 2, 4, 3, 1 і 5 займають по 4 байти кожне з першим найменш значущим байтом і розташовані послідовно починаючи з адреси 0x1000.

Синтаксис у C/C++ для вказівників такий:

  • array значить 0x1000;
  • array + 1 значить 0x1004;
  • *array значить розіменувати вміст array. Розглядаючи вміст як адресу пам'яті (0x1000), повернути значення за цією адресою (2);
  • array[i]: елемент масиву array з індексом i (індексація починається з нуля).

Нульовий вказівник

[ред. | ред. код]

Нульовий вказівник — це вказівник, який нікуди не вказує. Використовується для того, щоб показати, що дана зміна-вказівник ні на що не посилається. У різних мовах програмування представлений різними константами.

Див. також

[ред. | ред. код]

Примітки

[ред. | ред. код]
  1. Вказівник // Великий тлумачний словник сучасної української мови (з дод. і допов.) / уклад. і гол. ред. В. Т. Бусел. — 5-те вид. — К. ; Ірпінь : Перун, 2005. — ISBN 966-569-013-2.
  2. pointer // Англійсько-український словник з математики та інформатики / уклад. Є. Мейнарович, М. Кратко. — 2010.
  3. Videla, Alvaro (8 грудня 2018). Kateryna L. Yushchenko — Inventor of Pointers. https://medium.com (англ.). A Computer of One’s Own Pioneers of the Computing Age. Архів оригіналу за 23 вересня 2020. Процитовано 30 жовтня 2020.
  4. а б Plauger, P J; Brodie, Jim (1992). ANSI and ISO Standard C Programmer's Reference. Redmond, WA: Microsoft Press. с. 108, 51. ISBN 1-55615-359-7. Тип масиву не містить додаткових дірок, тому що всі інші типи щільно пакуються коли компонуються в масив [сторінка 51]