Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Visual2.doc
Скачиваний:
5
Добавлен:
07.03.2016
Размер:
3.31 Mб
Скачать

13.2. Покрокове виконання програми

Під час налагодження програм на Visual C++ часто зустрічаються рядки з викликами різних методів (наприклад, PerformWork(data)). Якщо продовжити покрокове виконання програми з такого рядка, то ви перейдете до коду виклику методу (наприклад, PerformWork(), який може бути досить довгим). Це означає, що для повернення до відладжуваного фрагменту вам доведеться пройти через весь код методу.

У цьому немає нічого поганого, якщо ви хочете налагодити викликаємий метод, ... а якщо не хочете? (Наприклад, якщо викликаний стандартний метод Visual C++?) У цьому випадку ви можете пропустити код методу, користуючись клавішею F10 для послідовного виконання своєї програми.

Якщо ви захочете пройти через код викликаного методу, користуйтеся клавішею F11.

Якщо ви опинитеся всередині викликаного методу або іншого блоку, який не хочете налагоджувати, можете вийти за його межі, натиснувши клавіші Shift+F11.

Існує й інша можливість – встановити курсор в деякій точці програми за поточним виконуваним рядком і натиснути клавіші Ctrl+F10, що призведе до виконання коду до рядка з курсором.

У нашому прикладі для покрокового виконання програми буде використовуватися клавіша F10. Натисніть F10 один раз, щоб перейти до наступного рядка програми:

void CBuggyView::OnCalculateCalculateaverage()

{

CBuggyDoc* pDoc = GetDocument();

ASSERT_VALID(pDoc);

float Sum;

float Average;

for(int loop_index = 1; loop_index < 5; loop_index++)

{

Sum += pDoc->data[loop_index];

}

Average = Sum / (float) 5.0;

OutputString.Format(

"Среднее арифметическое пяти чисел равно: %.3f",

Average);

Invalidate();

}

Поточним стає наступний рядок програми (рис. 13.4). Саме в ньому відбувається підсумовування чисел для отримання накопичуваної суми в змінній Sum.

Рис. 13.4. Покрокове виконання програми

Щоб виконати поточний рядок, оновити значення суми і перейти до наступного рядку, ще раз натисніть клавішу F10 (рис. 13.5). До змінної Sum додано перше ціле число, а ми можемо перевірити її значення і переконатися, що все йде нормально.

Рис. 13.5. Перегляд значень змінних

13.4. Перевірка значень змінних під час виконання програми

Щоб дізнатися значення змінної Sum (в якій повинно зберігатися перше ціле число, 1), затримайте над нею курсор миші (див. рис. 13.5). Поруч з ім'ям змінної на екрані з'являється підказка зі значенням 1.07374е+008 або 1.07374x108 – це дещо більше, ніж ми очікували. Схоже, ми знайшли проблему.

Вікна Auto і Locals

Крім екранної підказки, змінна Sum зі своїм значенням відображається у вікні Auto, розташованому в лівому нижньому кутку на рис. 13.5 (зверніть увагу на обрану вкладку Auto). У цьому вікні наведені значення останніх змінних, з якими працював Visual C++; серед них є й наша змінна Sum. Крім того, ви можете клацнути на вкладці Locals і перейти до однойменного вікна, що містить значення всіх змінних (включаючи Sum), визначених у поточному методі або фрагменті коду.

Підказка. Якщо ви хочете відстежувати значення конкретної змінної під час всього виконання програми, введіть її ім'я у вікні Watch, розташованому в правому нижньому кутку вікна Visual C++. Крім того, потрібну змінну можна просто перетягнути мишею у вікно Watch.

Перегляд програми показує, що ми забули обнулити початкове значення суми. Давайте зробимо це. Перш за все завершіть сеанс налагодження командою Debug → Stop Debugging, потім відредагуйте метод і надайте змінній Sum початкове значення 0:

void CBuggyView::OnCalculateCalculateaverage()

{

CBuggyDoc* pDoc = GetDocument();

ASSERT_VALID(pDoc);

float Sum = 0;

float Average;

for(int loop_index = 1; loop_index < 5; loop_index++)

{

Sum += pDoc->data[loop_index];

}

Average = Sum / (float) 5.0;

OutputString.Format("Среднее арифметическое пяти чисел равно: %.3f",

Average);

Invalidate();

}

