Покажчики. Частина 1. Загальні поняття. Типи покажчиків. Керовані та некеровані покажчики. Покажчики на функцію. Приклади використання

Покажчики. Частина 1. Загальні поняття. Типи покажчиків. Керовані та некеровані покажчики. Покажчики на функцію. Приклади використання


Зміст



1. Що таке покажчик? Визначення покажчика.

Однією з переваг мови C++ порівняно з іншими мовами програмування є використання покажчиків для доступу до змінної. Також, як відомо, доступ до змінної можна організувати за її іменем.

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

Покажчик – це змінна, яка містить адресу іншої змінної в пам’яті. Наприклад, якщо змінна a містить адресу змінної b, то це означає, що змінна a вказує на змінну b.

2. Які типи покажчиків підтримуються в C++?

В Visual C++ (CLR – Common Language Runtime) підтримуються три типи покажчиків:

  • керовані покажчики (managed pointers);
  • некеровані покажчики (unmanaged pointers);
  • некеровані покажчики на функції (unmanaged function pointers).

3. Яка відмінність між керованими та некерованими покажчиками?

Відмінність між керованими і некерованими покажчиками полягає в наступному:

на відміну від керованого покажчика некерованому покажчику можна присвоїти будь-яку адресу пам’яті, навіть ту, яка знаходиться за межами виконавчого середовища.

У цьому випадку пам’ять є нерегульована.

У випадку регульованої пам’яті керованому покажчику присвоїти адресу за межами виконавчого середовища не вдасться.

4. Що таке покажчики посилального типу або керовані покажчики (managed pointers)?

Керовані покажчики – це покажчики посилального типу. Ці покажчики передаються для аргументів, методів, які передаються за посиланням. Ці покажчики є сумісні з специфікацією Common Language Runtime (CLR). Керовані покажчики є посиланнями на об’єкти. Ці об’єкти розміщуються в загальній керованій пам’яті, яка виділяється для програми в момент її виконання.

У таких покажчиках замість символу * застосовується символ ^. Для виділення пам’яті під керований покажчик використовується утиліта gcnew.

5. Приклад використання керованих покажчиків. Утиліта gcnew та ключове слово ref в Visual Studio C++

В керованих покажчиках утиліта gcnew формує екземпляр деякого об’єкту. Утиліта gcnew виділяє пам’ять для екземпляра об’єкту і повертає посилання на цей об’єкт.

Опис цього об’єкту повинен починатися з ключового слова ref. Ключове слово ref дає інформацію про те, що опис є посилального типу. Загальна форма використання ключового слова ref має вигляд:

ref опис;

Після такого опису пам’ять під об’єкт виділяється з допомогою утиліти gcnew.

Приклад. У прикладі демонструється:

  • опис структури типу BOOK посилального типу, що містить інформацію про книгу;
  • використання ключового слова ref для вказання того, що структура є посилального типу;
  • використання утиліти gcnew для виділення пам’яті під структуру;
  • демонстрація використання керованих покажчиків для оперування об’єктами.

Нехай за межами опису класу описується наступна структура:

ref struct BOOK // ref - означає, що структурає посилального типу
{
    System::String ^ Title;  // заголовок книги
    System::String ^ Author; // прізвище автора книги
    int year;                // рік видання
    float price;             // вартість книги
};

Тоді в методах цього класу можна використовувати структуру BOOK приблизно таким чином:

...

BOOK ^ B; // змінна B є типу "керований покажчик"

B = gcnew BOOK; // виділення пам'яті під структуру

// заповнення полів структури
B->Title = "Title of Book";
B->Author = "Author of Book";
B->year = 1998;
B->price = 399.85f;

...

6. Що таке некеровані покажчики (unmanaged pointers) та некеровані покажчики на функції (unmanaged function pointers)?

Некеровані покажчики – це традиційні покажчики C/C++. Вони є покажчиками на об’єкти в нерегульованому об’ємі пам’яті, що виділяється для виконання програми. Некеровані покажчики не є сумісні зі специфікацією CLR.

Некеровані покажчики на функції – це покажчики на функції, які можна обробляти таким самим чином як і некеровані покажчики на об’єкти (дані).

Особливості використання некерованих покажчиків більш детально описані в наступній темі.

7. Яка загальна форма оголошення некерованого покажчика (unmanaged pointer)? Приклад

Загальна форма оголошення покажчика:

тип_змінної * імя_покажчика;

де

  • тип_змінної – це тип тієї змінної, на яку вказує покажчик. Його ще називають базовий тип покажчика;
  • імя_покажчика – імя змінної-покажчика.

