- •1 Основні відомості про вказівники
- •2. Вказівники та посилання
- •Void function_a (char*, int, short*);
- •Int *pi; /* вказівник-змінна на дані типу int */
- •3. Ініціалізація вказівника
- •4. Розіменування та присвоєння
- •5. Void-вказівник
- •6. Операція пересування вказівника
- •7. Використання вказівників з модифікатором const
- •8. Деактивації дії модифікатора
- •9. Подвійний вказівник
- •10. Вказівники і масиви
- •11. Доступ до ділянок динамічної пам'яті
- •12. Звільнення пам'яті
- •8. Операції з вказівниками
- •Int I, *pi; /* pi –змінна-вказівник */
- •13. Динамічні масиви
- •11. Посилання
- •Лабораторный практикум
- •Вопросы без ответов
- •3 Основні операції над вказівниками
- •4 Багаторівнева непряма адресація
- •5 Операції над вказівниками
- •Void main ()
- •Void main()
- •6 Проблеми, пов'язані з вказівниками
- •Int *х; /* змінній-покажчику 'х' виділена оп, але 'х' не містить значення адреси оп для змінної */
- •Int *х; /* х - ім'я покажчика, він одержав оп*/
- •Void main ()
- •9 Масиви
- •1.9.1 Основні поняття
- •Int а[5]; /* оголошення зовнішнього масиву */ main ()
- •9.2 Оголошення та звертання в одновимірних масивах
- •9.3 Оголошення та звертання до багатовимірних масивів
- •Int а[3][4]; /* а - вказівник-константа */
- •10 Масиви покажчиків
- •10.1 Робота з великими масивами
- •Void main()
- •Int *p[200], I, j; clrscr() ;
- •10.2 Вільні масиви та покажчики
- •11 Символьні рядки
- •11.1 Основні відомості про представлення рядків
- •11.2 Функції роботи з рядками
- •1. Функції введення рядків.
- •2. Функції виведення рядків.
- •14 Лекція №14
- •14.1 Вказівники Лекція № 2 - Вказівники та посилання
- •1.2.1. Вказівники
- •6. Вказівники і масиви
- •6.1. Вказівники і адреси
- •6.2. Вказівники і аргументи функцій
- •6.3. Вказівники і масиви
- •6.4. Адресна арифметика
- •6.5. Вказівники символів і функції
- •6.6. Вказівники – не цілі значення
- •6.7. Багатовимірні масиви
- •6.8. Масиви вказівників (вказівники на вказівники)
- •6.9. Ініціалізація масивів вказівників
- •6.10. Вказівники і багатовимірні масиви
- •6.11. Командний рядок аргументів
- •6.12. Вказівники на функції
- •Посібник для початківця про вказівники
- •6. Вказівники і структуровані програмні змінні
- •9. Вказівники типу far
- •10. Вказівники і динамічні змінні (керування пам'яттю)
- •9. Вказівники типу far
- •10. Вказівники і динамічні змінні (керування пам'яттю)
- •8. Вказівники і динамічні змінні (керування пам'яттю)
- •Void* operator new(size_t t)
- •Void operator delete(void* p)
- •Void main()
6.12. Вказівники на функції
Самі функції мови С++ не є змінними, але можна визначити вказівник на функцію, яку можна обробляти, передавати іншим функціям, розміщати в масиви і т. ін. Розглянемо програму, яка при заданні необов’язкового аргументу –n сортує рядки чисельно, а не лексикографічно.
Алгоритм сортування складається із трьох частин – порівняння (впорядковує будь-які пари об’єктів), перестановки (змінює порядок об’єктів) і сортування (розміщується об’єкт у потрібному порядку). Алгоритм сортування не залежить від операцій порівняння і перестановки, тому передача в нього різних функцій порівняння і перестановки дозволяє організувати сортування за різними критеріями. Саме такий підхід і використано в програмі сортування (див. ПП6.26 на СD).
Лексикографічне порівняння рядків здійснюється функцією Strcmp, а перестановка – функцією Swap. Функція Numcmp порівнює два рядки на базі числового значення і повертає той умовний вказівник, що й Strcmp. Ці три функції описано в Main і вказівники на них передаються у Sort. Тут Strcmp, Nimcmp і Swap – адреси функцій. Передача адрес функцій організовується компілятором. Модифікація функції Sort реалізовано в програмі (див. ПП6.27. на СD)
Опис
int
(*comp)()
означає, що comp
є вказівником на функцію, яка повертає
значення типу int.
Перші круглі дужки
тут
необхідні, оскільки без них опис int
*comp()
означав би, що comp
є функцією, яка повертає вказівник на
цілі значення. Використання comp
у рядку if
(*comp)(v[j],
v[j
+ gap])
<= 0) повністю відповідає опису, де
comp
– вказівник на функцію, *comp
– сама функція; (*comp)(v[j],
v[j
+ gap])
– звернення до фукції.
Функцію Strcmp, яка порівнює два рядки за першим числовим значенням, реалізовано в програмі ПП6.28. (див. на СD). Функція Swap, яка переставляє два вказівними, реалізована в програмі ПП6.29. (див. на СD).
У C++ існують наступні види вказівників:
1) вказівник на функцію;
2) вказівник на об'єкт;
3) вказівник на void.
Усі ці вказівники відрізняються властивостями і набором припустимих операцій. Вказівник завжди пов'язаний з яким-небудь конкретним типом.
Вказівник на функцію містить її адресу в сегменті коду (тобто адресу, за якою передається керування при виклику функції). Вказівник на функцію використовується для непрямого виклику функції (не через її ім'я, а шляхом звертання до змінної, що зберігає її адресу), а також для передачі функції в іншу функцію як параметр.
Оголошення вказівника на функцію:
тип (*ім'я)(список аргументів);
Приклад
int (*fn)(float,float) – задає вказівник з ім'ям fn на функцію, що повертає значення типу int і має два аргументи типу float.
Приклад програми
#include <iostream.h>
#include <conio.h>
double fx(double x)
{
double y;
y=x*x;
return y;
}
void print_tab(double (*f)(double),float a,float b,float dx)
{
float x;
for (x=a;x<=b;x+=dx)
cout<<x<<'\t'<<f(x)<<endl;
}
void main()
{
clrscr();
cout<<"Таблиця значень функції"<<endl;
print_tab(fx,10,20,0.5);
}
Дана програма містить функцію для виведення на екран таблиці значень функції в заданому діапазоні. Функція, яка буде табулюватися, передається в цю функцію як параметр.
Вказівник на об'єкт містить адресу області пам'яті, у якій зберігаються дані визначеного типу.
Вказівник на об'єкт має вид:
тип *ім'я;
При цьому тип може бути будь-яким, крім посилання.
Зірочка відноситься безпосередньо до імені, тому при оголошенні декількох вказівників потрібно ставити її перед кожним з них.
Приклад:
int *a,*b; – визначає два вказівники на тип int.
Вказівник на void застосовується тоді, коли не визначений тип об'єкта, адресу якого потрібно зберігати в вказівнику. Вказівнику на void можна присвоїти значення вказівника будь-якого типу, а також порівнювати його з будь-якими вказівниками, але перед виконанням яких-небудь дій з областю пам'яті, на яку він посилається, потрібно перетворити його до конкретного типу явно.
Усі величини типу вказівник підкоряються загальним правилам визначення області дії, видимості і часу життя.
Передача вказівників в функції Можливість передавати їх індекси у функції дуже корисна, і її легко освоїти. Якщо нам потрібна програма, яка отримує число і додає до нього п'ять, ми можемо написати щось схоже на цей код:
#include <stdio.h>
void AddFive(int Number)
{
Number = Number + 5;
}
void main()
{
int nMyNumber = 18;
printf("Мій старий номер: %d\n", nMyNumber);
AddFive(nMyNumber);
printf("Мій новий номер: %d\n", nMyNumber);
}
Проте тут проблема в тому, що змінна Number, до якої ми звертаємося всередині функції - це копія змінної nMyNumber, що передається у функцію. Таким чином, рядок Number = Number + 5 додає п'ять до копії змінної, залишаючи оригінальну змінну в main() незмінною. Спробуйте запустити програму, щоб переконатися в цьому. Щоб позбавитися від цієї проблеми, ми можемо передавати у функцію вказівник на місце в пам'яті, де зберігається число, але тоді ми повинні поправити функцію, щоб вона приймала вказівник замість числа. Для цього змінимо void AddFive(int Number) на void AddFive(int* Number) додаванням зірочки. Тут знову текст програми, з внесеними змінами. Зверніть увагу, на те що ми повинні переконатися, що передаємо у функцію адресу nMyNumber замість самого числа. Це зроблено за допомогою оператора &, який (як ви пам'ятаєте), читається як "отримати адресу".
#include <stdio.h>
void AddFive(int* Number)
{
*Number = *Number + 5;
}
void main()
{
int nMyNumber = 18;
printf("Мій старий номер: %d\n", nMyNumber);
AddFive(&nMyNumber);
printf("Мій новий номер: %d\n", nMyNumber);
}
Спробуйте придумати ваш власний приклад, щоб продемонструвати це. Звернули увагу на важливе значення * перед Number у AddFive функції? Це необхідно, щоб повідомити компілятору, що ми хочемо збільшити значення змінної, на яку вказує Number, а не значення самого вказівника. Останнє, на що необхідно звернути увагу відносно функцій, це те, що ви можете повернути з функції значення вказівника, наприклад: int * MyFunction(); В цьому прикладі MyFunction повертає вказівник на ціле число Вказівники на класи Є декілька інших застережень з вказівниками, одним з яких є структура чи клас. Ви можете визначити клас наступним чином:
class MyClass
{
public:
int m_Number;
char m_Character;
};
Потім ви можете визначити змінну типу MyClass наступним чином: MyClass thing; Ви повинні це вже знати. Якщо ні, спробуйте прочитати попередню частину. Щоб визначити вказівник на MyClass, ви повинні використовувати: MyClass *thing; ... як ви могли очікувати. При цьому виділяється частина пам’яті і отриманий вказівник буде вказівником на виділену пам'ять: thing = new MyClass; Тут проблема полягає в тому, як же тоді б ви використовували цей вказівник? Ну, як звичайно, ви б написали thing.m_Number, але ви не можете це зробити з вказівником, оскільки thing не є MyClass, а вказівником на нього. Таким чином, thing сама по собі не містить змінну m_Number, вона являє собою структуру, яка вказує на те, що містить m_Number. Тому ми повинні використовувати різні конвенції. Це замінить .(dot) на -> (тире і потім знак більше). Приклад можете побачити нижче:
class MyClass
{
public:
int m_Number;
char m_Character;
};
void main()
{
MyClass *pPointer;
pPointer = new MyClass;
pPointer->m_Number = 10;
pPointer->m_Character = 's';
delete pPointer;
}
