Приклад створення нового консольного застосунку та його налаштування
Розглянемо можливу послідовність дій по налаштуванню програми на прикладі задачі розробки програми відшукання коренів квадратного рівняння , . Умовно окремі групи дій будемо нумерувати з метою їх структуризації. Етап 1. Створимо консольний застосунок і наберемо такий текст програми: #include <iostream> using namespace std; Етап 2. Виконаємо компіляцію. Як це видно з рис. 2.1, компілятор виявив 5 синтаксичних помилок і вивів відповідні пояснення у вікно Error List. Рис. 2.1 – Результати компіляції Програміст повинен шукати синтаксичну помилку перед курсором за текстом програми, причому не обов’язково в цьому ж рядку. Якщо здійснити подвійний клік мишкою у вікні Error List над будь-яким з рядків, у вікні коду буде здійснений перехід до рядка, в якому вперше знайдена відповідна помилка. Насправді, у даному випадку різних повідомлень тільки два: error C2065: 'd' : undeclared identifier – невизначений ідентифікатор 'd'; error C2146: syntax error : missing ';' before identifier 'cout' – синтаксична помилка: відсутній символ ';' перед ідентифікатором cout. Перше з вказаних повідомлень зустрілося 4 рази і говорить про те, що змінна d (для запису значення дискримінанту) використовується, але не визначена в програмі. Усім цим повідомлення відповідає тільки одна помилка, яка зроблена раніше першої точки, де вона була виявлена. Тому включимо змінну d у перелік змінних, описуваних у верхній частині тексту програми. Друга помилка вказує, що оператори мови C++ повинні закінчуватися символом «крапка з комою». Місце, де виявлена помилка, також не співпадає з місцем, де вона була зроблена, – треба дописати символ «крапка з комою» в кінець попереднього рядка, завершивши записаний у ньому оператор. Відзначимо, що обидві помилки виправлялися не в тих рядках, де вони були виявлені. Виправлений текст набирає такий вигляд: #include <iostream> using namespace std; Етап 3. Натиснемо інструментальну кнопку , запускаючи програму на виконання, і переконаємося, що компіляція пройде успішно і програма почне виконуватися, видавши запит на уведення коефіцієнту a. Якщо увести значення a = 1, b = 2, c = 1, то ми переконаємося, що отримані корені є правильними. Однак для a = 1, b = 5, c = 2 результати обчислень будуть неправильними. Тому треба вже шукати логічні помилки. Етап 4. Ми можемо підозрювати, що в програмі неправильно обчислюється дискримінант. Відкриємо вікно Watch 1, додамо в нього змінну d, після чого помістимо курсор у рядок, наступний за обчисленням значення дискримінанта d, і натиснемо клавішу F5. Після уведення вказаного вище другого набору значень коефіцієнтів переконуємося, що дискримінант обчислений невірно (у вікні Watch 1 виводиться значення d, яке дорівнює 9 замість 17). Помічаємо, що в тексті програми оператор d = b * b - 4 * a * a; неправильний. Виправляємо помилку: d = b * b - 4 * a * c; Якщо виконати ті ж дії, що й раніше, то виконання програми перерветься у зв’язку з виявленням помилки часу виконання, а на екран буде виведене діалогове віконце з інформацією про помилку (див. рис. 2.2). Рис. 2.2 – Віконце помилки часу виконання У зображеному на рис. 2.2 віконці виведене таке повідомлення: Run-Time Check Failure #3 – The variable 'c' is being used without being initialized. – Помилка перевірки часу виконання № 3 – Змінна 'c' використовується без попередньої ініціалізації. Це повідомлення говорить про те, що в змінну c не було записане початкове значення перед її використанням. Закриємо віконце кліком мишкою на кнопкою Break (Перервати) і переконаємося, що у вікні Watch1 для змінної d буде виведене якесь дивне значення -1.#IND. У вікнах Autos і Locals ми побачимо, що таке ж число записане і в змінну c (цим числом позначається невизначене значення типу double). Крім того, ми побачимо, що в змінну a записане значення 2, а не 1. Таким чином, десь вище є логічна помилка, яку треба виправити. Етап 5. Для відшукання помилки припиняємо виконання застосунку і натискаємо клавішу F10 для нового запуску програми в режимі налаштування. Після декількох натискань клавіші F10 і уведення вказаних трьох значень, ми помічаємо, що третій оператор уведення замість того, щоб записати значення 2 в змінну c, записав його в змінну a (це можна було побачити дещо раніше, але людина звичайно бачить ті значення, що явно виділяються, – тут невизначене значення в змінній c). Вказану помилку можна було побачити, якби ми на етапі 3 не запускали програму одразу на виконання, а зробили попередню компіляцію. У такому разі ми б побачили у вікні Error List такі три попередження: warning C4101: 'x2' : unreferenced local variable – 'x2' : невикористовувана локальна змінна; warning C4101: 'x1' : unreferenced local variable – 'x1' : невикористовувана локальна змінна; warning C4700: uninitialized local variable 'c' used – використовується локальна змінна 'c', яка не була ініцалізірована. Перші два попередження говорять про те, що локальні змінні x1, x2 оголошені, але ніколи не використовуються. Третє повідомлення свідчить, що в операторі, в якому обчислюється значення дискримінанту (а саме на нього здійснюється перехід, якщо клікнути мишкою по повідомленню) використовується локальна змінна c, в яку явно не записувалося ніяке значення. Таким чином, ми переконалися, що навіть попередження можуть свідчити про помилку, і на них треба звертати увагу. У той же час на повідомлення про змінні x1, x2 можна не звертати увагу, хоча, якщо ми не плануємо використовувати ці змінні, краще видалити їх з програми, виключивши тим самим появу попередження. З наявних у програмі двох операторів cin >> a; виправимо другий, записавши його так: cin >> c; Крім того, видалимо змінні x1, x2 з оператора опису. Якщо тепер запустити програму на виконання, то буде отриманий правильний результат, який однак ще не свідчить про відсутність логічних помилок, оскільки ми ще не перевіряли випадок відсутності коренів. Етап 6. Запустимо програму на виконання і уведемо тепер такі значення: a = 1, b = 2, c = 3. У цьому разі ми бачимо, що, з одного боку, програма виводить повідомлення про відсутність коренів, а, з другого боку, вона ще виводить два корені з досить дивними значеннями -1.#IND. Знову треба зайнятися налаштуванням. Натискаючи декілька разів клавішу F10, бачимо, що оператори виконуються в потрібній послідовності (по лівій межі вікна коду буде переміщуватися жовта стрілка, вказуючи на рядок, який буде виконуватися наступним), але після виведення повідомлення про відсутність коренів, здійснюється перехід до рядка, в якому обчислюється та виводиться перший корінь, хоч цей рядок не повинен виконуватися. Справа в тому, що в програмі використаний невірний для цієї задачі формат оператора if. Вставимо перед рядком, де виводиться перший корінь, такий рядок: else Тепер після запуску програми на виконання, ми побачимо, що помилка залишилася, але тільки по відношенню до другого кореня. За допомогою клавіші F10 переконуємося в тому, що в програмі виконується один оператор виведення, виконання якого не повинне було мати місце. Справа в тому, що в цьому випадку два оператори cout << " x1 = " << (-b + sqrt(d)) / 2 * a; повинні розглядатися як один так званий складений оператор (блок), для чого їх треба забрати у фігурні дужки. Зробимо це і отримаємо такий текст програми: #include <iostream> using namespace std; Запуск програми зі значеннями a = 1, b = 2, c = 3 тепер приведе до отримання правильного результату. Етап 7. Запустимо програму на виконання і уведемо нові значення коефіцієнтів: a = 2, b = 5, c = 3. У цьому разі ми бачимо, що обчислені корені (x1 = -4, x2 = -6) знову є неправильними (повинні бути отримані значення x1 = -1, x2 = -1.5). Треба знову здійснювати покрокове виконання програми, натискаючи клавішу F10. Оскільки ми не передбачили (точніше, знищили) змінні для запису коренів рівняння, прийдеться дивитися на результат, що виводиться на екран користувача. Це можна зробити в даному випадку, але ніяк не може бути рекомендоване для використання. Правильним є або включення у вікно Watch виразів для обчислення коренів, або повернення в програму змінних x1, x2 і добавлення операторів для запису в ці змінні коренів. У результаті ми побачимо, що всі обчислення до виведення значення першого кореня виконуються правильно, а сам корінь є невірним. Висновок – є помилка в обчисленні кореня. Уважно подивившись на оператор, ми бачимо, що в ньому порушений порядок виконання операцій, а саме, оскільки операції множення та ділення мають один і той же пріоритет, при обчисленні кореня спочатку здійснюється ділення на 2, після чого отриманий результат помножується на a. Щоб отримати правильний результат, необхідно забрати знаменник 2 * a в дужки, причому це, звісно, потрібно зробити і при обчисленні другого кореня. Після виправлення тексту отримуємо правильний результат. Таким чином, одноразове отримання правильного результату не дає гарантії того, що програма буде правильною. Остання помилка не проявлялася раніше, тому що для коефіцієнта a уводилося значення 1, яке не впливало на результат і в разі попадання цього значення в чисельник, і в разі попадання його в знаменник. Це ще раз говорить про необхідність ретельного підбору тестових даних та багаторазового тестування. ©2015 arhivinfo.ru Все права принадлежат авторам размещенных материалов.
|