Приклад. Опис покажчиків, які вказують на різні типи змінних.

int * pi; // покажчик з іменем pi на тип int
float * pf; // покажчик з іменем pf на тип float

8. Некеровані покажчики. Операція взяття адреси &. Приклад

Для отримання адреси змінної в пам’яті використовується операція взяття адреси &. Ця операція є унарною. Вона повертає адресу свого операнда в пам’яті.

Приклад операції взяття адреси та використання покажчика для доступу до змінної.

int * pi; // покажчик з іменем pi на тип int
float * pf; // покажчик з іменем pf на тип float
float f;
int i;

i = 8;
pi = &i; // pi вказує на i
*pi = 10; // i = 10

f = 2.93f;
pf = &f; // pf вказує на f
*pf = 8.85f; // f = 8.85

Рисунок 1 схематично показує використання покажчиків для типу int.

C++ покажчик використання рисунок

Рисунок 1. Використання покажчика на тип int

Як видно з рисунку 1, з допомогою покажчика можна отримати доступ до змінної та змінити її значення. У цьому випадку тип, на який вказує покажчик, повинен співпадати з типом змінної.

9. Приклад використання некерованого покажчика на функцію.

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

  • мати однакову кількість та типи аргументів;
  • повертати значення однакового типу.

При оголошенні, покажик на функцію записується наступним чином:

тип * (ім'я_функції) (список_параметрів);

де

тип – тип значення, що повертається функцією.

Приклад. Використання некерованого покажчика на функцію для консольного додатку.

Опис та використання покажчика на функцію з іменем func_ptr, яка отримує два цілочисельних параметри x, y і повертає значення типу double.

Нехай дано 2 функції, які мають однакову кількість параметрів та повертають однакове значення:

// функція, що підносить x в степені y
double Power(int x, int y)
{
    double res;
    res = System::Math::Pow((double)x, (double)y);
    return res;
}

// функція, що ділить x на y
double Div(int x, int y)
{
    double res;
    res = (double)x / (double)y;
    return res;
}

У консольному додатку можна використовувати даний покажчик так:

// описати покажчик на функцію, що отримує 2 параметри типу int
double (*func_ptr)(int x, int y);

double res;

...

// виклик функції піднесення до степеня
func_ptr = Power; //  вказує на Power - піднесення до степеня
res = (*func_ptr)(4,3); // res = 64

// виклик функції ділення чисел через покажчик
func_ptr = Div; // func_ptr вказує на Div
res = (*func_ptr)(4,3); // res = 1.33333333333333

Такий спосіб використання покажчиків на функцію підходить тільки для консольних додатків.

10. Приклад використання керованого покажчика на функцію в середовищі C++/CLI (делегати)

Використання покажчика на функцію в середовищі C++/CLI для додатків, створених за шаблоном Windows Forms. У цьому випадку потрібно використовувати так звані делегати. Делегати підтримуються в .NET Framework.

Нехай дано 2 функції, які мають однакову кількість параметрів та повертають однакове значення:

// функція, що підносить x в степені y
public: double Power(int x, int y)
{
    double res;
    res = System::Math::Pow((double)x, (double)y);
    return res;
}

// функція, що ділить x на y
public: double Div(int x, int y)
{
    double res;
    res = (double)x / (double)y;
    return res;
}

Щоб використати делегат потрібно спочатку в деякому місці класу форми (або іншого класу) дати такий опис:

// опис делегату DelFun, що отримує два параметри типу int
// і повертає значення типу double
public: delegate double DelFun(int , int);

...

Після цього в деякому методі (наприклад, обробнику події кліку на кнопці) можна використовувати цей покажчик наступним чином:

double result;

DelFun ^ PFun = gcnew DelFun(this, &Lab1::Form1::Power);
result = PFun(3,2); // result = 9

PFun = gcnew DelFun(this, &Lab1::Form1::Div);
result = PFun(3,2); // result = 1.5

У вищенаведеному прикладі в рядках

&Lab1::Form1::Power

...

&Lab1::Form1::Div

ідентифікатори мають наступне призначення:

  • Lab1 – назва проекту;
  • Form1 – назва головної форми додатку (ім’я змінної);
  • Power – назва функції.
11. Яка відмінність між покажчиком-змінною та покажчиком-константою?

Покажчик-змінна (покажчик) – це змінна, яка призначена для збереження адреси в пам’яті.

Покажчик-константа – це значення адреси оперативної пам’яті.


Зв’язані теми