3. Приклад 2:
int vr = 1;
int* ptr = &vr; // ptr містить адресу змінної vr
Вказівники
Тип Ім’яВказівник - це змінна, значенням якої є
адреса пам'яті, по якому зберігається об'єкт
певного типу (інша змінна).
Приклад 1:
int * p // за адресою, записаному в змінної p,
// Буде зберігається змінна типу int або, іншими словами, p вказує на тип
даних int
4. &отримання
адреси змінної
*отримання
значення змінної
«розіменування»
float a; // Оголошена дійсна змінна a
float * adr_a; // Оголошений покажчик на тип float
adr_a = & a; // Оператор записує в змінну adr_a адресу а
a = * adr_a; // Оператор записує в змінну a значення, що
зберігається за адресою adr_a
Операції з вказівниками
void prim1() // Приклад
{ int a=5, *p;
*p=a;
cout<<"це адреса змінної а "<<p<<" а це її значення "<< *p<<endl;
}
6. Операції над адресами
додавання і віднімання покажчиків з
константою
віднімання одного покажчика від іншого
інкремент
декремент
7. #include <iostream>
using namespace std;
int main ()
{
// Оголошення масиву з 10 елементів
double mas [10] = {1.29, 3.23, 7.98, 5.54, 8.32, 2.48, 7.1};
// Оголошення покажчика на double
double * p1;
// Присвоєння покажчику адреси нульового елемента масиву
p1 = & mas [0];
// Виведення значення нульового елемента масиву
cout << * p1 << endl;
// Збільшення значення адреси на 3 * 8 (розмір типу double) = 24,
// В результаті вказівник зміститься на три позиції розміром double кожна
p1 = p1 + 3;
// Виведення на екран значення третього елемента масиву
cout << * p1 << endl;
system ( "pause");
return 0;
}
Додавання
константи
до
вказівника
8. Різниця двох вказівників
Різниця двох вказівників - це різниця їх значень, поділена
на розмір типу в байтах.
Так, різниця вказівників на третій і нульовий елементи масиву дорівнює трьом, а на
третій і дев'ятий - шести.
Підсумовування двох покажчиків не допускається.
Інкремент переміщує вказівник до наступного елементу
масиву, а декремент - до попереднього:
double * p1;
float * p2;
int * i, n;
p1 ++; // Збільшення значення адреси на 8.
p2 ++; // Збільшення значення адреси на 4.
i ++; // Збільшення значення адреси на 4.
9. Вказівники і масиви
prim4()
{
// Оголошення масиву з 10 елементів
double mas [10] = {1.29, 3.23, 7.98, 5.54, 8.32, 2.48, 7.1};
// Оголошення покажчика на double
double * p1;
// Присвоєння покажчику адреси нульового елемента масиву
p1 = & mas [0];
// Виведення на екран знченія нульового елемента масиву
cout << * p1 << endl;
// Збільшення значення адреси на 3 * 8 (розмір типу double) = 24,
// В результаті зміститься на три елементи , розміром double кожний
p1 = p1 + 3;
// Виведення на екран значення третього елемента масиву
cout << * p1 << endl;
}
10. Вказівники і рядки
void prim5()
{
// Оголошення рядка
char s [] = "Перевірочка";
// Оголошення покажчика на рядок
char * ps;
// Присвоєння покажчику адреси початку рядка
ps = s;
// Виведення на екран значення першої літери (нульового елементу)
cout << s <<* ps << endl;
// Збільшення значення адреси на 2 * 1 (розмір типу char) = 3,
// В результаті зміститься на 2 елементи,
ps = ps + 2;
// Виведення на екран значення третього символа рядка
cout << * ps << endl;
}
11. Операції відношення
До вказівників також застосовуються операції
відношення ==,! =, <,>, <=,> =.
Іншими словами, вказівники можна
порівнювати.
Наприклад, якщо i вказує на п'ятий елемент
масиву, а j - на перший, то ставлення i> j
істинно.
Крім того, будь-який вказівник можна
порівнювати на рівність з нулем.
12. Перетворення типів
#include <iostream>
using namespace std;
int main ()
{
float PI = 3.14159; // Оголошена дійсна змінна PI
float * p1; // Оголошений вказівник на float - p1
double * p2; // Оголошений вказівник на double - p2
p1 = & PI; // Змінній p1 присвоюється значення адреси PI
p2 = (double *) p1; // Вказівником на double присвоюється значення, яке
посилається на тип float
cout << "За адресою p1 =" << p1 << "зберігається * p1 =" << * p1 ";
cout << "За адресою p2 =" << p2 << "зберігається * p2 =" << * p2 ";
system ( "pause");
return 0;
}
13. Завдання на роботу з вказівниками (сума, різниця, порівняння)
Масиви Рядки
14. Посилання
Приклад . #include <iostream>
using namespace std;
int main()
{
int t = 13,
int &r = t; // ініціалізація посилання на t тепер r
синонім імені t
cout << "Початкове значення t:" << t; r += 10; // зміна
значення t через посилання
cout<<"n Остаточне значення t:" << t;
return 0;
}
int &r
Коли ми оголошуємо змінну компілятор автоматично виділяє пам'ять згідно типу змінної:
char C = '$'; // Буде виділена під символьну змінну С,
// І їй присвоєно стартове значення
Доступ до оголошеної змінної здійснюється за її імені. При цьому всі звернення до змінної змінюються на адресу пам'яті, в якій зберігається її значення:
cout << C; // З комірки пам'яті з ім'ям C буде вилучено значення
// І виведено на екран
При завершенні програми або функції, в якій була описана змінна, пам'ять автоматично звільняється.
Ідея роботи з вказівниками полягає в тому, що користувач працює з адресою комірки пам'яті і має можливість динамічно створювати і знищувати змінні.
Над адресами в C ++ визначені наступні арифметичні операції:
додавання і віднімання покажчиків з константою;
віднімання одного покажчика з іншого;
інкремент;
декремент.
Додавання і віднімання покажчиків з константою n означає, що покажчик переміщається по осередках пам'яті на стільки байт, скільки займає n змінних того типу, на який він вказує. Припустимо, що покажчик має символьний тип і його значення дорівнює 100. Результат складання цього покажчика з одиницею - 101, так як для зберігання змінної типу char потрібно 1 байт. Якщо ж значення покажчика дорівнює 100, але він має цілочисельний тип, то результат його складання з одиницею становитиме 104, так як для змінної типу int відводиться 4 байта.
Віднімання двох покажчиків визначає, скільки змінних даного типу розміщується між зазначеними осередками. Ці операції застосовні тільки до покажчиків одного типу і мають сенс в основному зі структурними типами даних, наприклад з масивами.
Фактично виходить, що значення покажчика змінюється на величину sizeof (тип). Якщо покажчик на певний тип збільшується або зменшується на константу, то його значення змінюється на величину цієї константи, помножену на розмір об'єкта даного типу. наприклад:
Якщо покажчики посилаються на різні типи, то при присвоєнні значення одного покажчика іншому, необхідно використовувати перетворення типів
Без перетворення можна привласнювати будь-якому вказівником покажчик void *. Розглянемо приклад роботи з покажчиками різних типів:
В покажчиках p1 і p2 зберігається один і той же адресу, але значення, на які вони посилаються, виявляються різними. Це пов'язано з тим, що покажчик типу * float адресує 4 байта, а покажчик * double - 8 байт. Після присвоювання p2 = (double *) p1; при зверненні до * p2 відбувається наступне: до змінної, що зберігається за адресою p1, дописується ще 4 таких байт з пам'яті. В результаті значення * p2 не збігається зі значенням * p1.
Посилання (reference) являє собою видозмінену форму вказівника, яка використовується в якості псевдоніму (іншого імені) змінної. У зв'язку з цим посилання не потребують додаткової пам’яті. Для визначення посилання використовують символ & (амперсант), який ставитися перед змінною-посиланням.
Змінні типу посилання можуть використовуватися в наступних цілях:
• замість передачі у функцію об'єкта за значенням;
• для визначення конструктора копії;
• для перевантаження унарних операцій;
У даному випадку ми використовували посилання в якості псевдоніму змінної. У цій ситуації воно називається незалежним посиланням (independent reference) і повинно бути ініціалізоване на час оголошення. Такий спосіб використання посилань може призвести до фатальних помилок, які важко виявити через виникнення плутанини у використанні змінних.