Помилка з ініціалізацією виправлена. Знову запустіть програму (рис. 13.6).

Рис. 13.6. Програма buggy: друга спроба

Тепер програма повідомляє, що середнє арифметичне перших п'яти цілих чисел дорівнює 2.800. Звичайно, це набагато ближче до очікуваного значенням 3.000, але всетаки не воно. Пора повертатися до відладчику.

Знову почніть налагодження командою Build → Start Debug → Go і виконайте програму до точки переривання. Увійдіть в цикл for клавішею F10 (рис. 13.7). Затримайте курсор миші над змінною Sum, щоб переконатися, що її значення дійсно дорівнює 0.

Зі змінною Sum все нормально; давайте перевіримо значення, яке до неї додається, pDoc->data[loop_index]:

void CBuggyView::OnCalculateCalculateaverage()

{

CBuggyDoc* pDoc = GetDocument();

ASSERT_VALID(pDoc);

float Sum = 0;

float Average;

for(int loop_index = 1; loop_index < 5; loop_index++)

{

Sum += pDoc->data[loop_index];

}

Average = Sum / (float) 5.0;

OutputString.Format(

"Среднее арифметическое пяти чисел равно: %.3f",

Average);

Invalidate();

}

Рис. 13.7. Налагодження циклу for у програмі buggy

Ми не зможемо дізнатися значення виразу pDoc-> data[loop_index], затримуючи на ньому курсор миші (незрозуміло, що саме нас цікавить – тільки pDoc або весь вираз?), але він присутній у вікні Auto у лівому нижньому кутку. Ми бачимо, що до суми додається число 2 (а не 1, як очікувалося).

Перегляд коду показує, що початкове значення змінної циклу дорівнює 1, а не 0, як належить. Зупиніть налагодження і виправте помилку:

void CBuggyView::OnCalculateCalculateaverage()

{

CBuggyDoc* pDoc = GetDocument();

ASSERT_VALID(pDoc);

float Sum = 0;

float Average;

for(int loop_index = 0; loop_index < 5; loop_index++)

{

Sum += pDoc->data[loop_index];

}

Average = Sum / (float) 5.0;

OutputString.Format(

"Среднее арифметическое пяти чисел равно: %.3f",

Average);

Invalidate();

}

Підказка. Щоб дізнатися значення того чи іншого виразу під час виконання програми, можна виконати команду DebugQuickWatch та ввести вираз у діалоговому вікні QuickWatch. Visual C++ вирахує його значення.

Запустіть програму (рис. 13.8). Ми домоглися бажаного результату – середнє арифметичне чисел 1-5 дорівнює 3. Вбудовані засоби налагодження Visual C++ допомогли ліквідувати помилки.

Щоб видалити з програми точку переривання, встановіть курсор на рядку з нею і натисніть клавішу F9.

Підказка. Закінчивши налагодження, слід видалити налагоджувальну інформацію з виконуваного файлу. Виконайте команду Build → Set Active Configuration та виберіть зі списку, рядок buggy - Win32 Release (за замовчуванням в програми на Visual C++ включається великий обсяг інформації, використовуваної відладчиком).

Рис. 13.8. Програма buggy після завершення налагодження

Виправлений варіант програми міститься у файлах buggyDoc.h/buggyDoc.cpp і buggyView.h/buggyView.cpp.

buggyDoc.h і buggyDoc.cpp

// buggyDoc.h : інтерфейс класа CBuggyDoc

//

/////////////////////////////////////////////////////////////////////////

#if !defined(AFX_BUGGYDOC_H__3236D78B_9951_11D0_8860_444553540000__INCLUDED_)

#define AFX_BUGGYDOC_H__3236D78B_9951_11D0_8860_444553540000__INCLUDED_

#if _MSC_VER >= 1000

#pragma once

#endif // _MSC_VER >= 1000

class CBuggyDoc : public CDocument

{

protected: // Создание только при сериализации

CBuggyDoc();

DECLARE_DYNCREATE(CBuggyDoc)

// Атрибуты

public:

// Операції

public:

int data[5];

// Перевантаження

// Перевантажені віртуальні функції,

// сформовані ClassWizard-ом.

//{{AFX_VIRTUAL(CBuggyDoc)

public:

virtual BOOL OnNewDocument();

virtual void Serialize(CArchive& ar);

//}}AFX_VIRTUAL

// Реалізація

public:

virtual ~CBuggyDoc();

#ifdef _DEBUG

virtual void AssertValid() const;

virtual void Dump(CDumpContext& dc) const;

#endif

protected:

// Сформовані функції карти повідомлень

protected:

//{{AFX_MSG(CBuggyDoc)

// УВАГА!! Тут ClassWizard буде додавати і

// видаляти функції-члени.

// не редагуйте текст у цих блоках!

//}}AFX_MSG

DECLARE_MESSAGE_MAP()

};

