- •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.5. Вказівники символів і функції
Рядкова константа, як, наприклад, рядок «Київ» є масивом символів. Компілятор завершує внутрішнє подання такого масиву символом ’\0’ так, що програми можуть знаходити його кінець. Отже, довжина масиву в пам’яті виявляється на одиницю більшою від кількості символів між подвійними лапками (” ”).
Очевидно, найчастіше рядкові константи з’являються як аргументи функцій, як наприклад у printf (”Привіт, Київ\n”). Доступ до символьного рядка в програмі здійснюється за допомогою вказівника символів, тобто функція printf одержує вказівник символьного масиву.
Звичайно, символьні масиви не зобов’язані бути тільки аргументами функцій. Якщо описати змінну message як char *message; то в результаті виконання оператора message = "реальний час"; змінна message стане вказівником на фактичний масив символів. Це не копіювання рядка, оскільки використовуються тільки вказівники. У мові C не передбачені будь-які операції для обробки рядка символів як цілих значень.
Розглянемо функцію Strcpy(s,t), яка копіює рядок t у рядок s. У програмі використаємо масиви (див. ПП6.7 на СD). Ця ж програма, але з використанням вказівників, реалізована як ПП6.8. (див. на СD). Аргументи передаються за значенням, тому функція Strcpy може використати s і t так, як вона побажає. Вказівники пересуваються по масивах (по одному елементу за крок), доти, доки не буде скопійовано в s завершальний в t символ ’\0’.
Інший варіант реалізації функція Strcpy реалізовано як ПП6.9. (див. на СD). Тут збільшення s і t внесено в перевірну частину. Значенням *t++ є символ, на який вказував t до збільшення. Так само цей символ розміщують у стару позицію s, перш ніж s буде збільшено. Кінцевий результат полягає у тому, що всі символи, в тому числі завершальний символ ’\0’, копіюються з t у s. Порівняння з символом ’\0’ зайве, тому функцію можна записати у вигляді ПП6.10 (див. на СD), який має переваги.
Розглянемо функцію Strcmp(s, t) (див. ПП6.11 на СD), яка порівнює символьні рядки s і t, повертає від’ємне, нульове або додатне значення відповідно до того, чи менше, дорівнює або більше лексикографічно s, ніж t. Версію Strcmp із вказівниками реалізовано як ПП6.12 (див. на СD).
6.6. Вказівники – не цілі значення
Вказівник можна присвоїти цілому значенню і передати це значення обернено, не змінивши його. При цьому не відбувається ніякого масштабування або перетворення і жоден біт не губиться. Розглянемо, наприклад, функцію StrSave(s) (див. ПП6.13 на СD), яка копіює рядок s у деяке місце для зберігання, яке виділяється за допомогою функції Alloc, і повертає вказівник на це місце. На практиці є бажання нехтувати описами, як показано в ПП6.14. (див. на СD).
Ця програма буде правильно працювати, оскільки за замовчуванням функції і аргументи мають тип int, а вказівник і ціле значення можна безпечно пересилати туди і назад. Однак такий стиль програмування ризикований, оскільки залежить від деталей реалізації та архітектури ПК і може призвести до неправильних результатів на конкретному компіляторі. Краще всього всюди використати повні описи.
6.7. Багатовимірні масиви
У мові C++ передбачено багатовимірні масиви. Розглянемо завдання перетворення дня місяця в день року і навпаки. Наприклад, перше березня є 60-м днем не високосного року та 61-м днем високосного року. Введемо дві функції для виконання цих перетворень: Day_of_year перетворить місяць і день у точно призначений день року, а Month_day – день року на місяць і день. Остання функція повертає два значення, тому аргументи місяця і дня повинні бути вказівниками:
Month_day(1977, 60, &m, &d)
надає m значення 3 і d значення 1 (1 березня).
Обидві ці функції потребують інформаційну таблицю, яка вказує кількість днів у кожному місяці. Кількості днів у місяці високосного і не високосного років розрізняються, тому простіше подати їх у вигляді двох рядків двовимірного масиву, ніж намагатися простежувати під час обчислень, що саме відбувається в лютому. Такий масив і функції, які виконують ці перетворення, визначено в ПП6.15. (див. на СD). Двовимірний масив day_tab повинен бути зовнішнім для Day_of_year і Month_day, оскільки він використовується обома цими функціями.
За визначенням у мові C++ двовимірний масив є одновимірним масивом кожен елемент якого є масивом. Тому індекси записуються як day_tab[i][j], а не day_tab [i, j], як у більшості мов. Використовувати двовимірні масиви можна так само, як і в інших мовах. Елементи зберігаються по рядках, тобто в разі звернення до елементів у порядку їх розміщення в пам’яті найшвидше змінюється найбільш правий індекс.
Масив ініціалізується за допомогою списку початкових значень, розташованих у фігурних дужках {}, де кожен рядок двовимірного масиву ініціалізується відповідним підсписком. Так у початок масиву day_tab поміщено стовпчик із нулями для того, щоб номери місяців змінювалися від 1 до 12, а не від 0 до 11.
Якщо двовимірний масив передається функції, то опис відповідного аргументу функції повинен містити кількість стовпчик. Кількість рядків несуттєва, оскільки фактично передається вказівник. У розглядуваному випадку це вказівник об’єктів, що є масивами з 13 чисел типу int. Отже, для передачі масиву day_tab функції F опис у F мав би вигляд:
F(day_tab)
int day_tab[2][13];
{...}
Кількість рядків несуттєва, тому опис аргументу в F міг би бути таким: int day_tab[][13]; або int (*day_tab)[13];. Це означає, що аргумент є вказівником масиву з 13 цілих значень. Круглі дужки тут потрібні, оскільки квадратні дужки [] мають вищий рівень старшинства, ніж операція *; Без круглих дужок () int *day_tab[13]; є описом масиву з 13 вказівників на цілі.
