VC调试方法.docx
《VC调试方法.docx》由会员分享,可在线阅读,更多相关《VC调试方法.docx(34页珍藏版)》请在冰豆网上搜索。
VC调试方法
VC环境程序调试方法
目录
一、熟悉VC环境1
二、单步调试F106
三、运行到光标Ctrl+F1011
四、断点调试F913
五、运行时Watch窗口改变变量的值17
六、Debug下拉菜单调试21
七、跟踪到函数运行F1124
一、熟悉VC环境
编程示例,在屏幕上显示一个短句“HelloWorld!
”。
源程序
#include
voidmain()
{
printf("HelloWorld!
\n");
}
运行结果
HelloWorld!
作为本书的第一个实验,在VisualC++编程环境下,以上述C语言源程序为例,介绍运行一个C程序的基本步骤,请读者按照以下步骤操作。
(1)启动VC++
执行“开始”—>“程序”—>“MicrosoftVisualStudio6.0”—>“MicrosoftVisualC++6.0”,进入VC++编程环境(如图1.1所示)。
图1.1VC++窗口
(2)新建文件
执行“文件/File”—>“新建/New”,单击“文件/Files”选项卡(如图1.2所示),先在“文件/Filename”栏中输入test,把C源(程序)文件命名为test.cpp,在“目录/Location”框中选择你已经建立的文件夹,如,D:
\3050888,然后选中“C++SourseFiles”,单击“确定”按钮,在D:
\3050888下就新建了文件test.cpp,并显示编辑窗口和信息窗口(如图1.3所示)。
图1.2新建文件
(3)编辑和保存
在编辑窗口(如图1.3所示)中输入源程序,然后执行“文件/File”—>“保存/Save”或“文件/File”—>“另存为/SaveAs”,保存源文件。
图1.3编辑源程序
(4)编译
执行“编译/Build”—>“编译/Compile”或Ctrl+F7(如图1.4所示),在“产生工作区”对话框中(如图1.5所示)选择“是/Y”,开始编译,并在信息窗口显示编译信息(如图1.6所示)。
图1.4编译源程序
图1.5产生一个工作区
图1.6编译正确
图1.6信息窗口中出现的“test.obj-0error(s),0warning(s)”,表示编译正确,没有发现(语法)错误和警告,并生成了目标文件test.obj。
☞如果显示有错误error(s),指程序中存在致命的错误,必须要改正;如果显示有警告warning(s),虽然不影响生成目标文件,但通常也应该改正。
(5)连接
执行“编译/Build”—>“构件/Build”或F7,也可用“重建全部/RebuildAll”,开始连接,并在信息窗口显示连接信息(如图1.7所示)。
图1.7信息窗口中出现的“test.exe-0error(s),0warning(s)”表示连接成功,产生了可执行文件test.exe。
图1.7连接成功并产生运行文件
(6)运行
执行“编译/Build”—>“执行/Execute”或Ctrl+F5(如图1.8所示),自动弹出运行窗口(如图1.9所示),显示运行结果“HelloWorld!
”,其中“Pressanykeytocontinue”提示读者按任何键退出DOS窗口,返回到VC++编辑窗口。
图1.8运行程序
图1.9运行窗口
(7)关闭程序工作区
执行“文件/File”—>“关闭工作区/CloseWorkspace”(如图1.10所示),在出现的对话框(如图1.11所示)中选择“是/Y”,关闭工作区。
图1.10关闭程序工作区
图1.11关闭所有文档窗口
(8)打开文件
如果要再次打开C源文件,可以执行“文件/File”—>“打开/Open”,在文件夹D:
\3050888下选择文件test.cpp;或者在D:
\3050888文件夹下,直接双击文件test.cpp。
(9)查看C源文件、目标文件和可执行文件的存放位置
经过编辑、编译、连接和运行后,在文件夹D:
\3050888(如图1.12所示)和D:
\3050888\Debug(如图1.13所示)中存放着有关的文件,其中源文件test.cpp在文件夹D:
\3050888中,目标文件test.obj和可执行文件test.exe都在文件夹D\3050888\Debug中。
图1.12文件夹“D:
\3050888”
图1.13文件夹“D:
\3050888\debug”
二、单步调试F10
3-1调试示例,输入x,计算并输出下列分段函数f(x)的值(保留1位小数)。
源程序(有错误的程序)
#include
voidmain()
{
floatx,y;
printf("inputx:
");
scanf("%f",x);
if(x!
=0)
y=1/x
else
y=0;
printf("f(%.2f)=%.1f\n",x,y);
}
运行结果(改正后程序的运行结果)
10.0
f(10.00)=0.1
(1)打开源程序error3_1.cpp,执行“编译/Build”—>“编译/Compile”,出现第一个编译错误是:
missing';'before'else'
双击该出错信息,箭头指向else所在行,出错信息指出在else前缺少分号。
在y=1/x后面补上分号后,重新编译,新出现的第一个出错信息:
localvariable'x'usedwithouthavingbeeninitialized
双击该错误信息,箭头指向scanf("%f",x);所在行,出错原因是x的前面少了&。
在x前面补上&后,重新编译并连接,均正确。
(2)执行“工具”—>“定制”,选择“调试”(如图3.1所示),出现调试工具栏(如图3.2所示)。
或者按照实验二介绍的方法,也可以出现调试工具栏。
图3.1选择工具栏
图3.2调试工具栏
(3)调试开始,单击调试工具栏中的单步执行
(StepOver(F10)),每次执行一行(如图3.3所示),编辑窗口中的箭头指向行表示程序将要运行该行。
图3.3中列出了变量窗口(VariablesWindow)和观察窗口(WatchWindow),在Watch窗口中还可以改变变量的值。
图3.3程序调试开始
(4)鼠标单击
三次,程序执行到输入这一行(如图3.4所示),同时运行窗口(如图3.5所示)显示提示符“inputx:
”(注意此时将要执行但还没有执行scanf(“%f”,&x);语句),继续单击
,就可以在运行窗口输入x的值10(如图3.6所示),按回车键Enter后,箭头指向了“if(x!
=0)”这一行(如图3.7所示),在变量窗口可以看到变量x的值是10.0000,变量x的地址(&x)是0x0012ff7c。
图3.4程序单步调试
图3.5运行窗口
图3.6在运行窗口输入变量x的值10
(5)继续单击
二次,箭头指向了“else”这一行(如图3.8所示),在变量窗口可以看到变量y的值是0.100000。
(8)继续单击
二次(如图3.9所示),运行窗口显示运行结果(如图3.10所示),符合题目的要求。
(9)单击终止调试图标
(StopDebugging(Shaft+F5)),程序调试结束。
图3.7程序单步调试,显示变量x的值和变量x的地址
图3.8程序单步调试,显示变量y的值
图3.9程序单步调试到最后一行
图3.10在运行窗口显示调试后的最后结果
三、运行到光标Ctrl+F10
4-1调试示例,计算表达式1+2+3+……+100的值。
源程序(有错误的程序)
#include
voidmain()
{
inti,sum;
for(i=1,i<=100,i++)
sum=sum+i;
printf("sum=%d\n",sum);
}
运行结果(改正后程序的运行结果)
sum=5050
(1)打开源程序error4_1.cpp,编译程序,出现第一个错误信息:
missing';'before')'
双击该错误信息,箭头指向“for”这一行,错误信息指出在for语句的括号里面应使用“;”,对for语句括号里面进行仔细分析,发现把“;”写成了“,”。
把“,”改为“;”后,重新编译,连接,都正确。
(2)开始调试,如果调试工具栏不可见,采用实验三介绍的方法,调出该工具栏(如图3.2所示)。
(3)鼠标单击第6行,光标就在第六行前面闪烁,这就是当前的光标位置(如图4.1所示)。
图4.1光标在程序中位置
(4)单击
(RuntoCursor(Ctrl+F10)),程序运行到光标的位置(如图4.2所示)。
在变量窗口中,第一次循环时i的值为1,正确,而sum的值是-858993460,不正确。
仔细分析程序,发现sum没有赋初值。
在for语句前面加一条语句sum=0;,重新编译、连接,然后重做(3)和(4),图4.3显示sum的值为0,正确。
图4.2程序运行到光标的位置
图4.3程序运行到光标的位置,观察“sum”的值
(5)把光标设在“}”的前面,鼠标单击
,程序运行到光标处“}”的前面(如图4.4所示),变量窗口中,sum的值是5050,正确。
(6)鼠标单击终止调试图标
(StopDebugging(Shaft+F5)),程序调试结束。
图4.4程序运行到光标的位置,观察最后“sum”的值
四、断点调试F9
5-1调试示例,从键盘输入一个正整数n,计算n!
的值,要求定义和调用函数fact(n),计算n!
。
源程序(有错误的程序)
#include
voidmain()
{
intn;
longintf;
printf("Inputn:
");
scanf("%d",&n);
f=fact(n);
printf("%d!
=%ld\n",n,f);
}
longfact(intm)
{
inti;
longintproduct;
for(i=1;i<=m;i++)
product=product*i;
returnproduct;
}
运行结果(改正后程序的运行结果)
Inputn:
10
10!
=3628800
实验四中我们使用了程序运行到光标位置调试程序,本次实验需要掌握设置断点,以及单步调试进入函数和跳出函数的方法。
(1)打开源程序error5_1.cpp,编译程序,出现的错误信息:
'fact':
undeclaredidentifier
'fact':
redefinition;differenttypemodifiers
双击该错误信息,箭头指向“f=fact(n);”这一行,错误信息指出函数“fact”没有定义,这是因为数据在调用前,必须先定义或声明。
在主调函数的变量定义前面加上函数声明“longfact(intm);”后,重新编译,连接,都正确。
(2)调试开始,设置2个断点(断点的作用:
程序执行到断点处暂停,使用户可以观察当前的变量或其它表达式的值,然后继续运行),先把光标定位到要设置断点的位置,然后单击编译工具条上的
(Inert/RemoveBreakpoint(F9)),断点就设置好了(如图5.1所示)。
如果要取消断点,只要把光标放到要取消的断点处,单击
,这个断点就取消了。
图5.1设置断点
(3)单击编译工具条
(go(F5)),运行程序,用户输入n的值10后,程序运行到第一个断点位置暂停(如图5.2所示)。
图5.2程序运行到断点位置
(4)单击
(StepInto(F11))进入函数fact()调试,箭头表示程序已经执行到函数fact()内(如图5.3所示)。
(5)使用
,在函数fact()中设置程序的第3个断点(如图5.3所示)。
(6)单击
(go(F5)),程序直接运行到断点处,暂停(如图5.4所示),在变量窗口观察到product的值是-2903040,不正确,因为变量product未赋初值,加上语句product=1后,按以上的步骤,重新编译、连接,运行到第3个断点处,变量窗口中product的值正确。
(7)现在需要从被调函数返回到主调函数,单击调试工具条中的
(StepOut(ShaftF11)),程序返回主调函数继续执行(如图5.5所示)。
(8)继续单击
(go(F5)),程序执行到最后(如图5.6所示),在运行窗口输出10!
=3628800,与题目要求的结果一致。
(9)单击终止调试图标
(StopDebugging(Shaft+F5)),程序调试结束。
图5.3进入函数fact()调试,并在运行时设置断点
图5.4程序从函数fact()开始直接运行到第3个断点的位置(return前面)
图5.5程序回到了主调函数
图5.6程序执行到最后
五、运行时Watch窗口改变变量的值
6-1调试示例,输入参数a,b,c,求一元二次方程a*x2+bx+c=0的根。
源程序(有错误的程序)error6_1.cpp
#include
#include
voidmain()
{
doublea,b,c,d;
printf("输入一元二次方程a=,b=,c=\n");
scanf("a=%lf,b=%lf,c=%lf",&a,&b,&c);
d=b*b-4*a*c;
if(a==0){
if(b=0){
if(c==0)
printf("0==0参数对方程无意义!
");
else
printf("C!
=0方程不成立");
}
else
printf("x=%0.2f\n",-c/b);
}
else
if(d>=0){
printf("x1=%0.2f\n",(-b+sqrt(d))/(2*a));
printf("x2=%0.2f\n",(-b-sqrt(d))/(2*a));
}
else{
printf("x1=%0.2f+%0.2fi\n",-b/(2*a),sqrt(-d)/(2*a));
printf("x2=%0.2f-%0.2fi\n",-b/(2*a),sqrt(-d)/(2*a));
}
}
运行结果(改正后程序的运行结果)
输入一元二次方程a=,b=,c=
a=2.1,b=8.9,c=3.5
x1=-7.22
x2=-10.58
运行结果(有错误程序的运行结果)
输入一元二次方程a=,b=,c=
a=2.1,b=8.9,c=3.5
x1=-0.44
x2=-3.80
实验五中我们已经学会了正确设置和取消断点,现在进一步学习断点的设置,并且观察断点前的变量值是否正确,如果不正确,可以在Watch窗口中将正确的值直接赋给变量,即起到改变变量值的作用,如果调试正确,再在程序做相应的修改。
这种做法,在调试运行大型程序时,特别有用。
对以上程序进行编译、连接、调试和运行如下:
(1)执行“编译”—>“构件”,对以上程序进行编译、连接,没有出现错误信息。
(2)调试开始,设置三个断点,如图6.2所示。
(3)单击编译工具条
(go(F5)),程序运行,等待输入一元二次方程“a、b、c”参数的值,输入a=2.1,b=8.9,c=3.5(如图6.1所示)。
图6.1DOS运行窗口输入参数
(4)程序运行到第一个断点,在Watch窗口输入变量名a、b、c,观察执行到第一个断点时变量a、b、c的值是否和
(2)中输入的值一致,如图6.2所示,此时,Watch窗口显示的变量a、b、c的值和输入的值一致。
注意:
变量可以在Wtach1、Wtach2、Wtach2、Wtach4任何一个窗口输入,输入可以是变量,也可以是表达式。
(5)假设我们在输入的时候,输错了变量a的值,我们可以在Watch窗口重新赋值,改变原来的值。
例如,如果在Watch窗口输入表达式a=0,则a的值就改变为0了,如图6.3所示。
从Watch窗口看到,a的值已经改变为0。
图6.2在Watch窗口观察当前变量的值
图6.3在Watch窗口改变变量的值
(6)单步执行,单击
,箭头指向了下一行,观察Watch窗口,a的值还是“0”,如图6.4所示,说明(4)中变量a的值确实被改变了。
(7)单步执行,单击
,箭头指向第17行,说明程序执行到第17行,再观察变量a、b、c的值,发现变量b的值已经改变,原来输入的是8.9,现在已改变为“0”,如图6.5所示。
(8)我们在
(2)中输入变量b的值是8.9,说明在程序的执行过程中肯定有一个地方改变了变量b的值,通过仔细观察、分析,发现if语句中误把相等“==”写成了赋值“=”,所以变量b被赋值0了。
单击
(StopDebugging(Shaft+F5))停止调试,把源程序中的“=”改为“==”后,重新编译、连接,没有出现错误信息。
图6.4验证变量a值的正确性
图6.5显示变量b的值已经改变
(9)单击
(Restart(Ctrl+Shaft+F5))重新开始调试,如图6.6所示。
图6.6重新开始调试
(10)执行(3)-(7),此时,观察到变量b的值没有改变,还是8.9,并且DOS窗口显示x=-0.35,单击
(StopDebugging(Shaft+F5)),结束本次调试。
(11)单击
(Restart(Ctrl+Shaft+F5))重新开始调试。
注意:
删除Watch窗口中的表达式a=0,否则a的值还是为0。
(12)单击
(go(F5)),输入数据,程序运行到第一个断点,观察到变量a、b、c的值和输入数据一样。
(13)单击
(go(F5)),程序运行到第二个断点,观察到变量d=49.81,应该输出实根。
(14)单击
(go(F5)),程序运行到第三个断点,在DOS窗口看到x1=-0.44,x2=-3.80。
(15)单击
(StopDebugging(Shift+F5))程序结束调试。
读者也可以输入不同的参数,观察有虚数的情况。
六、Debug下拉菜单调试
7-1调试示例,输入二个正整数m、n,输出它们的最小公倍数和最大公约数。
源程序(有错误的程序)error7_1.cpp
#include
voidmain()
{intm,n,j,k;
printf("Inputmn\n");
while(scanf("%d%d",&m,&n),m<0&&n<0);
j=m;
while(j/n!
=0)
j=j+m;
k=(m*n)/j;
printf("最小公倍数是%d\n最大公约数是%d\n",j,k);
}
运行结果(改正后程序的运行结果)
Inputmn:
37
最小公倍数是21
最大公约数是1
“编译”菜单中的调试命令(图7.1)和调试工具栏中按钮的功能是一样的,可以使用“编译”菜单来调试程序。
(1)输入并保存上述程序后,再进行编译和连接,没有出现错误信息。
(2)调试程序开始,设置3个断点(图7.2)。
执行“编译”—>“开始调试”—>
去(相当于调试工具栏中的
go(F5),运行程序,输入-37。
(3)程序执行到第一个断点,变量窗口显示m=-3,n=7,说明有错误。
因为如果输入了负数,必须重新输入,直到输入2个正数为止。
注意:
此时,菜单栏中新出现一个“Debug”菜单(图7.3),包括了调试工具栏中所有的调试工具,用户可以选择使用“Debug”菜单或调试工具栏来调试程序。
(4)单击
(StopDebugging(ShaftF5))停止调试,通过仔细分析,发现循环条件中m<0&&n<0应该是m<0||n<0。
因为&&表示m和n同时为负数时才重新输入,而||只要有一个负数,就要重新输入数据。
注意:
此时,不一定要停止程序调试,用户可以在Watch窗口输入m=3,再继续调试。
(5)把&&改为||,重新编译和连接,然后单击
(Rstart(Ctrl+Shaft+F5))重新开始调试,再单击
go(F5),输入-37后,箭头不动,说明需要重新输入数据。
(6)重新输入数据37,程序执行到第一个断点,观察变量窗口,m=3,n=7,没有错误。
(7)继续单击
go(F5),程序运行到第2个断点,变量窗口显示最小公倍数j的值是3,显然错误,因为最小公倍数j的值应该是21,说明第1个断点到第2个断点之间有错误。
(8)单击
(StopDebugging(ShaftF5))停止调试,仔细分析程序,发现循环条件j/n!
=0错误,因为只有被n除尽的j才是最小公倍数,循环条件应该是j%n!
=0。
(9)重新编译、连接,并取消第一个断点,再单击
(Rstart(Ctrl+Shaft+F5))重新开始调试,单击
go(F5),程序运行到第九行,就是新的第一个断点。
(10)变量窗口显示最小公倍数j的值是21,最小公倍数计算正确。
(11)单击
go(F5),程序运行到最后一个断点,变量窗口显示最大公约数k的值是1,最大公约数计算正确。
(12)单击终止调试图标
(StopDebugging(Shaft+F5)),程序调试结束。
图7.1编译菜单中的调试命令
图7.2设置断点
图7.3Debug下拉菜单
七、跟踪到函数运行F11
10-1调试示例,根据下式求
的值,直到某一项小于0.000001。
源程序(有错误的程序)error9_1.cpp
#include
intfact(intn)
{inti;
intres;
res=1;
for(i=0;ires=res*i;
returnres;/*调试时设置断点*/
}
intmulti(intn)
{inti;
intres;
res=1;
for(i=3;i<=n;i=i+2)
res=res*i;
returnres;/*调试时设置断点*/
}
voidmain()
{inti;
doublesum,item,eps;
eps=0.000001;
sum=1;
item=1;
for(i=1;item>=eps;