- •79057, М. Львів, вул. Генерала Чупринки, 103/54
- •Стислий зміст
- •1.2. Основні ознаки об'єктно-орієнтованого програмування 31
- •2.2. Розроблення реальної навчальної програми 40
- •2.4. Поняття про логічну та циклічну настанови 49
- •17.1. Поняття про узагальнені функції 364
- •17.2. Узагальнені класи 371
- •1.1.1. Причини створення мови програмування с
- •1.2. Основні ознаки об'єктно-орієнтованого програмування
- •1.2.1. Поняття про інкапсуляцію
- •1.2.2. Поняття про поліморфізм
- •1.2.3. Поняття про успадкування
- •2.1.1. Введення коду програми
- •2.1.2. Компілювання програми
- •2.1.3. Виконання програми
- •2.1.4. Порядкóвий аналіз програми
- •2.1.5. Оброблення синтаксичних помилок
- •2.2. Розроблення реальної навчальної програми
- •2.2.1. Присвоєнням значень змінним
- •2.2.2. Введення даних у програму
- •2.2.3. Деякі можливості виведення даних
- •2.2.4. Введення нового типу даних
- •2.3.1. Основні поняття про функції
- •2.3.3. Передавання аргументів функції
- •2.3.4. Повернення функціями аргуметів
- •2.3.5. Спеціальна функція main()
- •2.4. Поняття про логічну та циклічну настанови
- •2.4.1. Логічна настанова if
- •2.4.2. Циклічна настанова for
- •2.5.1. Поняття про блоки програми
- •2.5.2. Використання крапки з комою і розташування настанов
- •2.5.3. Практика застосування відступів
- •2.6.1. Поняття про ключові слова
- •2.6.2. Розроблення ідентифікаторів користувача
- •2.6.3. Використання стандартної бібліотеки
- •3.1. Оголошення змінних
- •3.1.1. Локальні змінні
- •3.1.2. Формальні параметри
- •3.1.3. Глобальні змінні
- •3.2. Модифікатори типів даних
- •3.3. Поняття про літерали
- •3.3.1. Шістнадцяткові та вісімкові літерали
- •3.3.2. Рядкові літерали
- •3.3.3. Символьні керівні послідовності
- •3.4. Ініціалізація змінних
- •3.5.1. Поняття про вбудовані оператори
- •3.5.2. Арифметичні оператори
- •3.5.3. Оператори інкремента і декремента
- •3.5.5. Оператори відношення та логічні оператори
- •3.6. Запис арифметичних виразів
- •3.6.1. Перетворення типів у виразах
- •3.6.2. Перетворення, що відбуваються під час використання типу bool
- •3.6.3. Операція приведення типів даних
- •3.6.4. Використання пропусків і круглих дужок
- •4.1. Використання настанови вибору if
- •4.1.1. Умовний вираз
- •4.1.2. Вкладені if-настанови
- •4.1.3. Конструкція if-else-if
- •4.2. Використання настанови багатовибірного розгалуження switch
- •4.2.1. Особливості роботи настанови
- •4.2.2. Організація вкладених настанов багатовибірного розгалуження
- •4.3. Використання настанови організації циклу for
- •4.3.1. Варіанти використання настанови організації циклу for
- •4.3.2. Відсутність елементів у визначенні циклу
- •4.3.3. Нескінченний цикл
- •4.3.4. Цикли часової затримки
- •4.4. Використання інших ітераційних настанов
- •4.4.1. Ітераційна настанова while
- •4.4.2. Ітераційна настанова do-while
- •4.4.3. Використання настанови переходу continue
- •4.4.4. Використання настанови break для виходу з циклу
- •4.4.5. Організація вкладених циклів
- •4.5. Використання настанови безумовного переходу goto
- •4.6. Приклад використання настанов керування
- •5.1. Одновимірні|одномірні| масиви
- •5.1.1. На межах масивів "прикордонної застави" немає
- •5.1.2. Сортування масиву
- •5.2. Побудова символьних рядків
- •5.2.1. Оголошення рядкового літерала
- •5.2.2. Зчитування рядків з клавіатури
- •5.3. Застосування бібліотечних функцій для оброблення рядків
- •5.3.1. Використання функції strcpy()
- •5.3.2. Використання функції strcpy()
- •5.3.3. Використання функції strcmp()
- •5.3.4. Використання функції strlen()
- •5.3.5. Використання ознаки завершення рядка
- •5.4.1. Двовимірні масиви
- •5.4.2. Багатовимірні|багатомірні| масиви
- •5.5. Ініціалізація масивів
- •5.5.1. Ініціалізація "розмірних" масивів
- •5.5.2. "Безрозмірна" ініціалізація масивів
- •5.6. Масиви рядків
- •5.6.1. Побудова масивів рядків
- •5.6.2. Приклад використання масивів рядків
- •6.1. Основні поняття про покажчики
- •6.2. Використання|із| покажчиків з операторами присвоєння
- •6.2.1. Оператори роботи з покажчиками
- •6.2.2. Важливість застосування базового типу покажчика
- •6.2.3. Присвоєння значень за допомогою покажчиків
- •6.3. Використання покажчиків у виразах
- •6.3.1. Арифметичні операції над покажчиками
- •6.3.2. Порівняння покажчиків
- •6.4. Покажчики і масиви
- •6.4.1. Основні відмінності між індексуванням елементів масивів і арифметичними операціями над покажчиками
- •6.4.2. Індексування покажчика
- •6.4.3. Взаємозамінність покажчиків і масивів
- •6.4.4. Масиви покажчиків
- •6.4.5. Покажчики і рядкові літерали
- •6.4.5. Приклад порівняння покажчиків
- •6.5. Ініціалізація покажчиків
- •6.5.1. Домовленість про нульові покажчики
- •6.5.2. Покажчики і 16-розрядні середовища
- •6.5.3. Багаторівнева непряма адресація
- •6.6. Виникнення проблем під час використання покажчиків
- •6.6.1. Неініціалізовані покажчики
- •6.6.2. Некоректне порівняння покажчиків
- •6.6.3. Не встановлення покажчиків
- •7.1. Правила дії областей видимості функцій
- •7.1.1. Локальні змінні
- •7.1.2. Оголошення змінних в ітераційних настановах і настановах вибору
- •7.1.3. Формальні параметри
- •7.1.4. Глобальні змінні
- •7.2. Передача покажчиків і масивів як аргументів функціям
- •7.2.1. Виклик функцій з покажчиками
- •7.2.2. Виклик функцій з масивами
- •7.2.3. Передача функціям рядків
- •7.3. Аргументи функції main(): argc і argv
- •7.3.1. Передача програмі числових аргументів командного рядка
- •7.3.2. Перетворення числових рядків у числа
- •7.4. Використання у функціях настанови return
- •7.4.1. Завершення роботи функції
- •7.4.2. Повернення значень
- •7.4.3. Функції, які не повертають значень (void-функції)
- •7.4.4. Функції, які повертають покажчики
- •7.4.5. Прототипи функцій
- •7.4.7. Організація рекурсивних функцій
- •8.1. Способи передачі аргументів функціям
- •8.1.2. Використання покажчика для забезпечення виклику за посиланням
- •8.2. Посилальні параметри
- •8.2.1. Механізм дії посилальних параметрів
- •8.2.2. Варіанти оголошень посилальних параметрів
- •8.2.3. Повернення посилань
- •8.2.4. Створення обмеженого (безпечного) масиву
- •8.2.5. Поняття про незалежні посилання
- •8.2.6. Врахування обмежень під час використання посилань
- •8.2.7. Перевантаження функцій
- •8.2.8. Поняття про ключове слово overload
- •8.3. Передача аргументів функції за замовчуванням
- •8.3.1. Можливі випадки передачі аргументів функції за замовчуванням
- •8.3.2. Порівняння можливості передачі аргументів функції за замовчуванням з її перевантаженням
- •8.3.3. Особливості використання аргументів, що передаються функції за замовчуванням
- •8.4. Перевантаження функцій і неоднозначності, що при цьому виникають
- •9.1. Специфікатори типів даних
- •9.1.1. Застосування специфікатора типу даних const
- •9.1.2. Застосування специфікатора типу даних volatile
- •9.2. Специфікатори класів пам'яті
- •9.2.1. Застосування специфікатора класу пам'яті auto
- •9.2.2. Застосування специфікатора класу пам'яті extern
- •9.2.3. Статичні змінні
- •9.2.4. Регістрові змінні
- •9.2.5. Походження модифікатора register
- •9.3. Порозрядні оператори
- •9.3.1. Порозрядні оператори і, або, що виключає або і не
- •9.3.2. Оператори зсуву
- •9.4.1. Перерахунки – списки іменованих цілочисельних констант
- •9.4.2. Створення нових імен для наявних типів даних
- •9.4.3. Оператор "знак запитання"
- •9.4.4. Складені оператори присвоєння
- •9.4.5. Оператор "кома"
- •9.4.6. Декілька присвоєнь "в одному"
- •9.4.7. Використання ключового слова sizeof
- •9.5.1. Оператори динамічного розподілу пам'яті
- •9.5.2. Ініціалізація динамічно виділеної пам'яті
- •9.5.3. Динамічне виділення пам'яті для масивів
- •9.5.4. Функції виділення та звільнення пам'яті у мові програмування с
- •10.1. Робота зі структурами
- •10.1.1. Основні положення
- •10.1.2. Доступ до членів структури
- •10.1.3. Масиви структур
- •10.1.4. Приклад застосування структури
- •10.1.5. Присвоєння структур
- •10.1.6. Передача структури функції як аргументу
- •10.1.7. Повернення функцією структури як значення
- •10.2. Використання покажчиків на структури і оператора "стрілка"
- •10.2.1. Особливості використання покажчиків на структури
- •10.2.2. Приклад використання покажчиків на структури
- •10.3. Посилання на структури
- •10.3.1. Використання структур під час передачі функції параметрів за посиланням
- •10.3.2. Використання як членів структур масивів і структур
- •10.4. Бітові поля структур
- •10.5. Особливості використання об'єднань
- •10.5.1. Оголошення об'єднання
- •10.5.2. Анонімні об'єднання
- •10.5.3. Використання оператора sizeof для гарантії переносності коду програми
- •11.1. Потреба об'єктно-орієнтованого програмування
- •11.1.1. Процедурні мови програмування
- •11.1.2. Поділ програми на функції
- •11.1.3. Недоліки структурного програмування
- •11.1.4. Неконтрольований доступ до даних
- •11.1.5. Відображення картини реального світу
- •11.2. Поняття про об'єктно-орієнтований підхід
- •11.2.1. Виробнича аналогія
- •11.3. Основні компоненти об'єктно-орієнтованої мови програмування
- •11.3.1. Поділ програми на об'єкти
- •11.3.2. Визначення класу
- •11.3.3. Поняття про успадкування в класах
- •11.3.4. Повторне використання коду
- •11.3.5. Поняття про типи даних користувача
- •11.3.6. Поняття про поліморфізм і перевантаження операторів
- •11.5. Вивчення основ створення об'єктно-орієнтованих програм
- •11.6. Поняття про універсальну мову моделювання
- •12.1. Базові поняття класу
- •12.2. Конструктори і деструктори
- •12.2.1. Параметризовані конструктори
- •12.2.2. Альтернативний варіант ініціалізації членів-даних об'єкта
- •12.3. Доступ до членів класу
- •12.4. Класи і структури – споріднені типи
- •12.5. Об'єднання і класи – споріднені типи
- •12.6. Вбудовувані функції
- •12.7. Створення масивів об'єктів
- •12.8. Покажчики на об'єкти
- •13.1. Поняття про функції-"друзі" класу
- •13.2. Перевантаження конструкторів
- •13.3. Динамічна ініціалізація конструктора
- •13.4. Присвоєння об'єктів
- •13.5. Передача об'єктів функціям
- •13.5.1. Конструктори, деструктори і передача об'єктів
- •13.5.2. Потенційні проблеми під час передачі параметрів
- •13.6. Повернення об'єктів функціями
- •13.7. Створення і використання конструктора копії
- •13.7.1. Використання конструктора копії для ініціалізації одного об'єкта іншим
- •13.7.2. Використання конструктора копії для передачі об'єкта функції
- •13.7.3. Використання конструктора копії під час повернення функцією об'єкта
- •13.7.4. Конструктори копії – а чи не можна знайти щось простіше?
- •13.8. Ключове слово this
- •14.1. Перевантаження операторів з використанням функцій-членів класу
- •14.1.3. Особливості реалізації механізму перевантаження операторів
- •14.1.4. Значення порядку слідування операндів
- •14.2. Перевантаження операторів з використанням функцій-не членів класу
- •14.2.1. Використання функцій-"друзів" класу для перевантаження бінарних операторів
- •14.2.2. Використання функцій-"друзів" класу для перевантаження унарних операторів
- •14.2.3. Перевантаження операторів відношення та логічних операторів
- •14.3. Особливості реалізації оператора присвоєння
- •14.4. Перевантаження оператора індексації масивів ([])
- •14.5. Перевантаження оператора "()"
- •14.6. Перевантаження інших операторів
- •14.6.1. Приклад перевантаження операторів класу рядків
- •15.1. Поняття про успадкування
- •15.2. Керування доступом до членів базового класу
- •15.3. Використання захищених членів класу
- •15.3.1. Використання специфікатора доступу protected для надання членам класу статусу захищеності
- •15.3.2. Використання специфікатора protected для успадкування базового класу
- •15.3.3. Узагальнення інформації про використання специфікаторів public, protected і private
- •15.4. Успадкування декількох базових класів
- •15.5. Використання конструкторів і деструкторів під час реалізації механізму успадкування
- •15.5.1. Прядок виконання конструкторів і деструкторів
- •15.5.2. Передача параметрів конструкторам базового класу
- •15.6. Повернення успадкованим членам початкової специфікації доступу
- •15.7. Віртуальні базові класи
- •16.1. Покажчики на похідні типи – підтримка динамічного поліморфізму
- •16.2. Віртуальні функції
- •16.2.1. Поняття про віртуальні функції
- •16.2.2. Успадкування віртуальних функцій
- •16.2.3. Потреба у застосуванні віртуальних функцій
- •16.2.4. Приклад застосування віртуальних функцій
- •16.2.5. Суто віртуальні функції та абстрактні класи
- •16.2.6. Порівняння раннього зв'язування з пізнім
- •16.2.7. Поняття про поліморфізм і пуризм
- •17.1. Поняття про узагальнені функції
- •17.1.1. Шаблонна функція з одним узагальненим типом
- •17.1.2. Шаблонна функція з двома узагальненими типами
- •17.1.3. Безпосередньо задане перевантаження узагальненої функції
- •17.1.4. Перевантаження шаблону функції
- •17.1.5. Використання стандартних параметрів у шаблонних функціях
- •17.1.6. Обмеження, які застосовуються під час використання узагальнених функцій
- •17.1.7. Приклад створення узагальненої функції abs()
- •17.2. Узагальнені класи
- •17.2.1. Створення класу з одним узагальненим типом даних
- •17.2.2. Створення класу з двома узагальненими типами даних
- •17.2.3. Створення узагальненого класу для організації безпечного масиву
- •17.2.4. Використання в узагальнених класах аргументів, що не є типами
- •17.2.5. Використання в шаблонних класах аргументів за замовчуванням
- •17.2.6. Безпосередньо задані спеціалізації класів
- •18.1. Основи оброблення виняткових ситуацій
- •18.1.1. Системні засоби оброблення винятків
- •18.1.2. Використання функцій exit() і abort() для завершення роботи програми
- •18.1.3. Перехоплення винятків класового типу
- •18.1.4. Використання декількох catch-настанов
- •18.2. Варіанти оброблення винятків
- •18.2.1. Перехоплення всіх винятків
- •18.2.2. Обмеження, що накладаються на тип винятків, які генеруються функціями
- •18.2.3. Повторне генерування винятку
- •18.3. Оброблення винятків, згенерованих оператором new
- •18.4. Перевантаження операторів new і delete
- •19.2.3. Класи потоків
- •19.3. Перевантаження операторів введення-виведення даних
- •19.3.1. Створення перевантажених операторів виведення даних
- •19.3.2. Використання функцій-"друзів" класу для перевантаження операторів виведення даних
- •19.3.3. Створення перевантажених операторів введення даних
- •19.4. Форматоване введення-виведення даних
- •19.4.1. Форматування даних з використанням функцій-членів класу ios
- •19.4.2. Встановлення ширини поля, точності та символів заповнення
- •19.4.3. Використання маніпуляторів введення-виведення даних
- •19.4.4. Створення власних маніпуляторних функцій
- •19.5. Файлове введення-виведення даних
- •19.5.1. Відкриття та закриття файлу
- •19.5.2. Зчитування і запис текстових файлів
- •19.5.3. Неформатоване введення-виведення даних у двійковому режимі
- •19.5.4. Зчитування і запис у файл блоків даних
- •19.5.6. Приклад порівняння файлів
- •19.5.7. Використання інших функцій для двійкового введення-виведення
- •19.5.8. Перевірка статусу введення-виведення
- •19.6. Використання файлів довільного доступу
- •19.6.1. Функції довільного доступу
- •19.6.2. Приклади використання довільного доступу до вмісту файлу
- •19.7. Використання перевантажених операторів введення-виведення даних під час роботи з файлами
- •20.1. Динамічна ідентифікація типів (rtti)
- •20.1.1. Отримання типу об'єкта у процесі виконання програми
- •20.1.2. Приклад rtti-застосування
- •20.1.3. Застосування оператора typeid до шаблонних класів
- •20.2. Оператори приведення типів
- •20.2.1. Оператор приведення поліморфних типів dynamic_cast
- •20.2.2. Оператор перевизначення модифікаторів const_cast
- •20.2.3. Оператор неполіморфного приведення типів static_cast
- •20.2.4. Оператор перетворення типу reinterpret_cast
- •20.2.5. Порівняння звичайної операції приведення типів з новими чотирма cast-операторами
- •21.1. Простори імен
- •21.1.1. Поняття про простори імен
- •21.1.2. Застосування настанови using
- •21.1.3. Неіменовані простори імен
- •21.1.4. Застосування простіру імен std
- •21.2. Застосування покажчиків на функції
- •21.2.1. Передача покажчиком на функцію її адреси іншій функції
- •21.2.2. Пошук адреси перевантаженої функції
- •21.3. Поняття про статичні члени-даних класу
- •21.5. Застосування до функцій-членів класу модифікаторів const і mutable
- •21.6. Використання explicit-конструкторів
- •21.7. Синтаксис ініціалізації членів-даних класу
- •21.8. Використання ключового слова asm
- •21.9. Специфікатор компонування функцій
- •21.11. Створення функцій перетворення
- •22.1. Огляд стандартної бібліотеки шаблонів
- •22.2. Поняття про контейнерні класи
- •22.3. Робота з векторами
- •22.3.1. Доступ до вектора за допомогою ітератора
- •22.3.2. Вставлення та видалення елементів з вектора
- •22.3.3. Збереження у векторі об'єктів класу
- •22.3.4. Доцільність використання ітераторів
- •22.4. Робота зі списками
- •22.4.1. Використання базових операцій для роботи зі списком
- •22.4.2. Сортування списку
- •22.4.3. Об'єднання одного списку з іншим
- •22.4.4. Зберігання у списку об'єктів класу
- •22.5. Поняття про відображення
- •22.5.1. Робота з відображеннями
- •22.5.2. Зберігання у відображенні об'єктів класу
- •22.6. Алгоритми оброблення контейнерних даних
- •22.6.1. Підрахунок кількості елементів
- •22.6.2. Видалення і заміна елементів
- •22.6.3. Реверсування послідовності
- •22.6.4. Перетворення послідовності
- •22.6.5. Дослідження алгоритмів
- •22.7. Використання класу string
- •22.7.1. Огляд функцій-членів класу string
- •22.7.2. Зберігання рядків у інших контейнерах
- •23.1.1. Директива #define
- •23.1.2. Директива #error
- •23.1.3. Директива #include
- •23.2. Директиви умовного компілювання
- •23.2.1. Директиви #if, #else, #elif і #endif
- •23.2.2. Директиви #ifdef і #ifndef
- •23.2.3. Директива #undef
- •23.2.4. Використання оператора defined
- •23.2.5. Про значення препроцесора
- •23.2.6. Директива #line
- •23.2.7. Директива #pragma
- •23.3. Оператори препроцесора "#" і "##"
- •23.4. Зарезервовані макроімена
- •23.5. Деякі поради студентам
- •24.1. Удосконалення процесу розроблення програмного забезпечення
- •24.1.1. Безпосередній процес розроблення пз
- •24.1.2. Каскадний процес розроблення пз
- •24.1.3. Використання ооп
- •24.1.4. Сучасні підходи до розроблення пз
- •24.2. Моделювання варіантів використання
- •24.2.1. Поняття про діючі суб'єкти
- •24.2.2. Поняття про варіанти використання
- •24.2.3. Поняття про сценарії
- •24.2.4. Застосування діаграм варіантів використання
- •24.2.5. Описи варіантів використання
- •24.2.6. Перехід від варіантів використання до класів
- •24.3. Предметна область програмування
- •24.3.1. Рукописні форми
- •24.3.2. Прийняття допущень і спрощень
- •24.4. Програма landlord: етап удосконалення
- •24.4.1. Встановлення діючих суб'єктів
- •24.4.2. З'ясування варіантів використання
- •24.4.3. Опис варіантів використання
- •24.4.4. Передбачення додаткових сценаріїв
- •24.4.5. Використання діаграм дій uml
- •24.5. Перехід від варіантів використання до класів
- •24.5.1. Аналіз переліку іменників з опису варіантів використання
- •24.5.2. Уточнення переліку іменників
- •24.5.3. Визначення атрибутів
- •24.5.4. Перехід від дієслів до повідомлень
- •24.5.5. Побудова діаграм класів
- •24.5.6. Побудова діаграм послідовностей
- •24.6. Кроки написання коду програми
- •24.6.1. Написання заголовного файлу
- •24.6.2. Створення початкових *.Срр файлів
- •24.6.3. Вимушені спрощення коду програми
- •24.6.4. Взаємодія користувача з програмою
- •24.6.5. Труднощі написання коду програми
- •24.7. Резюме
24.6.5. Труднощі написання коду програми
Процес розроблення реальних проектів може проходити зовсім не так гладко, як це було продемонстровано у нашому прикладі. Може знадобитися не одна, а декілька ітерацій кожного з розглянутих вище етапів. Програмісти можуть по-різному уявляти собі потреби користувачів, що вимагатиме повернення з середини етапу побудови на етап удосконалення. Користувачі також можуть запросто змінити свої вимоги, не дуже замислюючись над тим, які незручності вони тим самим створюють для розробників.
24.7. Резюме
Для простих програм під час їх розроблення може бути достатньо методу проб і помилок. Але під час розроблення крупних проектів потрібен більш організований підхід. У цьому розділі ми розглянули один з можливих методів розроблення ПЗ під загальною назвою уніфікований процес. Він складається з таких етапів: початок, удосконалення, побудова і впровадження. Етап удосконалення відповідає програмному аналізу, а побудова – плануванню структури програми і написанню її коду.
В уніфікованому процесі використовується прецедентний підхід до розроблення ПЗ. Ретельно вивчаються потенційні користувачі та аналізуються їх вимоги. Діаграма варіантів використання UML демонструє діючі суб'єкти і виконувані операції, що ініціюються ними (варіанти використання). Будь-який іменник з описів варіантів використання може в майбутньому стати іменем класу або атрибуту. Дієслова перетворюються на методи.
Доповненням до діаграм варіантів використання є ще багато інших UML-діаграм, що допомагають більш повною мірою досягти взаєморозуміння між користувачами і розробниками. Відносини між класами показуються на діаграмах класів, керівні потоки – на діаграмах дій, а діаграми послідовностей відображають взаємозв'язки між об'єктами під час виконання варіантів використання.
Додатки. Доповнення до С++
У цій частині навчального посібника будуть розглядатися такі основні теми:
Про автора 18
Передмова 19
Вступ 20
Розділ 1. Історія виникнення| мови програмування С++ 27
Розділ 2. Основні елементи мови програмування С++ 35
Розділ 3. Основні типи даних| у мові програмування C++ 55
Розділ 4. Поняття про настанови керування ходом виконання С++-програми 72
Розділ 5. Масиви та рядки – засоби групування взаємопов'язаних між собою змінних 91
Розділ 6. Особливості застосування покажчиків 111
Розділ 7. Основи застосування С++-функцій 131
Розділ 8. Використання засобів програмування для розширення можливостей С++-функцій 157
Розділ 9. С++-специфікатори та спеціальні оператори 177
Розділ 10. Поняття про структури і об'єднання даних 206
Розділ 11. Основи розроблення об'єктно-орієнтованих програм мовою C++ 233
Розділ 12. Введення в класи 245
Розділ 13. Робота з класами 270
Розділ 14. Перевантаження операторів 293
Розділ 15. Успадкування в класах 324
Розділ 16. Віртуальні функції та поліморфізм 349
Розділ 17. Шаблони в класах 364
Розділ 18. Оброблення виняткових ситуацій 381
Розділ 19. С++-система введення-виведення потокової інформації 399
Розділ 20. Динамічна ідентифікація типів і оператори приведення типу 432
Розділ 21. Поняття про простори імен та інші ефективні програмні засоби 448
Розділ 22. Введення в стандартну бібліотеку шаблонів 473
Розділ 23. Особливості роботи препроцесора С++ 513
Розділ 24. Формалізація процесу розроблення об'єктно-орієнтованого програмного забезпечення| 524
Додаток А. Основи створення консольних програм у середовищі Borland C++ Builder 559
Додаток Б. Основи створення консольних програм у середовищі Microsoft Visual C++ 567
Додаток В. Дещо про С-систему введення-виведення 573
Додаток Г. Особливості використання застарілого С++-компілятора 587
Додаток Д. .NET-розширения для C++ 589
Література 593
Додаток А. Основи створення консольних програм у середовищі Borland C++ Builder
У цьому додатку розглядаються питання, які стосуються використання інтегрованого середовища Borland C++ Builder для створення консольних кодів програм, що повністю відповідають прикладам, наведеним у цьому навчальному посібнику.
C++ Builder – це найкраще інтегроване середовище розробника, яке випускається фірмою Borland. Воно повністю узгоджується із стандартом мови програмування C++, не виникає жодних проблем з сумісністю середовища і мови. Існує студентська версія системи, вартість якої становить приблизно $100. Також є і безкоштовна її версія, яку можна скачати з сайту фірми Borland. Якщо у Вас виникне бажання нею скористатися, то коди програм доведеться писати в текстовому редакторі Notepad або будь-якому подібному до нього. У цьому додатку розглядається інтегроване середовище C++ Builder версії 6.0.
Будемо вважати, що система встановлена на Вашому комп'ютері, і Ви умієте її запускати у середовищі Windows.
Вам знадобиться, щоб на екрані відображалися розширення файлів (наприклад, *.срр), потрібних для роботи з середовищем MVC++. Переконайтеся, що в настройках Провідника вимкнена функція, яка приховує розширення зареєстрованих типів файлів.
У цьому ж додатку ми також детально розглянемо питання використання середовища C++ Builder для редагування, компілювання, зв'язування і виконання консольних програм.
А.1. Основні правила роботи у середовищі C++ Builder
Консольні програми з цього навчального посібника вимагатимуть мінімальних змін для запуску з середовища C++ Builder. Дамо короткі рекомендації щодо основних правил роботи під час створення консольних програм у інтегральному середовищі C++ Builder.
А.1.1. Підготовка панелей інструментів
Початкове завантаження інтегрованого середовища C++ Builder призводить до того, що на екрані з'являються безліч об'єктів, які Вам, у принципі, не знадобляться під час створення консольних програм. Справа Ви побачите вікно, що називається Form1. Закрийте його (клацнувши на хрестику в правому верхньому кутку). Також Вам не знадобиться і Object Inspector (Інспектор об'єктів), закрийте і його. Вам доведеться позбавлятися від цих віконець під час кожного запуску C++ Builder.
Коли Ви закриєте вікно Form1, то виявите під ним ще одне вікно з деяким початковим кодом, написаним мовою C++. Це вікно називається редактором коду програми. Саме тут Ви проглядатимете початкові файли і писатимете свої програми. Проте під час запуску коду програми Ви бачите файл Unit1, який Вас абсолютно не цікавить. Закрийте вікно і натисніть No, якщо система запитає, чи не хочете Ви зберегти зміни.
Під час початкового запуску середовища C++ Builder на екрані з'являється безліч панелей інструментів, значна частина з яких Вам також не буде потрібною. Вам, швидше за все, знадобляться панелі Стандартна (Standard) і Debug (Відлагодження). Можете прибрати всю решту панелей, вибравши з меню Вигляд (View) пункт Toolbars (Панелі інструментів) і прибравши галочки перед їх іменами.
А.1.2. Утримання на екрані вікна з результатами роботи програми
Відкомпілювати і запустити у вікні Сесії MS-DOS усі консольні програми можна, взагалі не вносячи ніяких змін. Проте, якщо Ви хочете запускати їх з середовища C++ Builder за допомогою команди Run (Пуск) з однойменного меню, потрібно буде вставити в кінець коду програми рядки, які утримуватимуть на екрані вікно з результатами роботи програми достатньо довго. Це можна зробити за два кроки:
вставте функцію getch(); перед останнім return в секції main(). За допомогою цієї функції Ви зможете побачити результати роботи програми на екрані;
вставте вираз #include <conio.h> // Для консольного режиму роботи у початок main(). Це необхідно для функції getch().
Якщо у програмі використовується консольна графіка, то потрібно ще інші додаткові зміни, про які буде сказано в цьому додатку дещо пізніше.
А.1.3. Створення нового консольного проекту
Середовище C++ Builder, як і інші сучасні компілятори, мислить в термінах проектів під час створення консольних програм. Консольний проект складається з одного або декількох початкових файлів, а також з декількох додаткових файлів, таких як файли ресурсів і визначень. Втім, вони нам спочатку не знадобляться. Результатом створення консольної програми є зазвичай один виконуваний *.exe-файл.
Щоб почати створювати проект, потрібно вибрати пункт New... (Новий...) з меню File (Файл). Ви побачите діалогове вікно, що називається New Items (Нові елементи). Виберіть закладку New (Нові), якщо це необхідно. Потім клацніть двічі на значку Console Wizard (Майстер консольних додатків). Переконайтеся в тому, що в діалоговому вікні у пункті меню Source Type (Тип коду програми) вибрано C++ і що встановлений прапорець Console Application (Консольний додаток). Зніміть прапорці Use VCL, Multi Threaded і Specify Project Source. Натисніть <ОК>. Відповідайте негативно, якщо система запитає, чи зберегти зміни в Project1. У новому вікні редактора коду програми Ви побачите такий початковий текст:
//-----------------------------------------------------------
#pragma hdrstop
//-----------------------------------------------------------
#pragma argsused
int main(int argc,char **argv [])
{
getch(); return 0;
}
//-----------------------------------------------------------
Це як би скелет майбутньої консольної програми. Деякі з цих рядків Вам будуть не потрібні, а деякі доведеться додати. Ми зараз виконаємо необхідні зміни і додамо вираз, що виводить який-небудь текст, щоб переконатися в тому, що програма працює. Результат:
//test1.cpp
#include <vcl>
#include <iostream> // Для потокового введення-виведення
#include <conio.h> // Для консольного режиму роботи
using namespace std; // Використання стандартного простору імен
//#pragma hdrstop //не знадобиться
//#pragma argsused // не знадобиться
int main() // Аргументи не потрібні
{
cout << "Щасливі ті, хто вперше компілює програму.";
getch(); return 0;
}
Дві директиви #pragma виявилися не потрібні, також не потрібні виявилися аргументи main().
Якщо Ви у такому вигляді запустите програму, то переконаєтеся в тому, що вікно з результатами дуже швидко зникають з екрану. Це виправляється вставкою функції getch(); у кінець програми, безпосередньо перед останнім return. У результаті такої зміни програма чекатиме натиснення якої-небудь клавіші і тільки після цього прибере вікно виведення результатів з екрану. Функції getch() потрібен заголовний файл conio.h, який ми включаємо за допомогою відповідного виразу на початку програми.
Якщо Ви створюєте свою програму, то Вам знадобиться цей скелет, його Ви і змінюватимете і доповнюватимете. Якщо у Вас вже є якийсь файл, то читайте підрозділ "Робота з наявними файлами" даного додатку.
А.1.4. Надання імені консольному проекту та збереження його
Перейменувати і зберегти потрібно як початковий файл, так і консольний проект, у якому він знаходиться. Компілятор автоматично іменує початковий файл Unit1.cpp. Для того, щоб його перейменувати і зберегти, виберіть пункт Save As... (Зберегти як...) з меню File (Файл). Знайдіть потрібний каталог для свого проекту, назвіть більш-менш осмислено свій файл (зберігши при цьому розширення *.срр) і натисніть Save (Зберегти).
Інформація про консольний проект зберігається у файлі з розширенням *.bpr. Тому коли Ви зберігаєте проект, то Ви насправді запам'ятовуєте стан як файлу (або файлів) *.срр, так і файлу *.bpr. Під час створення нового проекту йому дається автоматично ім'я Project1 (або Project з будь-якою іншою цифрою). Щоб зберегти проект і змінити його назву, виберіть пункт Save Project As... (Зберегти проект як...) з меню File (Файл). Перейдіть в каталог, у якому Ви хочете зберегти файл, наберіть його ім'я з розширенням *.bpr і натисніть Save (Зберегти).
А.1.5. Робота з наявними файлами консольних програм
Розглянемо перелік дій, які потрібно виконати під час створення консольного проекту при наявному початковому файлі. Наприклад, якщо Ви скачаєте з сайту будь-якого видавництва приклади кодів програм, то якраз опинитеся в такій ситуації. Ми тут розглядатимемо тільки консольні програми з одним початковим файлом.
Допустимо, що файл називається myprog.cpp. Переконайтеся в тому, що він знаходиться в тому самому каталозі, у якому Ви створюватимете проект. Виберіть пункт Open (Відкрити) з меню File (Файл). Виберіть файл в діалоговому вікні і натисніть Open (Відкрити). Файл з'явиться у вікні редактора коду програми. Вискочить діалогове віконце. У ньому буде питання, чи хочете Ви створити проект, у якому даний файл компілювався б і запускався. Відповідайте ствердно. Проект, таким чином, створений.
Тепер потрібно його перейменувати і зберегти. Виберіть з меню File (Файл) пункт Save Project As... (Зберегти проект як...). Замініть ім'я project1.bpr на яке-небудь інше (зазвичай вибирають співпадаюче з іменем програми): myprog.bpr. Натисніть Save (Зберегти). От і все.
А.2. Компілювання, зв'язування і запуск консольних програм на виконання
Щоб створити виконуваний файл, виберіть пункт Make (Зробити) або Build (Компонування) з меню Project (Проект). З Вашого *.срр буде створено об'єктний файл *.obj, а з нього, своєю чергою, файл *.exe. Наприклад, якщо Ви компілюєте myprog.cpp, то результатом буде створення файлу myprog.exe. Якщо будуть виявлені помилки компілятора або компонувальника, то вони будуть зразу ж відображені. Постарайтеся домогтися їх зникнення.
А.2.1. Запуск консольної програми в середовищі C++ Builder
Якщо Ви модифікували код програми, вставивши в неї вираз getch()(див. розд. А.1), то Ви можете відкомпілювати, зв'язати і запустити консольну програму прямо з середовища C++ Builder буквально однією командою Run (Пуск) з однойменного меню. Якщо ніяких помилок не виявлено, з'явиться вікно отриманих результатів роботи програми.
А.2.2. Запуск програми в MS DOS
Можна запустити свою програму і з-під MS DOS. Сесія MS DOS відкривається в Windows з меню Start Programs (Пуск Програми) за допомогою ярлика MS-DOS Prompt (Сесія MS-DOS). В результаті Ви побачите чорне віконце із запрошенням MS DOS. Переміщайтеся по каталогах, використовуючи команду cd <ім'я каталога>. Для того, щоб запустити будь-які програми, що були попередньо скомпільовані, зокрема ті, тексти яких є в навчальному посібнику, то переконайтеся, що Ви знаходитеся в тому ж каталозі, що і потрібний файл *.exe, і наберіть ім'я програми. Докладнішу інформацію можна отримати, скориставшись Довідковою системою Windows.
А.2.3. Заздалегідь скомпільовані заголовні файли
Процес компілювання можна істотно прискорити, якщо використовувати заголовні файли, що були заздалегідь скомпільовані. Для цього потрібно вибрати пункт Options (Параметри) з меню Project (Проект), перейти до закладки Compiler (Компілятор) і встановити прапорець Use Precompiled Headers (Використовувати прекомпільовані заголовні файли). У коротких програмах більше всього часу витрачається на компілювання службових заголовних файлів C++, таких, як iostream. Включення вказаного параметра дає змогу скомпілювати ці файли тільки один раз.
А.2.4. Закриття і відкриття консольних проектів
Коли Ви закінчуєте роботу над проектом, то його необхідно закрити, вибравши пункт Close All (Закрити все) з меню File (Файл). Щоб відкрити вже наявний проект, потрібно з того ж меню вибрати пункт Open Project (Відкрити проект), перейти у відповідну директорію і двічі клацнути на імені файлу з розширенням *.bpr.
А.3. Додавання заголовного файлу до консольного проекту
Серйозні консольні програми, написані мовою програмування C++, можуть працювати з одним або навіть декількома призначеними для користувача заголовними файлами (і це на додаток до безлічі бібліотечних файлів, таких, як iostream і conio.h). Продемонструємо, як додати їх до консольного проекту.
А.3.1. Створення нового заголовного файлу
Виберіть пункт New... (Новий...) з меню File (Файл), переконайтеся в тому, що Ви знаходитеся на закладці, в якій відображаються нові елементи, клацніть двічі на значку Text (Текст). З'явиться вікно редактора коду програми з файлом file1.txt. Наберіть текст і збережіть файл за допомогою пункту Save as... (Зберегти як...) з меню File (Файл). Придумайте ім'я для файлу, але не забудьте залишити розширення *.h. Цей файл потрібно зберегти в тій самій директорії, де знаходяться Ваші початкові (*.срр) файли. Ім'я збереженого файлу з'явиться у вигляді однієї із закладок вікна редактора. Тепер для редагування різних файлів можна просто перемикатися між закладками.
А.3.2. Редагування заголовного файлу
Щоб відкрити вже наявний заголовний файл, виберіть Open (Відкрити) з меню File (Файл), вкажіть в полі Files of Type (Типи файлів) значення *.* (Всі файли). Тепер можна вибрати із переліку потрібний заголовний файл.
У процесі написання виразу #include для заголовного файлу в початковому не забудьте переконатися в тому, що ім'я файлу поміщене в лапки:
#include "myHeader.h"
Ці лапки вкажуть компіляторові, що він повинен шукати заголовний файл в тому ж каталозі, де знаходяться початкові файли.
А.3.3. Визначення місцезнаходження заголовного файлу
Якщо вже Ви додаєте файл *.h, то потрібно повідомити компілятор про його місцезнаходження. Якщо він знаходиться в директорії з іншими Вашими файлами, що відносяться до даного проекту, то нічого робити не потрібно.
Інакше потрібно вказати його розташування. Наприклад, це необхідно робити в тому випадку, якщо Ви використовуєте консольну графіку в своїй програмі. Потрібно вказати розташування файлу borlacon.h, якщо Вам лінь скопіювати його в каталог з рештою файлів. Перейдіть до пункту Options (Параметри) меню Project (Проект) і спробуйте вибрати закладку Directories/Conditionals (Каталоги/Імплікації). У секції Directories (Каталоги) клацніть на кнопці з трьома крапками, розташованій праворуч від переліку шляхів Include Path, що включаються. З'явиться діалогове вікно Directories (Каталоги).
У самому низу цього вікна наберіть повний шлях до каталога, що містить заголовний файл. Клацніть на кнопці Add (Додати), щоб занести цей каталог в перелік шляхів, що включаються. Натисніть кнопки <ОК>|, щоб закрилися всі діалоги.
Не намагайтеся додавати заголовні файли за допомогою функції Add to Project (Додати в проект) з меню Project (Проект).
А.4. Проекти з декількома початковими файлами
Реальні додатки і навіть деякі приклади з цього навчального посібника вимагають підключення декількох початкових файлів. У C++ Builder початкові файли називаються компонентами (units), ця назва характерна саме для даного середовища програмування. У більшості інших середовищ файли все-таки називаються файлами, а у мові Pascal – модулями.
А.4.1. Створення додаткових початкових файлів
Додаткові *.срр-файли можна створювати так само, як заголовні файли. Для цього потрібно вибрати File New (Файл Новий) і двічі клацнути на значку Text (Текст) в діалоговому вікні New (Нові). Наберіть початковий код програми і збережіть файл. Під час його збереження не забудьте вказати правильний тип: це повинен бути C++ Builder Unit (компонент C++ Builder). Розширення *.срр підставиться автоматично після імені файлу. Якщо чомусь цього не трапилося і Ви просто наберете ім'я файлу і навіть правильне розширення, то цей файл не розпізнається як C++ Builder unit.
А.4.2. Додавання наявних початкових файлів
У Вас уже може бути створений початковий файл, наприклад borlacon.cpp, необхідний для роботи з консольною графікою. Щоб додати початковий файл в проект, виберіть пункт Add To Project (Додати в проект) з меню Project (Проект), перейдіть в необхідну директорію і виберіть файл, який хочете додати. Потім натисніть кнопку Open (Відкрити). Тепер цей файл в C++ Builder вважатиметься частиною проекту.
Початкові файли вказані в закладках вікна редагування, так що можна швидко перемикатися з одного файлу на іншій. Деякі з них можна закривати, щоб вони не займали місце на екрані, якщо вони не потрібні.
А.4.3. Застосування менеджера проектів
Щоб подивитися, які файли є складовими частинами проекту, потрібно вибрати Project Manager (Менеджер проектів) з меню View (Вигляд). Ви побачите діаграму, на якій показані зв'язки між файлами, приблизно так само як і у Провіднику Windows. Натиснувши на плюс поряд із значком проекту, можна побачити всі файли, що входять в проект. Файл, який Ви тільки що додали в проект, повинен бути серед них.
Якщо натиснути правою кнопкою миші на Project Manager (Менеджері проектів), з'явиться контекстне меню, з якого можна вибрати наступні дії: Open (Відкрити), Close (Закрити), Save as... (Зберегти як...) і Compile (Компілювати). Це зручний спосіб роботи з окремими початковими файлами.
У багатофайлових програмах можна компілювати початкові файли незалежно один від одного. Для цього потрібно вибрати пункт Compile Unit (Компілювати Компонент) з меню Project (Проект). При цьому перекомпілюються тільки ті файли, які були змінені з часу попередньої збірки програми.
А.4.4. Програми з консольною графікою
Опишемо, як здійснювати компонування програм, в яких використовується консольна графіка. Це відноситься, зокрема, до програм circstrc з розд. 5 "Функції" і circles з розд. 6 "Об'єкти і класи". Отже, за порядком.
1. Створіть новий проект, як це було описано вище. Як ім'я проекту краще за все використовувати ім'я програми. Поміняйте тільки розширення на *.bpr.
2. Потім у початковому файлі коду програми поміняйте рядок #include <msoftcon.h> на #include <borlacon.h>.
3. Скопіюйте (саме скопіюйте, а не переносіть) файли borlacon.cpp і borlacon.h у файл проекту (чи ж повідомте компілятор, де шукати заголовний файл).
4. Додайте початковий файл borlacon.cpp у свій проект, дотримуючись настанов, описаних трохи вище в дод. А.8.2. Додавання наявних початкових файлів.
5. Щоб затримати на екрані вікно отриманих результатів роботи програми, потрібно вставити рядок getch(); безпосередньо перед останнім оператором return в кінці секції main().
6. Для підтримки getch() потрібно залучити до програми ще один заголовний файл. Для цього напишіть на початку програми рядок #include <conio.h> // Для консольного режиму роботи.
Тепер можна компілювати, пов'язувати і запускати програми з використанням консольної графіки так само, як і будь-які інші коди програм.
А.5. Відлагодження коду програми
У розд. 4 "Настанови керування ходом виконання С++-програми" ми використовували відлагоджувач в основному з метою повнішого ознайомлення з процесом роботи циклів. Під час використання середовища C++ Builder ті самі кроки можуть допомогти Вам знайти помилку у програмі і усунути її. Ми розглядатимемо тільки однофайлові консольні програми, але необхідно зазначити, що відлагодження багатофайлових проектів нічим принципово не відрізняється.
Спершу просто створіть і відкомпілюйте яку-небудь програму. Позбавтеся усіх помилок компілятора і компонувальника. Переконайтеся, що код програми виводиться у віконці редагування.
А.5.1. Покроковий прогін коду програми
Щоб запустити відлагоджувач, натисніть клавішу F8. Вся програма буде перекомпільована, а перший її рядок (зазвичай описувач main()) – підсвічується. Послідовні натиснення F8 приведуть до просування по коду програми від одного оператора до іншого. Якщо Ви проганяєте цикл, то побачите, як стрілка доходить до останнього виразу, а потім переходить знов на початок циклу.
А.5.2. Перегляд змінних коду програми
Існує можливість переглядати значення змінних у процесі покрокового трасування коду програми. Виберіть пункт Add watch (Додати змінну) з меню Run (Пуск). З'явиться діалогове вікно Watch Properties (Параметри перегляду). Наберіть ім'я змінної в полі Вираз, потім виберіть її тип і натисніть <ОК>|. З'явиться вікно Watch List (Перелік спостереження). Виконуючи вказані кроки кілька разів, можна додати в цей перелік будь-яку необхідну кількість змінних. Якщо Ви нормально розмістите на екрані вікно перегляду і вікно редагування, то зможете спостерігати одночасну зміну значень змінних залежно від виконуваної в даний момент команди. Якщо змінна поки недоступна (наприклад, ще не визначена у програмі), то вікно перегляду видасть повідомлення про помилку замість значення поряд з іменем змінної.
У випадку з програмою cubelist механізм спостереження змінних не розпізнає змінну cube, оскільки вона визначається усередині циклу. Перепишіть програму так, щоб вона визначалася поза циклом, і відразу побачите результат: у вікні спостереження вона відображається так, як це необхідно.
А.5.3. Покрокове трасування функцій
Якщо у вашій програмі використовуються функції, то майте на увазі, що є чудова можливість здійснити покрокове трасування кожного виразу функції. Це робиться за допомогою клавіші F7. На відміну від режиму трасування по F8, який розглядає кожну зустрінуту функцію як один вираз, такий режим дає змогу "увійти" всередину функції та виявити можливі помилки в ній. Якщо Ви примусите по F7 проходити бібліотечні функції, наприклад cout <<, то милуватиметеся початковим кодом бібліотеки. Це процес довгий, тому радимо користуватися цією можливістю, тільки якщо Вам дійсно важливо знати, що відбувається усередині рутинних функцій. Втім, можна в міру потреби чергувати натиснення F7 і F8, залежно від необхідності виявлення помилок у внутрішніх функціях.
А.5.4. Точки зупинки
Точки зупинки дають змогу тимчасово переривати роботу програми в довільних місцях. Коли їх потрібно використовувати? Ми вже показали, як можна примусити відлагоджувач проганяти програму тільки до курсора. Але бувають випадки, коли необхідно мати декілька таких точок. Наприклад, можна зупинити програму в кінці умови if, а також після відповідної else. Точки зупинки вирішують цю задачу, оскільки їх можна ставити в необмеженій кількості. У них є ще і розширені функції, які ми тут розглядати не будемо.
Розглянемо, як вставити точки зупинки в код програми. По-перше, погляньте на код програми у вікні редагування. Напроти кожного виконуваного оператора Ви побачите крапочку зліва. Просто клацніть мишею на тій крапочці, напроти якої Ви збираєтеся вставити точку зупинки. Крапочка заміниться на червоний кружечок, а рядок коду програми підсвічуватиметься. Тепер при будь-якому варіанті запуску програми в середовищі програма зупинятиметься саме тут. Можна на цьому тимчасовому зрізі перевірити значення змінних, провести покрокове трасування коду програми і т.д.
Щоб видалити точку зупинки, клацніть мишкою на червоному кружечку. Він зникне.
Є ще багато інших функцій відлагоджувача. Тут ми показали тільки основні, щоб Вам було з чого почати роботу.
Додаток Б. Основи створення консольних програм у середовищі Microsoft Visual C++
У цьому додатку розглядаються питання використання Microsoft Visual C++ (MVC++) для створення консольних програм, наприклад, таких, які наводилися як навчальні приклади в цьому навчальному посібнику. Розмова піде про середовище MVC++ версії 6.0.
Справжня версія середовища MVC++ є спадкоємцем стандартного середовища C++. Вона постачається в різних варіантах, включаючи недорогу студентську комплектацію.
Будемо вважати, що система MVC++ встановлена на Вашому комп'ютері і Ви знаєте, як запустити її у Windows.
Вам знадобиться, щоб на екрані відображалися розширення файлів (наприклад *.срр), потрібних для роботи з середовищем MVC++. Переконайтеся, що в настройках Провідника вимкнена функція, яка приховує розширення зареєстрованих типів файлів.
Б.1. Елементи вікна середовища MVC++
Після запуску системи MVC++ вікно середовища розділено на три частини. Зліва знаходиться панель View (Вигляд). У неї дві закладки: ClassView (Класи) і FHeView (Файли). Якщо Ви відкриєте який-небудь проект, то на цій панелі в закладці ClassView (Класи) відображатиметься ієрархія класів програми, а в закладці FileView (Файли) – перелік файлів, з яких складається проект. При натисненні на плюсик| показується наступний рівень ієрархії. Для того, щоб відкрити який-небудь файл, потрібно двічі клацнути на його імені.
Найбільше місця вікні середовища MVC++ зазвичай займає та його частина, в якій знаходиться текст відкритого файлу. Його можна використовувати в різних цілях, зокрема для відображення початкового коду програми або різної довідкової інформації. Внизу на екрані знаходиться віконце з безліччю закладок: Build (Компонування), Debug (Відлагодження) і т.д. Тут також будуть відображатимуться різні повідомлення компілятора про такі виконувані дії, як, наприклад, відлагодження програми.
Б.2. Робота з однофайловими консольними програмами
З допомогою середовищем MVC++ можна достатньо легко створювати однофайлові консольні програми і виконувати роботу з ними: правити, компонувати, виправляти помилки тощо.
Можливі два варіанти роботи з однофайловими консольними програмами: або файл вже існує і його потрібно правити, або файлу ще немає. У будь-якому випадку починати необхідно, тільки переконавшись в тому, що немає відкритих проектів (що таке проект, ми незабаром про це взнаємо). Натисніть на меню File (Файл). Якщо команда закриття робочої області Close Workspace недоступна, значить, відкритих проектів немає і можна приступати до роботи над своїм текстом консольної програми. Якщо ж вона доступна, то натисніть на неї для закриття відкритого у даний момент проекту.
Б.2.1. Компонування наявного файлу
Якщо початковий файл *.срр вже існує, то виберіть пункт Open (Відкрити) з меню File (Файл). Майте на увазі, що це не те ж саме, що Open Workspace (Відкрити робочу область). У діалоговому вікні, що з'явилося на екрані, знайдіть потрібний файл, виберіть його і клацніть на кнопці Open (Відкрити). Файл з'явиться у вікні документа (якщо у програмі використовується консольна графіка, як у прикладі cidcstrc з розд. 5 "Функції" або в прикладі circles з розд. 6 "Об'єкти і класи", зверніться до розділу "Програми створення консольного оформлення" даного додаток).
Для компілювання і компонування початкового файлу виберіть пункт Build (Компонування) з однойменного меню. У діалоговому вікні з'явиться запит на створення звичайної робочої області проекту. Відповідайте ствердно. Файл відкомпілюється і буде пов'язаний зі всіма необхідними бібліотечними файлами.
Для запуску програми виберіть Execute (Запустити) з меню Build (Компонування). Якщо все зроблено правильно, то з'явиться вікно з результатами роботи програми.
Після закінчення роботи програми у вікні з'явиться фраза Натисніть будь-яку клавішу для продовження. Її вставляє в кінець програми компілятор. Вікно отриманих результатів роботи має бути видно впродовж тривалого періоду, щоб Ви могли їх переглянути.
Якщо Ви закінчуєте роботу з програмою, то закрийте її робочу область за допомогою пункту Close Workspace (Закрити робочу область) з меню File (Файл). Відповідайте ствердно, коли в діалоговому вікні з'явиться запит на закриття усіх вікон з документами. Програму можна запустити і вручну, безпосередньо з MS DOS. Сесія MS DOS відкривається у Windows з меню Start Programs (Пуск Програми) за допомогою ярлика MS-DOS Prompt (Сесія MS-DOS). В результаті Ви побачите чорне віконце із запрошенням MS DOS. Переміщайтеся по каталогах, використовуючи команду cd <ім'я каталога>. Виконувані (*.exe) файли програм, створених компілятором середовища MVC++, розташовуються в підкаталозі DEBUG каталога, у якому зберігаються файли проектів. Для того, щоб запустити будь-які програми, відкомпілювані у середовищі MVC++, зокрема ті, тексти яких є в цьому навчальному посібнику, переконайтеся, що Ви знаходитеся в тому ж каталозі, що і файл *.exe, і наберіть ім'я програми. Докладнішу інформацію можна отримати, скориставшись Довідковою системою Windows.
Б.2.2. Створення нового файлу
Щоб створити свій файл *.срр, закрийте робочу область відкритого проекту, виберіть пункт New (Новий) з меню File (Файл). Клацніть на закладці Files (Файли). Виберіть потрібний тип файлу C++ Source File (Початковий файл C++), наберіть ім'я файлу, переконавшись перед тим у тому, що Ви знаходитеся в потрібному каталозі. Клацніть на кнопці <ОК>|. З'явиться чисте вікно документа. У ньому можна набирати код консольної програми. Не забудьте зберегти файл, вибравши пункт Save As... (Зберегти як...) з меню File (Файл). Потім відкомпілюйте свою програму так, як це вже було описано вище.
Б.2.3. Виправлення помилок
Якщо у програмі є помилки, повідомлення про них з'являтимуться у вікні Build (Компонування) внизу екрану. Якщо двічі клацнути на рядку з якою-небудь помилкою, з'явиться стрілка у вікні документа, що вказує на той рядок у коді програми, де ця помилка відбулася. Окрім того, якщо у вікні Build (Компонування) поставити курсор на рядок з кодом помилки (наприклад, С2143) і натиснути клавішу F1, то у вікні документа з'являться коментарі до тієї чи іншої помилки. Помилки потрібно усувати до тих пір, поки не з'явиться повідомлення 0 error(s), 0 warning(s) (0 помилок, 0 попереджень). Для запуску програми виберіть пункт Execute Build (Виконання компонування) з меню Build (Компонування).
Однією з поширених помилок є відсутність в коді програми рядкаusing namespace std; // Використання стандартного простору імен
Якщо забути включити його у програму, то компілятор повідомить, що він не знає, що таке cout << endl і т.ін.
Перед початком роботи над новою програмою не забувайте закривати відриті проекти. Це гарантує, що Ви дійсно почнете створювати новий проект. Щоб відкрити вже скомпоновану| програму, виберіть Open Workspace (Відкрити робочу область) з меню File (Файл). У діалоговому вікні перейдіть в потрібну директорію і двічі клацніть на файлі з розширенням *.dsw.
Б.2.4. Інформація про типи в процесі виконання (RTTI)
Деякі програми, такі, як empl_io.cpp з розд. 19 "С++-система введення-виведення потокової інформації", використовують RTTI. Можна налаштувати середовищем MVC++ так, щоб ця функція працювала.
Виберіть пункт Settings (Настройки) з меню Project (Проект) і клацніть на закладці C/C++. Із переліку категорій виберіть C++ Language (Мова C++). Встановіть прапорець Enable Run-Time Type Information (Включити RTTI). Потім натисніть <ОК>|. Ця функція системи MVC++ дає змогу уникнути появи багатьох помилок компілятора і компонувальника, деякі з яких взагалі тільки вводять в оману.
Б.3. Робота з багатофайловими консольними програмами
Вище було продемонстровано, як можна швидко, але непрофесійно створювати консольні програми. Цей спосіб, можливо, і хороший для однофайлових програм. Але коли в проекті більше одного файлу, все відразу стає значно складнішим. Почнемо з термінології. З'ясуємо з поняттями робоча область і проект.
Б.3.1. Поняття про проекти і робочі області
У середовищі MVC++ використовується концепція робочих областей, що на один рівень абстракції вище, ніж концепція проекту. Річ у тому, що в робочій області може міститися декілька проектів. Вона складається з каталогу і декількох конфігураційних файлів. Усередині неї кожен проект може мати власний каталог чи ж файли усіх проектів можуть зберігатися в одному каталозі робочої області.
Напевно, концептуально простіше припустити, що у кожного проекту є своя окрема робоча область. Саме це ми і припускатимемо під час подальшого з'ясування.
Проект відповідає додатку (програмі), яку Ви розробляєте. Він складається зі всіх файлів, потрібних програмі, а також з інформації про ці файли і їх компонування. Результатом всього проекту зазвичай є один виконуваний *.exe файл (можливі і інші результати, наприклад файли *.dll).
Б.3.2. Робота над проектом
Припустимо, що файли, які Ви збираєтеся включити в свій проект, вже існують і знаходяться у відомому Вам каталозі. Виберіть пункт New (Новий) з меню File (Файл) і клацніть на закладку Projects (Проекти) в діалоговому вікні, що з'явилося. Виберіть із переліку Win32 Console Application. У полі Location (Розміщення) виберіть шлях до каталога, але саме ім'я каталога не вказуйте. Потім наберіть ім'я каталога, що містить файли, в полі Project Name (Ім'я проекту) (клацнувши на кнопці, що знаходиться праворуч від поля Location (Розміщення), Ви зможете вибрати потрібний каталог, переходячи по дереву, але переконайтеся в тому, що в цей шлях не включено саме ім'я каталога). Переконайтеся також в тому, що прапорець Create New Workspace (Створити нову робочу область) встановлений, і натисніть <ОК>|.
Наприклад, якщо файли знаходяться в каталозі c:\Book\Chl3\Elev, слідує в полі Location (Розміщення) вказати c:\Book\Chl3\, а в полі Project Name Field (Ім'я проекту) –Elev. Ім'я проекту автоматично додається до шляху (якби в полі Location (Розміщення) був вказаний повний шлях, то підсумковий шлях до файлів був би c:\Book\Chl3\Elev\Elev, а це, зазвичай, зовсім не те, що нам потрібно). Після цього з'являється ще одне діалогове вікно. Необхідно переконатися в тому, що вибрана кнопка An Empty Project (Порожній Проект), і клацнути на Finish (Закінчити). У наступному вікні натисніть <ОК>|.
У цей час в указаному каталозі створюються різні файли, що відносяться до проекту. Вони мають розширення *.dsp, *.dsw і т.д. Окрім того, створюється порожня папка DEBUG, в якій зберігатиметься відкомпілюваний файл, готовий для подальшого виконання.
Додавання початкового файлу
А зараз до проекту потрібно причепити початкові файли, що містять файли *.срр і *.h, які повинні бути доступні для перегляду в закладці Файл. Виберіть пункт Add to Project (Додати до проекту) з меню Project (Проект), клацніть на Files (Файли), виберіть потрібні файли і натисніть <ОК>|. Тепер файли включені в проект, і їх можна проглядати в закладці FileView (Файли) вікна View (Вигляд). Клацнувши на закладці QassView (Класи) в тому ж вікні, можна проглянути структуру класів, функцій і атрибутів.
Щоб відкрити файл проекту для перегляду і редагування, потрібно двічі клацнути на його значку в закладці FileView (Файли). Другим способом відкриття файлу є його вибір за допомогою команди Open (Відкрити) меню File (Файл).
Визначення місцезнаходження заголовних файлів
У Вашому проекті можуть використовуватися заголовні файли (зазвичай з розширенням *.h), наприклад, такі, як msoftcon.h у програмах, що використовують консольну графіку. Їх не потрібно включати в проект, якщо, зазвичай, Ви не хочете проглядати їх код програми, але компіляторові потрібно знати, де вони знаходяться. Якщо вони знаходяться в тому ж каталозі, у якому зберігаються початкові файли, то питань не виникає. Інакше потрібно повідомити компілятор про їх місцезнаходження.
Виберіть пункт Options (Параметри) з меню Tools (Інструменти). Клацніть на закладці Directories (Каталоги). Для того, щоб побачити перелік каталогів з файлами компілятора, що включаються, потрібно спочатку вибрати Include Files (Файли, що включаються) з пропонованого переліку під назвою Show Directories For (Показати директорії). Двічі клацніть на полі з крапочками в останньому рядку переліку. Потім перейдіть в директорію, в якій зберігається потрібний заголовний файл. Крапочки в полі будуть замінені на новий шлях до файлу. Натисніть <ОК>|. Ще можна набрати повний шлях до цієї директорії в полі Location (Розміщення).
Б.3.3. Збереження, закриття і відкриття проектів
Щоб зберегти проект, виберіть пункт Save Workspace (Зберегти робочу область). Щоб закрити пункт Close Workspace (Закрити робочу область) (відповідайте ствердно на запит закриття усіх вікон документів). Для відкриття наявного проекту виберіть пункт Open Workspace (Відкрити робочу область) з меню File (Файл). Перейдіть в необхідний каталог і відкрийте потрібний файл з розширенням *.dsw. Клацніть на кнопці Open (Відкрити).
Б.3.4. Компілювання і компонування
Як і у випадку роботи з однофайловими програмами, простим способом відкомпілювати, скомпонувати і запустити багатофайлову програму є вибір пункту Execute (Виконати) з меню Build (Компонування). Якщо запускати програму прямо з системи не потрібно, можна вибрати пункт Build (Компонування) з однойменного меню.
Б.4. Програми з консольною графікою
Програми, що використовують функції консольної графіки (описувані в дод. Д), вимагають декількох додаткових дій порівняно з іншими програмами. Вам знадобляться файли msoftcon.h і msoftcon.cpp. Вони були створені спеціально для цього навчального посібника, тому їх можна знайти тільки на сайті, адреса якого вказана у введенні.
1. Відкрийте початковий файл програми, як це було описано вище. У цьому файлі повинен бути рядок #indude "msoftcon.h".
2. Виберіть пункт Build (Компонування) з однойменного меню. Відповідайте ствердно на питання про створення звичайної робочої області проекту. Буде створений проект, але компілятор видасть повідомлення про те, що не знайдений файл msoftcon.h. У цьому файлі містяться оголошення функцій консольної графіки.
3. Найпростіше скопіювати цей файл в каталог з початковими файлами. Правильніше було б повідомити компілятор про те, де він може знайти цей файл. Слідуйте настановам з розд. "Визначення місцезнаходження заголовних файлів" даного додатку.
4. Тепер знову спробуйте скомпонувати свою програму. Цього разу компілятор знайде заголовний файл, але буде довго призупиняти свою роботу від кожної знайденої в ньому "помилки", оскільки компонувальник не знає, де шукати визначення графічних функцій. А вони знаходяться у файлі msoftcon.cpp. Підключіть його до програми, як це було описано в розділі "Додавання початкових файлів" даного додаток.
Тепер програма повинна відкомпілюватися та скомпонуватися нормально. Виберіть Execute (Виконати) з меню Build (Компонування) для того, щоб подивитися, як вона працює.
Б.5. Відлагодження програм
У розд. 4 "Настанови керування ходом виконання С++-програми" ми пропонували використовувати відлагоджувач для того, щоб легше було розібратися, що таке цикл. Тепер перед Вами конкретні рекомендації з використання вбудованого відлагоджувача Microsoft Visual C++.
Ті ж самі дії допоможуть Вам зрозуміти, де саме трапляються помилки, і як їх усувати. У цьому додатку ми розглядатимемо тільки однофайлові консольні програми, але той же підхід з невеликими варіаціями застосовується і для багатофайлових програм.
Почніть із звичайного компонування своєї програми. Спробуйте виправити всі помилки компілятора і компонувальника. Переконайтеся в тому, що код програми доступний у вікні редагування.
Б.5.1. Покрокове трасування
Щоб запустити відлагоджувач, просто натисніть F10. Ви побачите жовту стрілку поряд з вікном документа, що вказує на рядок з відкритою фігурною дужкою в main(). Якщо Ви хочете починати трасування не з початку, то встановіть курсор на потрібний рядок. Потім з меню Debug (Відлагодження), яке в цьому режимі замінює меню Build (Компонування), виберіть Start Debug (Почати відлагодження), а після цього Run to Cursor (Виконати до курсора). Жовта стрілка тепер з'явиться слідом за вибраним виразом.
Натисніть клавішу F10. Це приведе до того, що відлагоджувач перейде на наступну команду, яку можна виконувати. Відповідно, туди ж зрушиться стрілка. Кожне натиснення F10 означає крок трасування, тобто перехід до наступного виразу. Якщо Ви проганяєте цикл, то побачите, як стрілка доходить до останнього виразу, а потім перескакує знову на початок циклу.
Б.5.2. Перегляд значень змінних
Існує можливість перегляду значень змінних у процесі покрокового трасування. Клацніть на закладці Locals (Локальні) в лівому нижньому кутку екрану, щоб побачити локальні змінні. Закладка Auto (Авто) покаже вибірку змінних, зроблену компілятором.
Якщо потрібно створити власний набір змінних, що проглядаються, внесіть їх у вікно перегляду, розташоване в правому нижньому кутку екрану. Щоб зробити це, клацніть правою кнопкою миші на імені змінної в початковому коді програми. Із спливаючого меню, що з'явилося, виберіть пункт QuickView (Швидкий перегляд). У діалоговому вікні клацніть на Add watch (Додати) для підтвердження свого наміру. Ім'я змінної та її поточне значення з'явиться у вікні перегляду. Якщо змінна поки що недоступна (наприклад, ще не визначена у програмі), вікно перегляду видасть повідомлення про помилку замість значення поряд з іменем змінної.
Б.5.3. Покрокове трасування функцій
Якщо у програмі використовуються функції, є чудова можливість здійснити покрокове трасування кожного виразу функції. Це робиться за допомогою клавіші F11. На відміну від режиму трасування по клавіші F10, який розглядає кожну зустрінуту функцію як один вираз, такий режим дає змогу "увійти" всередину функції та виявити можливі помилки в ній. Якщо Ви примусите по клавіші F11 проходити бібліотечні функції, наприклад cout <<, то зможете милуватиметеся початковим кодом бібліотеки. Це процес довгий, тому радимо користуватися цією можливістю, тільки якщо Вам дійсно важливо знати, що відбувається усередині рутинних функцій. Втім, можна в міру потреби чергувати натиснення клавіш F10 і F11, залежно від необхідності виявлення помилок у внутрішніх функціях.
Б.5.4. Використання точок зупинки роботи програми
Точки зупинки, як випливає з їх назви, дають змогу тимчасово переривати роботу програми у вказаних Вами місцях. Коли їх потрібно використовувати? Ми вже показали, як можна примусити відлагоджувач проганяти програму тільки до курсора. Але бувають випадки, коли необхідно мати декілька таких точок. Наприклад, можна зупинити програму в кінці умови if, а також після відповідної else. Точки зупинки вирішують це завдання, оскільки їх можна ставити в необмеженій кількості. У них є ще і розширені функції, які ми тут розглядати не будемо.
Розглянемо, як вставити точки зупинки в код програми. По-перше, встановіть курсор на той рядок, у якому програма при трасуванні повинна зупинитися. Натисніть праву кнопку миші і виберіть з меню Insert/Delete Breakpoint (Вставити/Видалити точку зупинки). Напроти цього рядка коду програми з'явиться червоний кружок. Тепер, навіть якщо Ви просто запустите програму на виконання (вибравши, наприклад, Debug/Go (Відлагодження/Запуск)), програма зупиниться на цьому рядку. Можна на цьому часовому зрізі перевірити значення змінних, провести покрокове трасування коду програми і т.д. Загалом, можна зробити все, що Вам заманеться, наприклад, взагалі вийти з програми.
Щоб видалити точку зупинки, натисніть праву кнопку миші і виберіть пункт Видалити з меню, що з'явилося.
Незважаючи на те, що є ще багато інших функцій відлагоджувача, проте ми тут показали тільки деякі основні з них для того, щоб Вам було з чого почати роботу.
Додаток В. Дещо про С-систему введення-виведення
Цей додаток містить короткий опис С-системи введення-виведення. Незважаючи на те, що Ви передбачаєте використовувати С++-систему введення-виведення, є ряд причин, згідно з якими Вам все-таки необхідно розуміти основи орієнтованої С-системи введення-виведення. По-перше, якщо Вам доведеться працювати з С-кодом (особливо, якщо виникне потреба його перекладу у С++-код), то Вам потрібно знати, як працює С-система введення-виведення. По-друге, часто в одній і тій самій програмі використовуються як С-, так і С++-операції введення-виведення даних. Це особливо характерний для дуже великих програм, окремі частини яких писалися різними програмістами протягом достатньо тривалого періоду часу. По-третє, велика кількість тих, що існують С-програм продовжують знаходитися в експлуатації і потребують підтримки. Нарешті, багато книг і періодичних видань містять програми, написаних мовою програмування С. Щоб розуміти ці С-програми, необхідно розуміти основи функціонування С-системи введення-виведення.
Необхідно пам'ятати! Для С++-програм необхідно використовувати об'єктно-орієнтовану С++-систему введення-виведення.
У цьому додатку описані найбільш споживані С-орієнтовані функції введення-виведення. Проте стандартна С-бібліотека містить таку величезну кількість функцій введення-виведення даних, що ми не в стані розглянути їх тут у повному об'ємі. Якщо ж Вам доведеться серйозно зануритися у С-програмування, то рекомендуємо звернутися до довідкової літератури.
Система введення-виведення мови С вимагає містити у програми заголовний файл stdio.h (йому відповідає заголовок <cstdio>, що відповідає новому стилю). Кожна С-програма повинна використовувати заголовний файл stdio.h, оскільки мова С не підтримує С++-стиль внесення заголовків. С++-програма може виконувати дії з використанням будь-якого з цих двох варіантів. Заголовок <cstdio> поміщає свій вміст у простір імен std, а заголовний файл stdio.h – у глобальний простір імен, що відповідає С-орієнтації. У цьому додатку як приклади наведені С-програми, тому вони використовують С-стиль внесення заголовного файлу stdio.h і не вимагають встановлення простору імен.
Необхідно пам'ятати! Як наголошувалося в розд. 1, стандарт мови С був оновлений у 1999 році і отримав назву стандарту С99. У той час у С-систему введення-виведення було внесено декілька удосконалень. Але оскільки мова C++ опирається на стандарт С89, то він не підтримує засобів, які були додані у стандарт С99. Понад це, на момент написання цього навчального посібника жоден з широко доступних компіляторів C++ не підтримував стандарт С99. Та і жодна з широко поширюваних програм не використовувала засоби стандарту С99. Тому тут не описуються засоби, внесені у С-систему введення-виведення стандартом С99. Якщо ж Вас цікавить мова С, в т.ч. повний опис його системи введення-виведення і засобів, доданих стандартом С99, рекомендуємо звернутися до книги Герберта Шілдта "Полный справочник по C++" [27].
В.1. Використання потоків у С-системі введення-виведення
Подібно С++-системі введення-виведення, С-орієнтована система введення-виведення базується на понятті потоку. На початку роботи програми автоматично відкриваються три наперед певні текстові потоки: stdin, stdout і stderr. Їх називають стандартними потоками введення даних (вхідний потік), виведення даних (вихідний потік) і помилок відповідно. (Деякі компілятори відкривають також і інші потоки, які залежать від конкретної реалізації системи.) Ці потоки є С-версії потоків з in, cout і cerr відповідно. За замовчуванням вони пов'язані з відповідним системним пристроєм.
Потік |
Пристрій |
stdin |
клавіатура |
stdout |
екран |
stderr |
екран |
Необхідно пам'ятати! Більшість операційних систем, в т.ч. Windows, дають змогу перенаправляти потоки введення-виведення, тому функції зчитування і запису даних можна перенаправляти на інші пристрої. Ніколи не намагайтеся безпосередньо відкривати або закривати ці потоки.
Кожен потік, що є пов'язаним з файлом, має структуру керування файлом типу FILE. Ця структура визначена у заголовному файлі stdio.h. Ви не повинні модифікувати вміст цього блоку керування файлом.
В.2. Функції консольного введення-виведення даних
Двома найбільш популярними С-функціями введення-виведення є printf() і scanf(). Функція printf() записує дані у стандартний пристрій виведення (консоль), а функція scanf(), її доповнення, зчитує дані з клавіатури. Оскільки мова С не підтримує перевантаження операторів і не використовує операторів "<<" і ">>" як оператори введення-виведення, то для консольного введення-виведення використовуються саме функції printf() і scanf(). Обидві вони можуть обробляти дані будь-яких вбудованих типів, в т.ч. символи, рядки і числа. Але оскільки ці функції не є об'єктно-орієнтованими, їх не можна використовувати безпосередньо для введення-виведення об'єктів класів, що створюються програмістом.
В.2.1. Використання функції printf()
Функція printf() має такий прототип:
int printf(const char *fmt_string,.);
Перший аргумент Јmt_string, визначає спосіб відображення всіх подальших аргументів. Цей аргумент часто називають рядком форматування. Вона складається з елементів двох типів: тексту і специфікаторів формату. До елементів першого типу належать символи (текст), які виводяться на екран. Елементи другого типа (специфікатори формату) містять команди форматування, які визначають спосіб відображення аргументів. Команда форматування починається з символу відсотка, за яким знаходиться код формату. Специфікатори формату перераховані в табл|. В.1. Кількість аргументів повинна точно збігатися з кількістю команд форматування, причому збіг обов'язковий і у порядку їх проходження. Наприклад, під час виклику наведеної нижче функції printf()
printf("Привіт %c %d %s", 'c', 10, "всім!");
на екрані буде відображений "Привіт з 10 всім!".
Функція printf() повертає число реально виведених символів. Негативне значення повернення свідчить про помилку.
Команди формату можуть мати модифікатори, які задають ширину поля, точність (кількість десяткових розрядів) і ознака вирівнювання по лівому краю. Ціле значення, розташоване між знаком % і командою форматування, виконує роль специфікатора мінімальної ширини поля. Наявність цього специфікатора приведе до того, що результат буде заповнений пропусками або нулями, щоб гарантований забезпечити для значення, що виводиться, задану мінімальну довжину. Якщо значення (рядок або число), що виводиться, більше за цей мінімум, його буде виведено повністю, незважаючи на перевищення мінімуму. За замовчуванням як заповнювач використовується пропуск. Для заповнення нулями потрібно помістити 0 перед специфікатором ширини поля. Наприклад, рядок форматування %05d доповнить число, що виводиться, нулями (їх буде менше п'яти), щоб загальна довжина була дорівнювала п'яти символам.
Табл. В.1. Специфікатори формату функція printf()
Код |
Формат |
%c |
Символ |
%d |
Десяткове ціле із знаком |
%i |
Десяткове ціле із знаком |
%е |
Експоненціальне представлення (рядкова буква е) |
%Е |
Експоненціальне представлення (прописна буква е) |
%f |
Значення з плинною крапкою |
%g |
Використовує коротший з двох форматів: %е або %f (якщо %е, використовує рядкову букву е) |
%G |
Використовує коротший з двох форматів: %е або %f (якщо %е використовує прописну букву е) |
%о |
Вісімкове ціле без знаку |
%s |
Рядок символів |
%u |
Десяткове ціле без знаку |
%x |
Шістнадцяткове ціле без знаку (рядкові букви) |
%x |
Шістнадцяткове ціле без знаку (прописні букви) |
%Р |
Покажчик |
%n |
Відповідний аргумент повинен бути покажчиком на ціле. Даний специфікатор зберігає у цьому цілому число символів, виведених у вихідний потік до поточного моменту (до виявлення специфікатора %n) |
%% |
Виводить символ % |
Точне значення модифікатора точності залежить від коду програми формату, до якого він застосовується. Щоб додати модифікатор точності, поставте за специфікатором ширини поля десяткову крапку, а після неї значення специфікації точності. Для форматів а, А, е, Е, f і F модифікатор точності визначає число десяткових знаків, що виводяться. Наприклад, рядок форматування %10.4f забезпечить виведення числа, ширина якого складе не менше десяти символів, з чотирма десятковими знаками. Стосовно цілих або рядкам, число, наступне за крапкою, задає максимальну довжину поля. Наприклад, рядок форматування %5.7s відобразить рядок завдовжки не менше п'яти, але не більше семи символів. Якщо рядок, що виводиться, виявиться довшим за максимальну довжину поля, кінцеві символи будуть відсічені.
За замовчуванням усі значення, що виводяться, вирівнюються по правому краю: якщо ширина поля більше від значення, що виводиться, його буде вирівняно по правому краю поля. Щоб встановити вирівнювання по лівому краю, поставте знак "мінус" відразу після знаку %. Наприклад, рядок форматування %-10.2f забезпечить вирівнювання дійсного числа (з двома десятковими знаками у 10-символьному полі) по лівому краю. Розглянемо програму, у якій продемонстровано механізм використання специфікаторів ширини поля і вирівнювання по лівому краю.
#include <stdio.h> // Для введення/виведення
int main()
{
printf("|%11.6 f|\n", 123.23);
printf("|%-11.6 f|\n", 123.23);
printf("|%11.6 s|\n", "Привіт усім");
printf("|%-11.6 s|\n", "Привіт усім");
getch(); return 0;
}
У процесі виконання ця програма відображає на екрані такі результати:
123.230000 123.230000
Привіт Привіт
Існують два модифікатори команд форматування, які дають змогу функції printf() відображати короткі (short) і довгі (long) цілі. Ці модифікатори можуть застосовуватися до специфікаторів типу d, i, про, і, х і x. Модифікатор 1 повідомляє функцію printf() про довгий формат значення. Наприклад, рядок %ld означає, що повинно бути виведено довге ціле. Модифікатор h вказує на Додаток короткого формату. Отже, рядок %hu означає, що цілочисельне значення, що виводиться, має тип short unsigned.
Щоб позначити, що відповідний аргумент вказує на довге ціле, до специфікатора п можна застосувати модифікатор 1. Для вказівки на коротку цілу застосуєте до специфікатора п модифікатор h.
Якщо Ви використовуєте сучасний компілятор, який підтримує додані у 1995 році засоби роботи з символами широкого формату (двобайтовими символами), то можете задіювати модифікатор 1 стосовно специфікатора з, щоб повідомити про використання двобайтових символів. Окрім того, модифікатор 1 можна використовувати з командою формату s для виведення рядка двобайтових символів.
Модифікатор 1 можна також поставити перед командами форматування дійсних чисел е, Е, f, F, g і G. У цьому випадку він повідомить про виведення значення типу long double.
В.2.2. Використання функції scanf()
Функція scanf()– це С-функція загального призначення введення даних з консольного пристрою. Вона може зчитувати дані всіх вбудованих типів і автоматично перетворить числа у відповідний внутрішній формат. Її поведінка багато в чому назад поведінці функції printf(). Загальний формат функції scanf() такий:
int scanf(const char *fmt_string,.);
Керівний рядок задається параметром fmt_string, складається з символів трьох категорій:
специфікаторів форматy;
"пропускних" символів (пропуски, символи табуляції та порожнього рядка);
символів, відмінних від "пропускних".
Функція scanf() повертає кількість введених полів, а під час виникнення помилки значення EOF (воно визначене у заголовку stdio.h).
Специфікатори формату ним передує знак відсотка (%) повідомляють, якого типу дане буде лічене наступним. Наприклад, специфікатор %s прочитає рядок, а %d ціле значення. Ці коди наведено в табл|. В.2.
Табл. В.2. Специфікатори формату функції scanf()
Код |
Значення |
%c |
Зчитує один символ |
%d |
Зчитує десяткове ціле |
%i |
Зчитує ціле в будь-якому форматі (десяткове, вісімкове|, шістнадцяткове|) |
%е |
Зчитує дійсне число |
%f |
Зчитує дійсне число |
%F |
Аналогічно коду програми %f (тільки С99) |
%g |
Зчитує дійсне число |
%o |
Зчитує вісімкове| число |
%s |
Зчитує рядок |
%x |
Зчитує шістнадцяткове| число |
%p |
Зчитує покажчик |
%n |
Приймає ціле значення, дорівнює кількості символів, зчитаних дотепер |
%u |
Зчитує десяткове ціле без знаку |
%[ ] |
Проглядає набір символів |
%% |
Зчитує знак відсотка |
Пропускні символи в рядку форматування примушують функцію scanf() пропустити один або декілька пропускних символів у вхідному потоці. Під пропускним символом маємо на увазі пропуск, символ табуляції або символ нового рядка. По суті, один пропускний символ у керівному рядку примусить функцію scanf() зчитувати, але не зберігати будь-яку кількість (нехай навіть нульове) пропускних символів до першої непропускної.
"Непропускний" символ у рядку форматування примушує функцію scanf() прочитати і відкинути відповідний символ. Наприклад, під час використання рядка форматування %d, %d функція scanf() спочатку прочитає ціле значення, потім прочитає і відкине кому і нарешті прочитає ще одне ціле. Якщо заданий символ не виявиться, робота функції scanf() буде завершена.
Всі змінні, що використовуються для прийому значень за допомогою функції scanf(), повинні передаватися за допомогою їх адрес. Це означає, що всі аргументи мають бути покажчиками на змінні. (Мова С не підтримує посилання або посилальні параметри.) Передача покажчиків дає змогу функції scanf() змінювати значення будь-якого аргументу. Наприклад, якщо потрібно рахувати цілочисельне значення у змінну count, використовується наступний виклик функції:
scanf().scanf("%d" &count);
Рядки звичайно зчитуються у символьні масиви, а ім'я масиву (без індексу) є адресою першого елемента у цьому масиві. Тому, щоб рахувати рядок у символьний масив address, використовують такий програмний код:
char address[80];
scanf("%s", address);
У цьому випадку параметр address вже є покажчиком, і тому йому не потрібно передувати оператором "&".
Елементи вхідного потоку, що зчитуються функцією scanf(), мають бути розділені пропусками, символами табуляції або нового рядка. Такі символи, як кома, крапка з комою і тому подібне, не розпізнаються як роздільники. Це означає, що настанова
scanf("%d%d" &r, &c);
прийме значення, введені як 10 20, але навідріз відмовиться від "блюда", поданого у вигляді 10,20.
Подібно до printf(), у функції scanf() специфікатори формату за порядком зіставляються із змінними, перерахованими у списку аргументів.
Символ "*", що знаходиться після знаку "%" і перед кодом формату, прочитає дані заданого типу, але заборонить їх присвоєння змінній. Отже, настанова
scanf("%d%*c%d" &x, &y);
під час введення даних у вигляді 10/20 помістить значення 10 у змінну х, відкине знак ділення і привласнить значення 2 0 змінною у.
Команди форматування можуть містити модифікатор максимальної довжини поля. Він є ціле число, що розташовується між знаком "%" і кодом формату, яке обмежує кількість символів, що зчитуються для будь-якого поля. Наприклад, якщо виникає бажання прочитати у змінну str не більше 20 символів, використаємо таку настанову:
scanf("%20 s", str);
Якщо вхідний потік містить більше 20 символів, то під час подальшого виконання операції введення зчитування почнеться з того місця, у якому "зупинився" попередній виклик функції scanf(). Наприклад, якщо (під час використання даного прикладу) вводиться такий рядок символів:
ABCDEFGHIJKLMNOPQRSTUVWXYZ
то у змінну str будуть прийняті тільки перші 20 символів (до букви 'Т'), оскільки команда форматування тут містить модифікатор максимальної довжини поля. Це означає, що решта символів, "UVWXYZ", не буде використана взагалі. У разі іншого виклику функції
scanf() scanf("%s", str);
символи "UVWXYZ" помістилися б у змінній str. Внаслідок виявлення "пропускного" символу введення даних для поля може завершитися до досягнення максимальної довжини поля. У цьому випадку функція scanf() переходить до зчитування наступного поля.
Незважаючи на те, що пропуски, символи табуляції та нового рядка використовуються як роздільники полів, під час зчитування одиночного символу вони читаються подібно до будь-якого іншому символу. Наприклад, якщо вхідний потік складається з символів х у, то настанова
scanf("%c%c%c" &а, &b, &c);
помістить символ х у змінну а, пропуск у змінну b і символ в у змінну c.
Функцію scanf() можна також використовувати як набір сканованих символів (scansei). У цьому випадку визначається набір символів, які можуть бути зчитані функцією scanf() і присвоєні відповідному масиву символів. Функція scanf() продовжує зчитувати символи і поміщати юс| у відповідний символьний масив доти, доки не трапиться символ, відсутній у заданому наборі. Після цього вона переходить до наступного поля (якщо таке є).
Для визначення такого набору необхідно помістити символи, що підлягають скануванню, у квадратні дужки. Відкриваюча квадратна дужка повинна знаходитися відразу за знаком відсотка. Наприклад, наступний набір сканованих символів вказує на те, що необхідне прочитати тільки символи x, y і z.
%[XYZ]
Відповідна набору змінна повинна бути покажчиком на масив символів. Під час повернення з функції scanf() цей масив міститиме рядок, що має завершальний нуль-символ, який складається з зчитаних символів. Наприклад, наведений нижче код програми використовує набір сканованих символів для зчитування цифр у масив s1. Якщо буде введений символ, відмінний від цифри, масив s1 завершиться нульовим символом, а решта символів зчитуватиметься в масив s2 доти, доки не буде введений наступний "пропускний" символ.
// Простий приклад використання набору сканованих символів.
#include <stdio.h> // Для введення/виведення
int main()
{
char s1[80], s2[80];
printf("Введіть числа, а потім декілька букв:\n");
scanf("%[0123456789]%s", s1, s2);
printf("%s %s", s1, s2);
getch(); return 0;
}
Багато компіляторів дають змогу за допомогою дефіса задати в наборі сканованих символів діапазон. Наприклад, у процесі виконання такої настанови функція scanf() прийматиме символи від А до z.
%[A-z]
При цьому в наборі сканованих символів можна задати навіть декілька діапазонів. Наприклад, ця програма зчитує спочатку цифри, а потім букви.
/* Демонстрація механізму використання в наборі сканованих символів
декількох діапазонів. */
#include <stdio.h> // Для введення/виведення
int main()
{
char s1[80], s2[80];
printf("Введіть числа, а потім декілька букв:\n");
scanf("%[0-9]%[a-zA-z]", s1, s2);
printf("%s %s", s1, s2);
getch(); return 0;
}
Якщо перший символ у наборі сканованих символів є знаком вставки (Л), то отримуємо зворотний ефект: дані, що вводяться, зчитуватимуться до першого символу із заданого набору символів, тобто знак вставки примушує функцію scanf() приймати будь-які символи, які не визначені в наборі. У наступній модифікації попередньої програми знак вставки використовують для заборони зчитування символів, тип яких вказано у наборі сканованих символів:
/* Демонстрація механізму використання набору сканованих символів для
заборони зчитування вказаних у ньому символів. */
#include <stdio.h> // Для введення/виведення
int main()
{
char s1[80], s2[80];
printf("Введіть не цифри, а потім не букви:\n");
scanf("%[^0-9]%[^а-zA-z]", s1, s2);
printf("%s %s", s1, s2);
getch(); return 0;
}
Важливо пам'ятати, що набір сканованих символів розрізняє прописні і рядкові букви. Отже, якщо виникає бажання сканувати як прописні, так і рядкові букви, задайте їх окремо.
Деякі специфікатори формату можуть використовувати такі модифікатори, які точно указують тип змінної, що приймає дані. Щоб прочитати довге ціле, поставте перед специфікатором формату модифікатор 1, а щоб прочитати коротке ціле модифікатор h. Ці модифікатори можна використовувати з кодами формату d, i, про, u, x і п.
За замовчуванням специфікатори f, е і g примушують функцію scanf() присвоювати дані змінним типу float. Якщо поставити перед одним з цих специфікаторів формату модифікатор 1, функція scanf() привласнить прочитане дане змінній типу double. Використання ж модифікатора L означає, що змінна, що приймає значення, має тип long, double.
Модифікатор 1 можна застосувати і до специфікатора з, щоб позначити покажчик на двобайтовий символ з типом даних whcar_t (якщо Ваш компілятор відповідає стандарту C++). Модифікатор 1 можна також використовувати з кодом формату s, щоб позначити покажчик на рядок двобайтових символів. Окрім того, модифікатор 1 можна використовувати для модифікації набору сканованих двобайтових символів.
В.3. С-система оброблення файлів
Незважаючи на те, що файлова система в C відрізняється від тієї, що використовується у мові програмування C++, між ними є багато загального. С-система оброблення файлів складається з декількох взаємопов'язаних функцій. Найбільш популярні з них перераховані в табл|. В.3.
Загальний потік, який "цементує" С-систему введення-виведення, є файловий покажчик (file pointer). Файловий покажчик це покажчик на інформацію про файл, яка містить його ім'я, статус і поточну позицію. По суті, файловий покажчик ідентифікує конкретний дисковий файл і використовується потоком, щоб повідомити всім С-функціям введення-виведення, де вони повинні виконувати операції. Файловий покажчик це змінна-покажчик типу FILE, який визначено у заголовку stdio.h.
Табл. А.3. С-функції оброблення файлів
Функція |
Призначення |
fopen() |
Відкриває потік |
fclose() |
Закриває потік |
fputc() |
Записує символ у потік |
fgetc() |
Зчитує символ з потоку |
fwrite() |
Записує блок даних у потік |
fread() |
Зчитує блок даних з потоку |
fseek() |
Встановлює індикатор позиції файлу на заданий байт у потоці |
fprintf() |
Робить для потоку те, що функція printf() робить для консолі |
fscanf() |
Робить для потоку те, що функція scanf() робить для консолі () |
feof() |
Повертає значення true, якщо досягнуто кінець файлу |
ferror() |
Повертає значення true, якщо виникла помилка |
rewind() |
Встановлює індикатор позиції файлу у початок файлу |
remove() |
Видаляє файл |
В.3.1. Використання функції fopen()
Функція fopen() виконує три завдання.
відкриває потік;
пов'язує файл з потоком;
повертає покажчик типу FILE на цей потік.
Найчастіше під файлом маємо на увазі дисковий файл. Функція fopen() має такий прототип:
FILE *fopen(const char * filename, const char *mode);
У цьому записі параметр filename вказує на ім'я файлу, що відкривається, а параметр mode- на рядок, що містить потрібний статус (режим) відкриття файлу. Можливі значення параметра mode показані у наведеній табл. В.4. Параметр filename повинен представляти рядок символів, які становлять ім'я файлу, яке допустимо у даній операційній системі. Цей рядок може містити специфікацію шляху, якщо діюче середовище підтримує таку можливість.
Табл. В.4. Допустимі значення параметра anode
mode |
Призначення |
"r" |
Відкриває текстовий файл для зчитування |
"w" |
Створює текстовий файл для запису |
"а" |
Відкриває текстовий файл для запису у кінець файлу |
"rb" |
Відкриває двійковий файл для зчитування |
"wb" |
Створює двійковий файл для запису |
"ab" |
Відкриває двійковий файл для запису у кінець файлу |
"r+" |
Відкриває текстовий файл для зчитування і запису |
"w+" |
Створює текстовий файл для зчитування і запису |
" a+ " |
Відкриває текстовий файл для зчитування і запису у кінець файлу |
"r+b" |
Відкриває двійковий файл для зчитування і запису |
"w+b" |
Створює двійковий файл для зчитування і запису |
"a + b" |
Відкриває двійковий файл для зчитування і запису у кінець файлу |
Якщо функція fopen() успішно відкрила заданий файл, вона повертає покажчик FILE. Цей покажчик ідентифікує файл і використовується більшістю інших файлових системних функцій. Він не повинен піддаватися модифікації кодом програми. Якщо файл не вдається відкрити, повертається нульовий покажчик.
Як видно з табл. В.4, файл можна відкривати або в текстовому, або у двійковому режимі. Під час відкриття в текстовому режимі виконуються перетворення деяких послідовностей символів. Наприклад, символи нового рядка перетворяться у послідовності символів "повернення каретки" / "переведення рядка". У двійковому режимі подібні перетворення не виконуються.
Якщо виникає потреба відкрити файл test для запису, використаємо таку настанову.
fp = fopen("test", "w");
У цьому записі змінна fp має тип FILE *. Проте часто для відкриття файлу використовують такий програмний код:
if((fp = fopen("test", "w"))==NULL) {
printf("Не вдається відкрити файл.");
exit(1);
}
При такому методі виявляється будь-яка помилка, пов'язана з відкриттям файлу (наприклад, під час використання захищеного від запису або заповненого диска), і тільки після цього можна робити спробу запису у заданий файл. NULL це макроім'я, що є визначеним у заголовку stdio.h.
Якщо Ви використовуєте функцію fopen(), щоб відкрити файл виключно для виконання операцій виведення (записи), будь-який вже наявний файл із заданим ім'ям буде стертий, і замість нього буде створено новий. Якщо файл з таким ім'ям не існує, він буде створено. Якщо виникає потреба додавати дані у кінець файлу, використовується режим "а". Якщо опиниться, що вказано файл не існує, він буде створено. Щоб відкрити файл для виконання операцій зчитування, необхідна наявність цього файлу. Інакше функція поверне значення помилки. Нарешті, якщо файл відкривається для виконання операцій зчитування-запису, то у разі його існування він не буде видалений; але його немає, він буде створено.
В.3.2. Використання функції fputc()
Функція fputc() використовують для виведення символів у потік, заздалегідь відкрито для запису за допомогою функції fopen(). Її прототип має такий вигляд:
int fputc(int ch, FILE *fp);
У цьому записі параметр fp файловий покажчик, що повертається функцією fopen(), а параметр ch символ, що виводиться. Файловий покажчик повідомляє функції fputc(), в який дисковий файл необхідно записати символ. Незважаючи на те, що параметр ch має тип int, у ньому використовується тільки молодший байт.
При успішному виконанні операції виведення функція fputc() повертає записаний у файл символ, інакше значення EOF.
В.3.3. Використання функції fgetc()
Функція fgetc() використовують для зчитування символів з потоку, відкритого в режимі зчитування за допомогою функції fopen(). Її прототип має такий вигляд:
int fgetc(FILE *fp);
У цьому записі параметр fp файловий покажчик, що повертається функцією fopen(). Незважаючи на те, що функція fgetc() повертає значення типу int, його старший байт дорівнює нулю. Під час виникнення помилки або досягненні кінця файлу функція fgetc() повертає значення EOF. Отже, для того, щоб рахувати весь вміст текстового файлу (до самого кінця), можна використати такий програмний код:
ch = fgetc(fp);
while(ch != EOF) {
ch = fgetc(fp);
}
В.3.4. Використання функції feof()
Файлова система у мові C може також обробляти двійкові дані. Якщо файл відкрито у режимі введення двійкових даних, то не виключено, що може бути зчитано ціле число, дорівнює значенню EOF. У цьому випадку під час використання такого коду програми перевірки досягнення кінця файлу, як ch != EOF, буде створена ситуація, еквівалентна отриманню сигналу про досягнення кінця файлу, хоча насправді фізичний кінець файлу може бути ще не досягнутий. Щоб вирішити цю проблему, у мові C передбачена функція feof(), яка використовують для визначення факту досягнення кінця файлу під час зчитування двійкових даних. Її прототип має такий вигляд:
int feof(FILE *fp);
У цьому записі параметр fp ідентифікує файл. Функція feof() повертає ненульове значення, якщо кінець файлу був-таки досягнутий; інакше нуль. Таким чином, у процесі виконання такої настанови буде зчитаний весь вміст двійкового файлу:
while(!feof(fp)) ch = fgetc(fp);
Безумовно, цей метод застосовний і до текстових файлів.
В.3.5. Використання функції fclose()
Функція fclose() закриває потік, який був відкрито у результаті звернення до функції fopen(). Вона записує у файл усі дані, що ще залишилися у дисковому буфері, і закриває файл на рівні операційної системи. Під час виклику функції fclose() звільняється блок керування файлом, що є пов'язаним з потоком, що робить його доступним для повторного використання. Ймовірно, Вам відомо про існування обмеження операційної системи на кількість файлів, які можна тримати відкритими у будь-який момент часу, тому, перш ніж відкривати наступний файл, рекомендується закрити всі файли, вже непотрібні для роботи.
Функція fclose() має такий прототип:
int fclose(FILE *fp);
У цьому записі параметр fp файловий покажчик, що повертається функцією fopen(). При успішному виконанні функція fclose() повертає нуль; інакше повертається значення EOF. Спроба закрити вже закритий файл розцінюється як помилка. Під час видалення носія даних до закриття файлу згенерує помилка, як і у разі недоліку вільного простору на диску.
В.3.6. Використання функцій fopen(), fgetc(), fputc() і fclose()
Функції fopen(), fgetc(), fputc() і fclose() становлять мінімальний набір операцій з файлами. Їх використання продемонстровано у наведеному нижче коді програми, яка виконує копіювання файлу. Звернемо Вашу увагу на те, що файли відкриваються у двійковому режимі і що для перевірки досягнення кінця файлу використовується функція feof().
Код програми В.1. Демонстрація копіювання вмісту одного файлу в іншій
#include <stdio.h> // Для введення/виведення
int main(int argc, char *argv[])
{
FILE *in, *out;
char ch;
if(argc != 3) {
printf("Bи забули ввести ім'я файлу.\n");
return 1;
}
if((in=fopen(argv[1], "rb")) == NULL) {
printf("Не вдається відкрити початковий файл.\n");
return 1;
}
if((out=fopen(argv[2], "wb")) == NULL) {
printf("Не вдається відкрити файл-приймач.\n");
return 1;
}
// Код копіювання вмісту файлу
while(!feof(in)) {
ch = fgetc(in);
if(!feof(in)) fputc(ch, out);
}
fclose(in);
fclose(out);
getch(); return 0;
}
В.3.7. Використання функції ferror() і rewind()
Функція ferror() використовують для визначення факту виникнення помилки у процесі виконання операції з файлом. Її прототип має такий вигляд:
int ferror(FILE *Јp);
У цьому записі параметр fp дійсний файловий покажчик. Функція ferror() повертає значення true, якщо у процесі виконання останньої файлової операції відбулася помилка; інакше значення false. Оскільки виникнення помилки можливе у процесі виконання будь-якої операції з файлом, функцію ferror() необхідно викликати відразу після кожної функції оброблення файлів; інакше інформацію про помилку можна просто втратити.
Функція rewind() переміщає індикатор позиції файлу у початок файлу, що задається як аргумент. Її прототип має такий вигляд:
void rewind(FILE *fp);
У цьому записі параметр fp дійсний файловий покажчик.
В.3.8. Використання функції fread() і fwrite()
У файловій системі мови С передбачено дві функції, fread() і fwrite(), які дають змогу зчитувати і записувати блоки даних. Ці функції подібні С++-функціям read() і write(). Їх прототипи мають такий вигляд:
size_t fread(void *buffer, size_t num_bytes,
size_t count, FILE *fp);
size_t fwrite(const void *buffer, size_t num_bytes
size_t count, FILE *fp);
Під час виклику функції fread() параметр buffer є покажчик на область пам'яті, яка призначена для прийому даних, що зчитуються з файлу. Функція зчитує count об'єктів завдовжки num_bytes з потоку, яка адресується файловим покажчиком fp. Функція fread() повертає кількість зчитаних об'єктів, яка може опинитися менше заданого значення count, якщо у процесі виконання цієї операції виникла помилка або був досягнуто кінець файлу.
Під час виклику функції fwrite() параметр buffer є покажчик на інформацію, яка підлягає запису у файл. Ця функція записує count об'єктів завдовжки num_bytes у потік, яка адресується файловим покажчиком fp. Функція fwrite() повертає кількість записаних об'єктів, яка буде дорівнює значенню count, якщо у процесі виконання цієї операції не було помилки.
Якщо під час виклику функцій fread() і fwrite() файл був відкрито для виконання двійкової операції, то вони можуть зчитувати або записувати дані будь-якого типу. Наприклад, наведений нижче код програми записує у дисковий файл значення типу float.
Код програми В.2. Демонстрація запису у дисковий файл значення з плинною крапкою
#include <stdio.h> // Для введення/виведення
int main()
{
FILE *fp;
float f = 12.23F;
if((fp=fopen("test","wb"))==NULL) {
printf("Не вдається відкрити файл.\n");
return 1;
}
fwrite(&f, sizeof(float), 1, fp);
fclose(fp);
getch(); return 0;
}
Як показано у цій програмі, значення буфера може виконувати (і при тому достатньо часто) одна змінна.
За допомогою функцій fread() і fwrite() часто виконується зчитування і запис вмісту масивів або структур. Наприклад, наведений нижче код програми, використовуючи одну тільки функцію fwrite(), записує вміст масиву значень з плинною крапкою balance у файл з іменем balance. Потім за допомогою однієї тільки функції fread() програма зчитує елементи цього масиву і відображає їх на екрані.
Код програми В.3. Демонстрація механізму використання функції fwrite() для запису вміст масиву значень з плинною крапкою у файл
#include <stdio.h> // Для введення/виведення
int main()
{
register int i;
FILE *fp;
float balance[100];
// Відкриваємо файл для запису.
if((fp=fopen("balance","w"))==NULL) {
printf("Не вдається відкрити файл.\n");
return 1;
}
for(i=0; i<100; i++) balance[i] = (float) i;
// Одним махом" зберігаємо весь масив balance.
fwrite(balance, sizeof balance, 1, fp);
fclose(fp);
// Онулюємо масив.
for(i=0; i<100; i++) balance[i] = 0.0;
// Відкриваємо файл для зчитування.
if((fp=fopen("balance","r"))==NULL) {
printf("Не вдається відкрити файл.\n");
return 1;
}
// Одним "махом" зчитуємо весь масив balance.
fread(balance, sizeof balance, 1, fp);
// Відображаємо вміст масиву.
for(i=0; i<100; i++) printf("%f ", balance[i]);
fclose(fp);
getch(); return 0;
}
Використовувати функції fread() і fwrite() для зчитування і запису блоків даних ефективніше, ніж багато разів викликати функції fgetc() і fputc().
В.4. Виконання операцій введення-виведення даних з довільним доступом до файлів
В.4.1. Використання функції fseek()
С-система введення-виведення дає змогу виконувати операції зчитування і запису даних з довільним доступом. Для цього слугує функція fseek(), яка встановлює потрібним чином індикатор позиції файлу. Її прототип такий.
int fseek(FILE *fp, long numbytes, int origin);
У цьому записі параметр fp файловий покажчик, що повертається функцією fopen(), параметр numbytes кількість байтів щодо початкового положення, які задаються параметром origin. Параметр origin може приймати одне наступних макроімен (визначених у заголовку stdio.h).
Ім'я |
Призначення |
SEEK_SET |
Пошук з початку файлу |
SEEK_CUR |
Пошук з поточної позиції |
SEEK_END |
Пошук з кінця файлу |
Отже, щоб перемістити індикатор позиції у файлі на numbytes байтів відносно його початку, як параметр origin необхідно використовувати значення SEEK_SET. Для переміщення щодо поточної позиції використовуйте значення SEEK_CUR, а для зсуву з кінця файлу значення SEEK_END.
Нульове значення результату функції свідчить про успішне виконання функції fseek(), а ненульове – про виникнення збою. Як правило, функцію fseek() не рекомендується використовувати для файлів, відкритих у текстовому режимі, оскільки перетворення символів може призвести до помилкових переміщень індикатора позиції у файлі. Тому краще використовувати цю функцію для файлів, відкритих у двійковому режимі. Наприклад, якщо виникає потреба рахувати 234-й байт у файлі test, виконайте такий програмний код:
Код програми В.4. Демонстрація механізму використання функції fseek()
int funс1()
{
FILE *fp;
if((fp=fopen("test", "rb")) == NULL) {
printf("Не вдається відкрити файл.\n");
exit(1);
}
fseek(fp, 234L SEEK_SET);
return getc(fp); // Зчитування одного символу розташованого
// на 234-й позиції.
}
В.4.2. Використання функції fprintf() і fscanf()
Крім розглянутих вище основних функцій введення-виведення, С-система введення-виведення містить функції fprintf() і fscanf(). Поведінка цих функцій аналогічно поведінці функцій printf() і scanf(), за винятком того, що вони працюють з файлами. Саме тому ці функції звичайно використовуються у С-програмах. Прототипи функцій fprintf() і fscanf() виглядають так:
int fprintf(FILE *fp, const char *fmt_string,.);
int fscanf(FILE *fp, const char *fmt_string,.);
У цьому записі параметр fp файловий покажчик, що повертається функцією fopen(). Функції fprintf() і fscanf() працюють подібно до функцій printf() і scanf() відповідно, за винятком того, що їх дія спрямована у файл, визначено параметром fp.
В.5. Видалення файлів
Функція remove() видаляє заданий файл. Її прототип виглядає так.
int remove(const char * filename);
Вона повертає нуль при успішному видаленні файлу і ненульове значення – в іншому випадку.
Додаток Г. Особливості використання застарілого С++-компілятора
Програми, наведені у цьому навчальному посібнику, повністю відповідають стандарту ANSI/ISO для C++ і можуть бути скомпільовані практично будь-яким сучасним С++-компілятором, в т.ч. Visual C++ (Microsoft) і C++ Builder (Borland). Отже, під час використання сучасного компілятора у Вас не повинно бути проблем з компілювання програм з цього навчального посібника1.
Але, якщо Ви використовуєте компілятор, створений кілька років тому, то під час спроби скомпілювати наші приклади він може видати цілий список помилок, не розпізнавши ряд нових С++-засобів. І у цьому випадку не варто хвилюватися. Для того, щоб ці програми запрацювали із старими компіляторами, потрібно внести в них невеликі зміни. Найчастіше старі і нові С++-програми відрізняються використанням двох засобів: заголовків і просторів імен. Ось про це і піде мова у цьому застосуванні.
Як згадувалося в розділі 2, настанова #include містить у програму заданий заголовок. Для попередніх версій C++ під заголовками розумілися файли з розширенням *.h. Наприклад, у старій С++-програмі для внесення заголовка iostream була б використана така настанова:
#include <iostream.h>
У цьому випадку у програму був би включений заголовний файл iostream.h. Таким чином, в т.ч. у стару С++-програму заголовок, необхідно задавати ім'я файлу з розширенням *.h.
У нових С++-програмах відповідно до стандарту ANSI/ISO для C++ використовуються заголовки іншого типу. Сучасні заголовки визначають не імена файлів, а стандартні ідентифікатори, які можуть збігатися з такими, але не завжди. Сучасні С++-заголовки є абстракцію, яка просто гарантує внесення у програму необхідної інформації.
Оскільки сучасні заголовки необов'язково є іменами файлів, вони не повинні мати розширення *.h. Вони визначають ім'я заголовка, поміщеного у кутові дужки. Ось, наприклад, як виглядають два сучасні заголовки, що підтримуються стандартом C++.
<iostream> // Для потокового введення-виведення
<fstream>
Щоб перетворити ці "нові" заголовки в "старі" заголовні файли, достатньо додати розширення *.h.
В т.ч. сучасний заголовок у програму, потрібно пам'ятати, що його вміст відноситься до простору імен std. Як ми вже зазначали вище, простір імен це просто декларативна область. Її призначення локалізувати імена ідентифікаторів щоб уникнути колізій з іменами. Старі версії C++ поміщають імена бібліотечних функцій у глобальний простір імен, а не у простір імен std, що використовується сучасними компіляторами. Таким чином, працюючи із старим компілятором, не потрібно використовувати цю настанову:using namespace std; // Використання стандартного простору імен
Насправді більшість старих компіляторів взагалі не сприймуть настанову using namespace.
Дві прості зміни
Якщо Ваш компілятор не підтримує простори імен і нові заголовки, він видасть одне або декілька повідомлень про помилки під час спроби скомпілювати перші декілька рядків програм, наведених у цьому навчальному посібнику. У цьому випадку в ці програми необхідно внести тільки дві прості зміни: використовувати заголовок старого типа і видалити namespace-настанову. Наприклад, замініть ці настанови
#include <iostream> // Для потокового введення-виведення
using namespace std; // Використання стандартного простору імен
такою
#include <iostream.h>
Ця зміна перетворить "нову" програму в "стару". Оскільки під час використання "старого" заголовка в глобальний простір імен зчитується весь вміст заголовного файлу, необхідність у використанні namespace-настанови відпадає. Після внесення цих змін програму можна скомпілювати за допомогою старого компілятора.
Іноді доводиться вносити і інші зміни. C++ успадковує ряд заголовків з мови С. Мова С не підтримує сучасний стиль використання С++-заголовків, використовуючи замість них заголовні *.h-файли. Для дозволу зворотної сумісності стандарт C++, як і раніше, підтримує заголовні С-файли. Проте стандарт C++ також визначає сучасні заголовки, які можна використовувати замість заголовних С-файлів. У С++-версіях стандартних С-заголовків до імені С-файлу просто додається префікс 'c' і опускається розширення *.h. Наприклад, С++-заголовком для файлу math.h слугує заголовок <cmath>, а для файлу string.h – заголовок <cstring>. Незважаючи на те, що у С++-програму дозволено містити заголовний С-файл, проти такого підходу у розробників стандарту є істотні заперечення (іншими словами, це не рекомендовано). Тому у справжній книзі використовуються сучасні С++-заголовки в усіх настановах #include. Якщо Ваш компілятор не підтримує С++-заголовки для С-заголовків, просто заміните "старі" заголовні файли.
Додаток Д. .NET-розширения для C++
Розроблена компанією Microsoft інтегрована оболонка .NET Framework визначає середовище, яке призначене для підтримки розробки і виконання сильно розподілених застосувань, заснованих на використанні компонентних об'єктів. Вона дає змогу "мирно співіснувати" різним мовам програмування і забезпечує безпеку, переносність програм і загальну модель програмування для платформи Windows. Незважаючи на відносну новизну оболонки .NET Framework, ймовірно, в найближчому майбутньому у цьому середовищі працюватимуть багато С++-програмісти.
Інтегрована оболонка .NET Framework надає кероване середовище, яке стежить за виконанням програми. Програма, призначена для приміщення в оболонку .NET Framework, не компілюється з метою отримання об'єктного коду програми. Натомість вона перекладається проміжною мовою Microsoft Intermediate Language (MSIL), а потім виконується під управлянням універсального засобу CLR (Common Language Runtime). Кероване виконання це механізм, який підтримує ключові переваги, пропоновані оболонкою .NET Framework.
Щоб скористатися перевагами керованого виконання, необхідно застосовувати для С++-програм спеціальний набір нестандартних ключових слів і директив препроцесора, які були визначені розробниками компанії Microsoft. Важливо розуміти, що цей додатковий набір не включений у стандарт C++ (ANSI/ISO Standard C++). Тому програмний код, у якому використовуються ці ключові слова, не можна переносити в інші середовища виконання.
Опис оболонки .NET Framework і методів С++-програмування, необхідних для її використання, виходить за рамки цього навчального посібника. Проте тут наведено короткий огляд .NET-розширення мови програмування C++ заради тих програмістів, які працюють в .NET-середовищу.
Д.1. Ключові слова .NET-середовища
Для підтримки .NET-середовища керованого виконання С++-програм Microsoft вводить в мову C++ такі ключові слова:
__abstract |
__box |
__delegate |
__event |
__finally |
__gc |
__identifier |
__interface |
__nogc |
__pin |
__property |
__sealed |
__try_cast |
__typeof |
__value |
Короткий опис кожного з цих ключових слів наведений у наступних розділах.
Ключове слово __abstract
Ключове слово __abstract використовується у поєднанні із словом __gc під час визначення абстрактного керованого класу. Об'єкт __abstract-класса створити не можна. Для класу, визначеного з використанням ключового слова __abstract, необов'язково внесення в нього чисте віртуальній функції.
Ключове слово __box
Ключове слово __box укладає у спеціальну оболонку значення усередині об'єкта. Таке "упакування" дає змогу використовувати тип цього значення у коді, який вимагає, щоб даний об'єкт був виведений з класу System::Object, базового класу для всіх .NET-об'єктів.
Ключове слово __delegate
Ключове слово __delegate визначає об'єкт-делегат, який інкапсулює покажчик на функцію усередині керованого класу (тобто класу, модифікованого ключовим словом__gc).
Ключове слово __event
Ключове слово __event визначає функцію, яка представляє деяку подію. Для такої функції задається тільки прототип.
Ключове слово __finally
Ключове слово __finally це доповнення до стандартного С++-механізму оброблення виняткових ситуацій. Воно використовують для визначення блоку коду програми, який повинен виконуватися після виходу з блоків try/catch. При цьому не має значення, які умови приводять до завершення try/caten-блока. Блок__finally повинен бути виконаний у будь-якому випадку.
Ключове слово __gc
Ключове слово __gc визначає керований клас. Позначення "gc" є скорочення від словосполучення "garbage collection" (тобто "сбирання сміття") і означає, що об'єкти цього класу автоматично піддаються процесу утилізації пам'яті, що звільняється під час роботи програми, коли вони більше не потрібні. В об'єкті відпадає необхідність у разі, коли на нього не існує жодного посилання. Об'єкти __gc-класса повинні створюватися за допомогою оператора new. Масиви, покажчики і інтерфейси також можна визначати з використанням ключового слова__gc.
Ключове слово __identifier
Ключове слово __identifier дає змогу будь-якому іншому ключовому слову мови програмування C++ використовуватися як ідентифікатор. Ця можливість не призначена для широкого застосування і введена для вирішення спеціальних завдань.
Ключове слово __interface
Ключове слово __interface визначає клас, який повинен діяти як інтерфейс. У будь-якому інтерфейсі жодна з функцій не повинна містити тіло, тобто всі функції інтерфейсу є опосередковано заданими суто віртуальними функціями. Таким чином, інтерфейс є абстрактний клас, у якому не реалізована жодна з його функцій.
Ключове слово __nogc
Ключове слово __nogc визначає некерований клас. Оскільки такий (некерований) тип класу створюється за замовчуванням, ключове слово __nogc використовується рідко.
Ключове слово __pin
Ключове слово __pin використовують для визначення покажчика, який фіксує місцезнаходження у пам'яті об'єкта, на який він вказує. Таким чином, "закріплений" об'єкт не переміщатиметься у пам'яті у процесі збірки сміття. Як наслідок, складальник сміття не у змозі зробити недійсним покажчик, модифікований за допомогою ключового слова __pin.
Ключове слово __property
Ключове слово __property визначає властивість, що є функцією-членом, яка дає змогу встановити або набути значення певної змінної (члена даних класу). Властивості надають зручний засіб керування доступом до закритих (private) або захищених (protected) даних.
Ключове слово __sealed
Ключове слово __sealed оберігає клас, що модифікується ним, від успадкування іншими класами. Це ключове слово можна також використовувати для інформування про те, що віртуальна функція не може бути перевизначена.
Ключове слово __try_cast
За допомогою ключового слова __try_cast можна спробувати перетворити тип виразу. Якщо зроблена спроба виявиться невдалою, згенерує виняток типу
System::InvalidCastException.
Ключове слово __typeof
Ключове слово __typeof дає змогу отримати об'єкт, який інкапсулює інформацію про даного типу. Цей об'єкт є примірником класу System::Type.
Ключове слово __value
Ключове слово __value визначає клас, який є позначенням типу. Будь-яке позначення типу містить власні значення. І цим тип __value відрізняється від типу __gc, який повинен виділяти пам'ять для об'єкта за допомогою оператора new. Позначення типу не представляють інтерес для "складальника сміття".
Д.2. Розширення препроцесора
Для підтримки .NET-середовища компанія Microsoft визначає директиву препроцесора using, яка використовують для імпортування метаданих у програму. Метадані містять інформацію про тип і членів класу у формі, яка не залежить від конкретної мови програмування. Таким чином, метадані забезпечують підтримку змішаного використання мов програмування. Всі керовані С++-програми повинні імпортувати бібліотеку <mscorlib.dll>, яка містить необхідні метадані для оболонки .NET Framework.
Компанія Microsoft визначає дві pragma-настанови (використовувані з директивою препроцесора #pragma), які мають відношення до оболонки .NET Framework. Перша (managed) визначає керований код. Друга (unmanaged) визначає некерований (власний, тобто притаманний даному середовищу) код. Ці настанови можуть бути використані усередині програми для селективного створення керованого і некерованого коду програми.
Використовується атрибуту attribute
Компанія Microsoft визначає атрибут attribute, який використовують для оголошення іншого атрибуту.
Компілювання керованих С++-програм
На момент написання цього навчального посібника єдиний доступний компілятор, який міг обробляти програми, що орієнтуються на роботу у середовищі .NET Framework, постачався компанією Microsoft (Visual Studio .NET). Щоб скомпілювати керовану програму, необхідно використовувати команду /clr, яка передасть Вашу програму "до рук" універсального засобу Common Language Runtime.
Література
1. Александреску А. Современное проектирование на С++. Серия С++ In-Depth. tType. 3. – М.: Изд-ий дом "Вильямс", 2002. – 336 c.
2. Аммераалъ Л. STL для программистов на С++. – М.: ДМК, 1999. – 240 с.
3. Архангельский А.Я. Программирование в С++ Builder 6. – М.: ЗАО "Изд-во БИНОМ", 2004. – 1152 с.
4. Бронштейн И.Н., Семендяев К.А. Справочник по математике для инженеров и учащихся втузов. – 13-е изд., испр. – М.: Наука, Гл. ред. физ.-мат. лит., 1986. – 544 с.
5. Буч Г. Объектно-ориентированный анализ и проектирование с примерами на С++. – М.: Бином, 1998. – 560 с.
6. Влиссидес Дж. Применение шаблонов проектирования. Дополнительные штрихи. – М.: Изд-ий дом "Вильямс", 2003. – 144 с.
7. Гамма Э., Хелм Р., Джонсон Р., Влиссидес Дж. Приемы объектно-ориентированного программирования. Патерны проектирования. – СПб.: Питер, 2004. – 366 с.
8. Глинський Я.М., Анохін В.Є., Ряжська В.А. С++ і С++ Builder. – Львів.: Деол, СПД Глинський, 2003. – 192 с.
9. Кениг Э., Му Б. Эффективное программирование на С++. Серия С++ In-Depth. tType. 2. – М.: Изд-ий дом "Вильямс", 2002. – 384 с.
10. Ласло М. Вычислительная геометрия и компьютерная графика на С++. – М.: Бином, 1997. – 304 с.
11. Лафоре, Роберт. Объектно-ориентированное программирование в С++. Классика Computer Science. 4-е изд./ Пер. с англ. – СПб.: Питер, 2005. – 924 с.
12. Либерти Д. Освой самостоятельно С++ за 21 день. – М.: Изд-ий дом "Вильямс", 2000. – 816 с.
13. Липпман С., Лажойе Ж. Язык программирования С++. Вводный курс, 3-е изд./ Пер. с англ. – СПб.-М.: Невский диалект – ДМК Пресс, 2004. – 1104 с.
14. Павловская Т.А. Программирование на языке высокого уровня: Учебник. – СПб.: Питер, 2005. – 461 с.
15. Павловская Т.А., Щупак Ю.А. С++. Объектно-ориентированное программирование: Практикум. – СПб.: Питер, 2005. – 265 с.
16. Павловская Т. С/С++. Программирование на языке высокого уровня. – СПб.: Питер, 2001. – 460 с.
17. Павловская Т., Щупак Ю. С/С++. Структурное программирование: Практикум. – СПб.: Питер, 2005. – 240 с.
18. Павловская Т., Щупак Ю. С++. Объектно-ориентированное программирование: Практикум. – СПб.: Питер, 2005. – 265 с.
19. Прата, Стивен. Язык программирования С++. Лекции и упражнения: Учебник/ Пер. с англ. – СПб.: ООО "ДиаСофтБП", 2005. – 1104 с.
20. Саттер Г. Решение сложных задач на С++. Серия С++ In-Depth. T. 4. – М.: Изд-ий дом "Вильямс", 2002. – 400 с.
21. Синтес, Антони. Освой самостоятельно объектно-ориентированное программирование за 21 день/ Пер. с англ. – М.: Изд. дом "Вильямс", 2002. – 672 с.
22. Справочник по элементарной математике: геометрия, тригонометрия, векторная алгебра/ Под ред. члена-корр. АН УССР П.Ф. Фильчакова. – К.: Наукова думка, 1966. – 444 с.
23. Страуструп Б. Язык программирования С++. – СПб.: Бином, 1999. – 991 с.
24. Халперн, Пабло. Стандартная библиотека С++ на примерах/ Пер. с англ. – М.: Изд. дом "Вильямс", 2001. – 336 с.
25. Шаллоуэй А., Тротт Д. Шаблоны проектирования. Новый подход к объектно-ориентированному анализу и проектированию. – М.: Изд-ий дом "Вильямс", 2002. – 288 с.
26. Шилдт, Герберт. Искусство программирования на С++/ Пер. с англ. – СПб.: БХВ-Петербург, 2005. – 496 с.
27. Шилдт, Герберт. Полный справочник по С++, 4-е изд./ Пер. с англ. – М.: Изд. дом "Вильямс", 2006. – 800 с.
28. Шилдт, Герберт. С++: Базовый курс, 3-е изд./ Пер. с англ. – М.: Изд. дом "Вильямс", 2005. – 624 с.
29. Шилдт, Герберт. Самоучитель С++, 3-е изд./ Пер. с англ. – СПб.: БХВ-Петербург, 2005. – 688 с.
30. Штерн В. Основы С++. Методы программной инженерии. – М.: Лори, 2003. – 860 с.
31. Элджер Д. С++: библиотека программиста. – СПб.: Питер, 2000. – 320 с.
1 ANSI є скороченням від англійської назви Американського Національного Інституту Стандартів, а ISO – від Міжнародної Організації Стандартів.
1 Для мови Асемблер характерне символічне представлення реального машинного коду, який може виконувати комп'ютер.
1 Під функцією ми розуміємо підпрограму.
2 Точніше, С++-програма починається з виклику функції main() і зазвичай закінчується поверненням з функції main().
1 Більше того, мова програмування C++ дає змогу програмісту визначати власні типи даних.
1 Необхідно пам'ятати, що Ви повинні ввести ціле число галонів, тобто число, що не містить дробової частини.
2 Як альтернативний варіант можна використовувати декілька декларативних int-настанов – результат буде той самий.
1 Безумовно, одна функція може викликати іншу.
2 Стандартну бібліотеку буде розглянуто нижче, а поки помітимо, що вона є колекцією вбудованих функцій.
1 Згадаймо, слово void використовується тільки у тому випадку, коли функція не повертає ніякого значення.
2 Все ж таки зазвичай функцію main() розміщують першою, щоб її було легко знайти.
3 Детальніше їх опис наведено нижче в цьому навчальному посібнику.
1 Окрім того, стандарт мови програмування C++ підтримує рядковий тип за допомогою бібліотечного класу string, який також описаний нижче в цьому навчальному посібнику.
1 Необхідно пам'ятати, що тут одиниця буде оброблена як значення true, а нуль – як false.
1 Пропонуємо читачу як вправу доповнити інформацію по вивчених темах, а також ввести в цю "довідкову" систему нові теми.
1 Нескінченні цикли можна також створювати, використовуючи настанови while або do-while, але цикл for – це традиційне вирішення переважної більшості питань.
2 Зупинити перебір множників можна на значенні виразу i/j, оскільки число, яке перевищує i/j, вже не може бути множником значення i.
1 Детально функція qsort() розглянута в розд. 20.
1 Згадаймо: унарному оператору потрібен тільки один операнд.
1 Спробуйте виконати цю програму і переконайтеся в цьому самі.
1 Для більшості 32-розрядних компіляторів значення i збільшуватиметься на 4, а значення f – на 8.
1 Ваші результати можуть відрізнятися від наведених, але інтервали між значеннями повинні бути такими самими
1 Інакше кожного разу після запуску програма видаватиме один і той самий "прогноз".
1 Звернемо Вашу увагу на те, що для виведення ASCII-кодів на екран використовується операція приведення типів.
1 Необхідно пам'ятати, що блок починається з відкриваючої фігурної дужки і завершується такою, що його закриває.
2 Наприклад, неможливо використовувати настанову goto для переходу в середину коду іншої функції.
1 Існує один спосіб обійти це обмеження, який буде розглядатися нижче у цій книзі.
1 Необхідно пам'ятати, що у мові програмування C++ ім'я масиву без індексу є покажчик на перший елемент цього масиву.
1 У Windows команда "Run" (Виконати) також використовує командний рядок.
1 Як і для всіх функцій, return-значення повинне бути сумісним з типом значення, що повертається.
1 Це оголошення також використовується в прототипі функції.
1 Більше того, це було б помилкою.
1 Бітові поля розглядаються нижче у цьому навчальному посібнику (див. розд. 10.4).
1 Такий стиль програмування, напевно, підійшов би тільки для того, щоб ввести в оману конкурента.
2 У загальному випадку воно трапляється на початку програми.
1 Ви отримаєте повідомлення про помилку.
1 Тільки правильний вибір може підвищити швидкодію програми.
1 Передача покажчика завжди відбувається|походить| швидше, ніж передача самої структури.
1 Оператор "стрілка" зарезервований для доступу до членів структури за допомогою покажчика.
1 Безумовно, змінна i займає два байти, а символьна змінна ch використовує тільки один.
2 Ця програма написана в припущенні, що короткі цілочисельні значення мають довжину два байти.
1 Абзац містить|утримує| 16 байтів.
1 Під чергою розуміємо перелік елементів з дисципліною обслуговування у порядку надходження, тобто "першим прибув – першим обслужений".
1 Іншими словами, об'єкт займає певну область пам'яті, а визначення типу – ні.
1 При цьому не можна вказувати навіть тип void.
1 Задля справедливості зазначимо, що класу chErga деструктор, по суті, не потрібний, а його наявність тут можна виправдати тільки з ілюстративною метою.
1 Таким чином, об'єднання також визначає тип класу.
1 Застосування операторів "крапка" і "стрілка" для об'єктів відповідає їх застосуванню для структур і об'єднань.
1 Точніше, під час її виклику не можна задавати ім'я об'єкта.
1 Іншими словами, створюється точний дублікат об'єкта.
1 Як створити конструктор копії, буде показано далі в цьому розділі.
1 Ви можете не побачити на екрані виведене "сміття". Це залежить від того, як Ваш компілятор реалізує динамічне виділення пам'яті. Проте помилка все одно тут наявна.
1 Це робиться автоматично і без нашої на те згоди.
1 Тернарний оператор "?" перезавантажувати не можна.
1 Передусім, це становить саму суть присвоєння.
2 Такий стан речей цілком узгоджується з традиційною дією оператора "=".
1 Цей параметр також використовується як ознака постфіксної форми і для оператора декремента.
1 Іншими словами, А – В не те ж саме, що В – А!
1 Підказка: одне з них викликане настановою delete в тілі операторної функції operator=().
1 Звичайно ж, його, як і раніше, можна використовувати і праворуч від оператора присвоєння.
1 Специфікатор protected описано у наступному підрозділі.
1 Проте члени i та j, як і раніше, залишаються доступними для класу derivedA.
1 Основне призначення директиви using – забезпечити підтримку просторів імен.
1 Дозвіл подібних речей зруйнував би інкапсуляцію!
1 Насправді більшість С++ програмістів вважає такий стиль програмування невдалим
1 Пригадайте, що площа круга обчислюється за формулою R2.
1 Насправді в більшості крупних програм використовуються обидва види зв'язування.
1 Окрім того, початковий код програми не захаращуватиметься декількома "вручну" перезавантаженими версіями.
1 "Правильне" закінчення означає виконання стандартної послідовності дій після завершення роботи.
1 Тип size_t, по суті, – це цілочисельний тип без знаку.
1 Пригадайте, що простір імен std використовується всіма бібліотеками стандарту мови програмування C++
1 Клас basic_ios виведений з класу ios_base, який визначає ряд нешаблонних властивостей, що використовуються класом basic_ios.
1 У разі потреби другий параметр також може мати тип посилання на об'єкт.
1 Не буде перебільшенням наголосити на тому, що серед усіх відомих структурованих мов С-система введення-виведення не має собі подібних.
1 Див. додаток В, у якому представлено огляд С-орієнтованих функцій введення-виведення.
2 Точніше, ці значення визначені у класі ios_base, який, як згадувалося вище, є базовим для класу ios.
1 Між цими і Вашими результатами можливо виникне розбіжність, викликана використанням різних компіляторів.
2 За замовчуванням після десяткової крапки відображається шість цифр.
1 Ця функція призначена в основному для внутрішнього використання. Значення результату, що повертається нею, не має нічого спільного із успадкуванням або ієрархією класів.
1 Функція, яка генерує об'єкти, іноді називається генератором об'єктів.
1 Якщо ж спроба виконати цю операцію виявилася невдалою при участі в ній посилань, генерується виняток типу bad_cast.
1 Саме ця адреса використовується під час виклику функції.
1 Цей процес подібний до процесу отримання адреси масиву, коли також використовується тільки його ім'я без індексу.
1 Безумовно, звертатися можна також і через ім'я об'єкта.
2 Звичайно ж, статична функція-член класу може отримувати доступ до нестатичних глобальних даних і функцій.
1 Наприклад, у мові програмування C++ не передбачено настанови, яка могла б заборонити переривання.
1 Цю інформацію необхідно уточнити у документації, яка додається до Вашого компілятора.
1 Як ми побачимо далі, ітерації зазвичай відповідають варіантам використання.
1 У програмі, насправді, ми використовуватимемо cout замість функції display().
1 У цьому випадку вам взагалі не знадобиться інформація, представлена у цьому застосуванні.
