一步步使用Code::Blocks进行设置断点调试程序
一、调试之前要做的工作
首先,我们要确保Code::Blocks的配置正确,调试工作才能进行得更顺利
为此,我们需要生成调试符号。调试符号可以让调试器知道代码的哪一行正在执行,这样你就可以知道程序运行到哪里了。
为确保调试符号设置正确,请在Code::Blocks中选择项目 | 编译选项(Project | Build Options),会看到这样一个对话框:
你需要确保调试(Debug)目标里的生成调试符号(Produce debugging symbols)选项被勾选上。
还需要在编译 | 选择目标 | 调试(Build | Select Target |Debug)中,确保调试(Debug)作为项目的目标被选中:
以上操作确保了目标是对项目进行调试,调试器将使用调试符号来编译你的程序。
二、设置断点
调试器的价值在于,它能让我们看到程序正在做的事情——哪些代码正在执行,以及变量的值是多少。
为此,我们在程序的某个地方设置断点,然后在调试器下运行该程序。调试器将执行程序,直到到达设置了断点的代码行。此时,编译器便可以让你查看程序,或者一步步地执行程序,检查代码的每一行是如何影响你的变量的。
首先我们来看一段用来计算特定数额资金的利率(interest rate)、年利息(compounded annually)的程序:
#include <iostream>
using namespace std;
double computeInterest (double base_val, double rate, int years)
{
double final_multiplier;
for ( int i = ; i < years; i++ )
{
final_multiplier *= ( + rate);
}
return base_val * final_multiplier;
} int main ()
{
double base_val;
double rate;
int years;
cout << "Enter a base value: ";
cin >> base_val;
cout << "Enter an interest rate: ";
cin >> rate;
cout << "Enter the number of years to compound: ";
cin >> years; cout << "After " << years << " you will have " << computeInterest( base_val, rate, years ) << " money" << endl;
}
看了运行结果,很明显,出现了错误,这时我们将设置断点开始进行调试。
1,先在main函数开始的地方,设置一个断点。这样就可以查看整个程序的执行过程了。
(1)将光标移到 double base_val 这一行
(2)选择 调试 | 设置断点 (Debug | Toggle Breakpoint)或者按下F5。这会在该代码行旁边的侧边栏中设置一个小红点,表明这一行有一个断点:
(3)可以使用设置断点命令或者单击小红点用来设置或取消设置该断点。
(4)开始运行程序。选择调试 | 开始(Debug | Start)或者按下F8。
这样程序将正常执行,直到遇到断点。
现在我们应该看到了打开的调试器,它看起来应该是这样的:
首先要注意的是小圆点下面的三角形,它表示接下来要执行的代码行。它跟小红点之间相隔若干行。
它之所以没有紧挨着小红点,是因为变量的声明不产生任何的机器代码,因此,尽管断点看起来是在15行,但实际上它在第18行。
(5)这时应该还有一个监视(Watches)窗口打开了,如下图:
我已经展开了监视窗口的两个子项:局部变量(Local variables)和函数参数(Function Arguments)。
监视窗口会显示出所有当前可用的变量,包括局部变量和函数参数,以及这些变量的值。
注意:这里看起来像乱码的原因是因为我们还没有对它们进行初始化,这也是接下来的几行程序所要做的事情。
(6)为了执行接下来的几行代码,我们需要告诉调试器向下执行下一行(F7)。
所谓向下执行一行,就会执行当前的代码行,也就是三角形所标识的那一行。
一旦走到下一行,程序就会执行cout语句,输出一条信息到屏幕中,要求你输入一个值。
如果你尝试输入一个值但没有任何效果——因为程序还在调试器的控制之下。
再次按下F7后,程序会等待用户输入,因为这时候cin函数还未返回——cin函数需要在返回前得到用户的输入。
重复这一过程,分别输入0.1给利率,输入1给年数。
现在,断点到达了这一行代码:
再次确认输入是否正确。我们可以通过监视窗口来检查局部变量的值:
注意:rate的值不是0.1,是因为0.10000...1中最末尾的1只是浮点数的一种怪异的表达方式(浮点数并不是精确的),它实在太小了,对大多数程序来说不会造成很大影响。
(7)现在我们确定一切都没问题,来调查一下computerInterest函数中会发生什么,单步执行(Step into)。
单步执行会进入当前行的函数里面去执行,而不像下一行命令,只是执行函数然后显示给你最终的结果。
现在我们就单步进入computerInterest函数之中:
(8)从结果中我们可以看出函数的参数部分一切正常,但变量i 和 final_multiplier 值不对劲。
为此,使用下一行命令(F7),执行循环语句,由于它与一些初始化操作相关联,我们看看会发生什么。
(9)从中我们可以看出,final_multiplier没有正确初始化。而且,接下来要执行的语句将要用到final_multiplier:
final_multiplier *= ( + rate);
这条语句的意思是,将final_multiplier乘以(1+rate),再把结果重新赋值给final_multiplier。但是我们看到final_multiplier并没有被初始化,因此这个乘法的结果也将会是一个莫名其妙的值。
(10)如何修复bug?
我们需要在声明final_multiplier变量的语句中,把它也初始化。在这个例子中,它应该被初始化1。
double final_multiplier=;
(11)修复bug后的运行结果为:
三、总结
通过以上一个简单的程序案例,使我掌握了调试一个程序的基本流程,和分析bug的过程,为以后自己独立寻找bug,解决bug提供了实用的技能。
我不光可以写bug,还能Debug!
一步步使用Code::Blocks进行设置断点调试程序的更多相关文章
- code::blocks怎么设置命令行参数
Project->Set Program's Arguments...然后在相应的输入框中输入命令行参数
- Code::Blocks代码自动提示设置及常用快捷键
Code::Blocks代码自动提示设置及常用快捷键(适用windows和linux) 1)以下需要设置的地方均在Settings->Editor...弹出的对话框中. 2)不少命令都可针对当前 ...
- ubuntu下code::blocks设置运行窗口为gnome命令行
code::blocks编译运行C++程序(F9)默认出现的运行串口在有鼠标的情况下进行粘贴还是很方便的,只要按下鼠标滑轮,位与剪切板中的数据就能粘贴到运行串口中.但是对于用笔记本而且没有鼠标地童鞋这 ...
- ubuntu15.10下code::blocks设置运行窗口为gnome命令行
code::blocks编译运行C++程序(F9)默认出现的运行串口在有鼠标的情况下进行粘贴还是很方便的,只要按下鼠标滑轮,位与剪切板中的数据就能粘贴到运行串口中. 但是对于用笔记本而且没有鼠标地童鞋 ...
- Code::Blocks配置GTK+2和GTK+3
Code::Blocks配置GTK+2和GTK+3 作者 He YiJun – storysnail<at>gmail.com 团队 ls 版权 转载请保留本声明! 本文档包含的原创代码根 ...
- 关于Ubuntu12.04下code::blocks不能使用debug解决方法
问题描述: 系统:ubuntu 12.04 code::blocks版本:10.05 问题现象:debug->start 之后出现:warning: GDB: Fail ...
- Code::Blocks项目配置基础
File 菜单 New :新建( Empty file/file . class . project . build target ) . Recent projects/files :近期打开的项目 ...
- Code::Blocks无法调试 Starting the debuggee failed: No executable specified, use `target exec'
1.必须建立工程 2.工程名不可有特殊字符或空格,可以有字母.数字.下划线 2.编译器设置里勾选-g(产生调试符号) 3.重新编译项目(如果之前编译过了) 4.调试器设置 > Default & ...
- code::blocks的快捷键汇总
编辑部分: Ctrl + A:全选 Ctrl + C:复制 Ctrl + X: 剪切 Ctrl + V:粘贴 Ctrl + Z:撤销 Ctrl + S:保存 Ctrl + Y / Ctrl + S ...
随机推荐
- BZOJ5415[Noi2018]归程——kruskal重构树+倍增+堆优化dijkstra
题目描述 本题的故事发生在魔力之都,在这里我们将为你介绍一些必要的设定. 魔力之都可以抽象成一个 n 个节点.m 条边的无向连通图(节点的编号从 1 至 n).我们依次用 l,a 描述一条边的长度.海 ...
- Java生成数独函数
突然想写一下生成算法.代码注释的比较多,应该比较好理解 使用了递归 import java.util.ArrayList; public class Sudoku { static int sudok ...
- MT【219】构造二次函数
(2012北大保送)已知$f(x)$是二次函数,且$a,f(a),f(f(a)),f(f(f(a)))$是正项等比数列;求证:$f(a)=a$ 构造二次函数$f(x)=qx$,则$a,f(a),f(f ...
- Java 关键字final的一小结
* final类不能被继承,没有子类,final类中的方法默认是final的. * final方法不能被子类的方法覆盖,但可以别继承 (方法) * final 成员变量 表示常量,只能被赋值一 ...
- HNOI2018题解
在此处输入标题 标签(空格分隔): 未分类 重做了一遍,本来以为很快的,结果搞了一天... 寻宝游戏 可以发现只有\(\&0\)和\(|1\)会对答案有影响 那么对于每一位,我们只要知道最后一 ...
- sprintf-%s的用法
@2018-9-19 sprintf-%s的用法 #include <stdio.h> #include <string.h> char string[] = "I ...
- cf1063A Oh Those Palindromes (贪心)
给一些字符 求它们能拼成的字符串 的回文子串的个数最大值 对应的那个字符串 就是把相同的都放一起是最优的,排下序就行了... #include<bits/stdc++.h> #define ...
- STL总结
容器类放入的都是元素的拷贝,而非引用.所以如果需要对元素做出改动,最好是把元素存在data[N]数组中,而仅仅在容器中存放数组下标. 函数传递容器类参数时,需要传引用,否则会超时. vector ve ...
- table默认的box-sizing在不同浏览器不同
转载自:https://blog.csdn.net/csm0912/article/details/88290672
- Python 爬虫入门(四)—— 验证码上篇(主要讲述验证码验证流程,不含破解验证码)
本篇主要讲述验证码的验证流程,包括如何验证码的实现.如何获取验证码.识别验证码(这篇是人来识别,机器识别放在下篇).发送验证码.同样以一个例子来说明.目标网址 http://icp.alexa.cn/ ...