- •12. Класи пам'яті даних 100
- •13. Робота з файлами 106
- •14. Посилання 111
- •Склад мови
- •Алфавіт мови
- •Лексеми
- •Ключові слова
- •Ідентифікатори
- •Константи
- •Символьні рядки
- •Знаки операцій, роздільники, коментарі
- •Типи даних
- •Класифікація типів даних
- •Цілочислові типи
- •Дійсні типи
- •Оголошення змінних і констант
- •Переліки
- •Структура програми
- •Функція main
- •Область дії змінної
- •Введення і виведення даних
- •Функції стандартної математичної бібліотеки
- •Вирази і операції
- •Поняття виразу, операнда, операції
- •Порядок виконання операцій
- •Арифметичні операції
- •Порозрядні операції
- •Операції порівняння
- •Логічні операції
- •Операції присвоєння
- •Умовна операція
- •Операція визначення розміру sizeof
- •Узгодження типів у виразах
- •Умовні оператори
- •Оператори
- •Умовний оператор if
- •Оператор вибору switch
- •Оператори циклу
- •Цикл з параметром. Оператор for
- •Цикл з передумовою. Оператор while
- •Цикл з постумовою. Оператор do while
- •Оператори переходу
- •Використання псевдовипадкових чисел
- •Одновимірні масиви
- •Багатовимірні масиви
- •Символьні рядки
- •Вказівники
- •Оголошення вказівника, операції, пов’язані з вказівниками
- •Адресна арифметика
- •Void – вказівники, типізація вказівників
- •Звертання до елементів масивів через вказівники
- •Масиви символьних рядків і масиви вказівників
- •Динамічне виділення пам’яті
- •Структури і об’єднання
- •Оголошення і ініціалізація структур
- •Звертання до елементів структур
- •Перейменування типів
- •Об’єднання
- •Поля бітів
- •Директиви препроцесора
- •Призначення директив препроцесора
- •Директива включення #include
- •Директиви макропідстановок #define I #undef
- •Директиви умовної компіляції
- •Директиви #ifdef, #ifndef
- •Функції
- •Структура функції
- •Виклик функцій. Прототипи функцій
- •Взаємодія фактичних і формальних параметрів функцій
- •Inline – функції
- •Масиви і символьні рядки як параметри функцій
- •Використання кваліфікатора const в оголошеннях параметрів
- •Багатовимірні масиви як параметри функцій
- •Опрацювання структур у функціях
- •Вказівники на функції
- •Рекурсивні функції
- •Класи пам'яті даних
- •Клас пам'яті, час існування і видимість об’єкта
- •Область дії глобальних і локальних змінних
- •Специфікатори класів пам'яті
- •Специфікатори глобальних змінних
- •Багатофайлові програми
- •Робота з файлами
- •Звертання до файлів
- •Послідовний запис до файлу і послідовне читання з файлу
- •Файли з довільним доступом
- •Посилання
- •Призначення посилань
- •Передача аргументів функцій як посилань
Адресна арифметика
Зручність використання вказівників пов’язана з можливістю виконання над ними таких операцій: присвоєння, порівняння, збільшення і зменшення, віднімання. Операції над вказівниками називають адресною арифметикою.
Операції присвоєння, порівняння та віднімання бінарні, обидва операнди цих операцій обов’язково повинні бути вказівниками або адресними виразами з однаковим базовим типом. Операції збільшення чи зменшення значень вказівників можуть бути як унарними (постфіксний або префіксний інкремент або декремент вказівника) і бінарними – збільшення (зменшення) значення вказівника на задану цілочислову величину.
Приклад використання операції присвоєння значень вказівників:
#include <iostream>
using namespace std;
int main() {
int a = 5;
int * p1, * p2;
p1 = &a;
p2 = p1;
*p2 = 123;
cout << a << endl;
}
Над вказівниками (або адресними виразами) можна виконувати всі операції порівняння мови С++. Результатом виконання операції є величина логічного типу. Наприклад:
#include <iostream>
using namespace std;
int main() {
int a = 5, b = 5;
int * p1, * p2;
p1 = &a;
p2 = &b;
if ( p1 == p2 ) // Порівнюємо значення вказівників
cout << "p1 == p2" << endl;
else
cout << "p1 != p2" << endl;
if ( *p1 > *p2 ) // Порівнюємо значення, на які
// посилаються вказівники, тобто а і b
cout << "a > b" << endl;
else
cout << "a <= b" << endl;
}
До значення вказівника можна додавати (чи віднімати від нього) довільне ціле число. Результатом операції збільшення (зменшення) вказівника є нова адреса. Наприклад
#include <iostream>
using namespace std;
int main() {
int a[ 5 ] = { 1, 2, 3, 4, 5 };
int * p;
p = &a[ 0 ]; // Адреса першого елемента масиву
cout << *p << endl; // Виводимо перший елемент масиву
p++; // Адреса другого елемента масиву
cout << *p << endl; // Виводимо другий елемент масиву
}
У попередньому прикладі при виконанні операції p++ значення вказівника буде збільшуватися на sizeof( базовий_тип ), тобто sizeof( int ). Після виконання операції інкремента вказівник буде посилатися на наступне ціле значення в пам'яті, тобто на наступний елемент масиву.
У загальному випадку, при збільшенні (зменшенні) значення вказівника на ціле число k фактично він буде змінюватися на k * sizeof( базовий_тип ) і буде вказувати на інше значення базового типу в пам'яті. Таким чином, величина, яка додається до вказівника або віднімається нього завжди кратна розміру базового типу цього вказівника.
#include <iostream>
using namespace std;
int main() {
int a[ 5 ] = { 1, 2, 3, 4, 5 };
int * p;
p = &a[ 0 ]; // Адреса першого елемента масиву
cout << *p << endl; // Виводимо перший елемент масиву
p += 2; // Адреса третього елемента масиву
cout << *p << endl; // Виводимо третій елемент масиву
}
Операція віднімання виконується над двома вказівниками (або адресами), її результатом є кількість елементів базового типу, які можна розташувати в ділянці оперативної пам'яті, адреси початку і кінця якої задають вказівники. Наприклад
#include <iostream>
using namespace std;
int main() {
int a[ 5 ] = { 1, 2, 3, 4, 5 };
int * p1, * p2;
p1 = & a[ 0 ]; // Адреса першого елемента масиву
p2 = & a[ 4 ]; // Адреса останнього елемента масиву
cout << p2 - p1; // 4 елемента: 0-й, 1-й, 2-й, 3-й
}
Операндом операції звертання за адресою може бути адреса ділянки пам'яті, в якій зберігається значення певного типу. Тип значення в пам'яті буде визначатися базовим типом вказівника. В наступній програмі спочатку обчислюється вираз в дужках, тобто знаходимо адресу четвертого елемента масиву, після цього звертаємося за цією адресою.
#include <iostream>
using namespace std;
int main() {
int a[ 5 ] = { 1, 2, 3, 4, 5 };
int * p;
p = & a[ 0 ]; // Адреса першого елемента масиву
cout << *( p + 3 ); // Виводимо 4-й елемент масиву
}
Всі інші операції, крім перелічених, виконувати над вказівниками не можна: не можна додавати чи множити вказівники, виконувати над ними побітові операції тощо.