/////////////////////////////////////////////////////////////////////////

//{{AFX_INSERT_LOCATION}}

// Microsoft Visual C++ буде вставляти додаткові

// оголошення перед попереднім рядком.

#endif

// !defined(AFX_BUGGYDOC_H__3236D78B_9951_

// 11D0_8860_444553540000__INCLUDED_)

// buggyDoc.cpp : реалізація класа CBuggyDoc

//

#include "stdafx.h"

#include "buggy.h"

#include "buggyDoc.h"

#ifdef _DEBUG

#define new DEBUG_NEW

#undef THIS_FILE

static char THIS_FILE[] = __FILE__;

#endif

/////////////////////////////////////////////////////////////////////////

// CBuggyDoc

IMPLEMENT_DYNCREATE(CBuggyDoc, CDocument)

BEGIN_MESSAGE_MAP(CBuggyDoc, CDocument)

//{{AFX_MSG_MAP(CBuggyDoc)

// УВАГА!! Тут ClassWizard буде додавати і

// видаляти функції-члени.

// не редагуйте текст у цих блоках!

//}}AFX_MSG_MAP

END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////

// Создание/уничтожение CBuggyDoc

CBuggyDoc::CBuggyDoc()

{

// ЗРОБИТИ: додайте код конструктора

data[0] = 1;

data[1] = 2;

data[2] = 3;

data[3] = 4;

data[4] = 5;

}

CBuggyDoc:: *"CBuggyDoc()

{

}

BOOL CBuggyDoc::OnNewDocument()

{

if (!CDocument::OnNewDocument())

return FALSE;

// ЗРОБИТИ: додайте код для повторної ініциалізації документа

// (документи SDI будуть використовувати його повторно)

return TRUE;

}

/////////////////////////////////////////////////////////////////////////

// Сериалізація в CBuggyDoc

void CBuggyDoc::Serialize(CArchive& ar)

{

if (ar.IsStoring())

{

// ЗРОБИТИ: додайте код збереження даних

}

else

{

// ЗРОБИТИ: додайте код завантаження даних

}

}

/////////////////////////////////////////////////////////////////////////

// Діагностика в CBuggyDoc

#ifdef _DEBUG

void CBuggyDoc::AssertValid() const

{

CDocument::AssertValid();

}

void CBuggyDoc::Dump(CDumpContext& dc) const

{

CDocument::Dump(dc);

}

#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////

// Команди CBuggyDoc

buggyView.h і buggyView.cpp

// buggyView.h : інтерфейс класа CBuggyView

//

/////////////////////////////////////////////////////////////////////////

#if !defined(AFX_BUGGYVIEW_H__3236D78D_9951_11D0_8860_444553540000__INCLUDED_)

#define AFX_BUGGYVIEW_H__3236D78D_9951_11D0_8860_444553540000__INCLUDED_

#if _MSC_VER >= 1000

#pragma once

#endif // _MSC_VER >= 1000

class CBuggyView : public CView

{

protected: // создание только при сериализации

CBuggyView();

DECLARE_DYNCREATE(CBuggyView)

// Атрибуты

public:

CBuggyDoc* GetDocument();

// Операції

public:

// Перевантаження

// Перевантажені віртуальні функції,

// сформовані ClassWizard-ом.

//{{AFX_VIRTUAL(CBuggyView)

public:

virtual void OnDraw(CDC* pDC); // перевизначається для

// малювання в цьому виді

virtual BOOL PreCreateWindow(CREATESTRUCT& cs);

protected:

virtual BOOL OnPreparePrinting(CPrintInfo* pInfo);

virtual void OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo);

virtual void OnEndPrinting(CDC* pDC, CPrintInfo* pInfo);

//}}AFX_VIRTUAL

// Реалізація

public:

virtual ~CBuggyView();

#ifdef _DEBUG

virtual void AssertValid() const;

virtual void Dump(CDumpContext& dc) const;

#endif

protected:

CString OutputString;

// Сформовані функції карти повідомлень

protected:

//{{AFX_MSG(CBuggyView)

afx_msg void OnCalculateCalculateaverage();

//}}AFX_MSG

DECLARE_MESSAGE_MAP()

};

#ifndef _DEBUG // отладочная версия в buggyView.cpp

inline CBuggyDoc* CBuggyView::GetDocument()

{ return (CBuggyDoc*)m_pDocument; }

#endif

/////////////////////////////////////////////////////////////////////////

//{{AFX_INSERT_LOCATION}}

// Microsoft Visual C++ буде вставляти додаткові

// оголошення перед попереднім рядком.

#endif

// !defined(AFX_BUGGYVIEW_H__3236D78D_9951_

// 11D0_8860_444553540000__INCLUDED_)

// buggyView.cpp : реалізація класа CBuggyView

//

#include "stdafx.h"

#include "buggy.h"

#include "buggyDoc.h"

#include "buggyView.h"

#ifdef _DEBUG

#define new DEBUG_NEW

#undef THIS_FILE

static char THIS_FILE[] = __FILE__;

#endif

/////////////////////////////////////////////////////////////////////////

// CBuggyView

IMPLEMENT_DYNCREATE(CBuggyView, CView)

BEGIN_MESSAGE_MAP(CBuggyView, CView)

//{{AFX_MSG_MAP(CBuggyView)

ON_COMMAND(ID_CALCULATE_CALCULATEAVERAGE, OnCalculateCalculateaverage)

//}}AFX_MSG_MAP

// Standard printing commands

ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint)

ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint)

ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview)

END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////

// Створення/видалення CBuggyView

CBuggyView::CBuggyView()

{

// ЗРОБИТИ: додайте код конструктора

OutputString = "Выполните команду Calculate/Calculate Average";

}

CBuggyView::~CBuggyView()

{

}

BOOL CBuggyView::PreCreateWindow(CREATESTRUCT& cs)

{

// ЗРОБИТИ: Змініть клас вікна або його стилі,

// редагуючи вміст CREATESTRUCT cs

return CView::PreCreateWindow(cs);

}

/////////////////////////////////////////////////////////////////////////

// Малювання в CBuggyView

void CBuggyView::OnDraw(CDC* pDC)

{

CBuggyDoc* pDoc = GetDocument();

ASSERT_VALID(pDoc);

pDC->TextOut(0, 0, OutputString);

// ЗРОБИТИ: додайте код для відображення даних

}

/////////////////////////////////////////////////////////////////////////

// Друк в CBuggyView

BOOL CBuggyView::OnPreparePrinting(CPrintInfo* pInfo)

{

// Стандартна підготовка

return DoPreparePrinting(pInfo);

}

void CBuggyView::OnBeginPrinting(CDC* /*pDC*/,

CPrintInfo* /*pInfo*/)

{

// ЗРОБИТИ: додайте додаткову ініціалізацію перед друком

}

void CBuggyView::OnEndPrinting(CDC* /*pDC*/,

CPrintInfo* /*pInfo*/)

{

// ЗРОБИТИ: додайте код для "зборки сміття" після друку

}

/////////////////////////////////////////////////////////////////////////

// Діагностика в CBuggyView

#ifdef _DEBUG

void CBuggyView::AssertValid() const

{

CView::AssertValid();

}

void CBuggyView::Dump(CDumpContext& dc) const

{

CView::Dump(dc);

}

CBuggyDoc* CBuggyView::GetDocument() // не-відладочна версія

// є вбудованою

{

ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CBuggyDoc)));

return (CBuggyDoc*)m_pDocument;

}

#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////

// Обробники повідомлень CBuggyView

void CBuggyView::OnCalculateCalculateaverage()

{

// ЗРОБИТИ: додайте код обробки команди

CBuggyDoc* pDoc = GetDocument();

ASSERT_VALID(pDoc);

float Sum = 0;

float Average;

for(int loop_index = 0; loop_index < 5; loop_index++)

{

Sum += pDoc->data[loop_index];

}

Average = Sum / (float) 5.0;

OutputString.Format("Среднее арифметическое пяти чисел равно: %.3f",

Average);

Invalidate();

}

На цьому завершується наше знайомство з відладчиком Visual C++. Залишається лише використовувати отримані знання на практиці.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]