基于VC++6.0平台的C程序编译问题及其解决策略

2013-12-29 00:00:00侯小刚赵晟轩赵华
电脑知识与技术 2013年4期

摘要:目前大多数C语言的编译系统都是集成环境,而VC++6.0是最常用运行平台。为了提高学生在VC++6.0平台下完成C语言编程能力,论文首先对文献[1]进行分析,指出其对隐形问题的错误分析,然后给出正确的解释和修改案例。其次通过案例给出显性问题和隐性问题的调试和编译方法。最后指出编译C语言源程序的问题及应用策略,从而提高学生编程能力。

关键词:显性问题;隐性问题;编译方法; VC++6.0;解决策略

中图分类号:TP312 文献标识码:A 文章编号:1009-3044(2013)04-0773-03

C Program Compilation Problems and Solving Strategy Based on VC++ 6.0 Platform

HOU Xiao-gang1, ZHAO Sheng-xuan2 , ZHAO Hua3

(1. Institute of Geographic Science and Tourism,Xinjiang Normal University,Urumqi 830054,China;2. Digital Culture and New Media Technology Research Center Century College,Beijing 102613,China;3. College of Computer Science and Engineering,Xinjiang Normal University,Urumqi, 830054,China)

Abstract:In order to improve the students ability of completing C language programming on VC++ 6.0 platform, this paper points out the error analysis of implicit problem and gives the correct interpretation based on the analyzing of references[1]. Then the debugging and compilation method on implicit and explicit problems are provided by establishing the examples. Finally, the strategies of compiling C language source code are presented to improve the students' programming ability.

Key words: dominant problem; recessive problems; compiled methods; VC++6.0; coping strategy

1 概述

C语言是一种常用计算机程序设计语言,它不仅具有编程的灵活性而且还具有很强的数据处理能力,不仅在软件开发上,还在各类科研都需要用到C语言[2],它不仅可以编写系统软件,甚至可以开发出三维、二维图形和动画,因此深受计算机专业工作者和计算机应用开发人员的喜爱[3]。但是C语言也存在缺点,主要表现在:首先对数据的封装性不做要求,这一点使得C在数据的安全性上有很大缺陷(这也是C和C++的一大区别)。其次C语言的语法限制不太严格[4]。再次对变量的类型约束不严格,从而影响程序的安全性。最后对数组下标越界不作检查等[5]。目前比较优秀的C语言编译平台是Microsoft公司推出的一款Visual C++6.0编译器, 它不仅是一个C++ 编译器,而且是一个基于Windows操作系统的可视化集成开发环境(integrated development environment,IDE)[6]。它由许多组件组成:包括编辑器、调试器以及程序向导AppWizard、类向导Class Wizard等开发工具[3]。该文的目的是为了帮助学生在VC++6.0平台下完成用C语言的编程,该文分析文献[1],指出了其中对隐形问题分析不当之处以及所引案例的不妥之处,并进行错误改进,最后基于显性和隐性两类问题提出正确调试和编译方法,并通过案例分析介绍C程序的编译过程。

2 基于VC++6.0的C程序编译问题分析及其应对策略

文献[1]分析了几种C语言编程中经常出现“显性”与“隐性”问题,并通过案例展示讨论。

#include

void main()

{

char bz,oper;

int data1,data2,t;

printf("********* 微型计算器 *********\n");

printf("*********** 运算符: '+' '-' '*' '/' ***********\n");

printf("\n");

while(bz!='N'&&bz!='n')

{

printf("请输入运算符:\n");

scanf("%c",&oper);

printf("请输入data1:\n");

scanf("%d",&data1);

printf("请输入data2:\n");

scanf("%d",&data2);

switch(oper)

{

case '+':printf("%d+%d=%d\n",data1,data2,t=data1+data2);break;

case '-':printf("%d-%d=%d\n",data1,data2,t=data1-data2);break;

case '*':printf("%d*%d=%d\n",data1,data2,t=data1*data2);break;

case '/':printf("%d/%d=%d\n",data1,data2,t=data1/data2);break;

default:printf("输入的运算符无效!\n");

}

printf("是否计算?(输入N/n退出)\n");

scanf("%c",&bz); //此语句无效

}

}

针对文献[1]对上述案例的分析,发现有如下不妥之处:第一,本案例错误之处是对变量bz没有赋初值,使得变量的内容是一个随机值,这就给程序运行带来了隐患,使程序也许不会进入循环,这是一个“隐性问题”,文献[1]对此没有进行分析。在C语言中变量一定要先定义,后引用,在本案例中要对bz赋初值。第二,本案例是用2个scanf()函数接收两个整型的操作数的输入,用一个scanf()接收一个字符型的程序结束标志的输入,本意是想对bz赋值从而控制循环,系统却把第二个操作数结束输入标志(如空格、回车、tab)当做有意义字符通过scanf(“%c”,&bz)语句直接赋给变量bz,从而导致表面上的scanf(“%c”,&bz)语句失效,这又是一个“隐性问题”。在C语言中整型数据与字符型数据混合输入时要注意输入方式,一定要清楚其中的运行规则,在本例中要在scanf(“%c”,&bz)语句前加入getchar()语句接收操作数结束标志,而文献[1]所分析是缓冲区造成的,与实际不符。

3 C语言编程中常见错误

3.1 “显性”问题

C语言中“显性”问题是语法错误[3],“显性”问题VC++ 6.0编译器可以自动帮学生识别出来了。例如:1)语句结束标志的分号,该用结束标志的时候忘记添加,而在不需要的地方添加;2)函数体、复合语句等前后缺少花括号;3)switch语句中选项后忘记加break跳出命令;4)数组长度使用变量;5)忽略大小写区eARThObF4kjlPa018Br1uY4mSRlcFpSGUpY6bEMYTmE=分,导致显示变量未定义等。为了避免与解决“显性”问题的出现,学生要做到如下两点:1)养成良好的书写习惯,如:输入花括号时成对输入、注意程序的缩进格式、一个语句一行等;2)根据VC++6.0的报错功能逐个找个错误原因修改(双击可指出错误点)。

3.2 “隐性”问题的应对策略

C语言中的“隐性”问题是逻辑错误[3],“隐性”问题VC++ 6.0编译器是无法识别出来的,只有靠学生对C语言基本知识的牢固掌握以及在编程中养成良好的习惯,才有可能减少C语言编程中的“隐性”问题。C语言中,逻辑错误比较复杂,不易察觉,具有隐蔽性、复杂性和致命性[7]。C语言的“隐性”问题归纳起来分为以下几类:1)数据之间显隐性转换的问题。如下代码图1与程序运行结果图2。语句1中1/2.0本身得出了正确的结果0.5,但是0.5赋值给一个整形变量后就会丢掉小数点。语句3与语句4中1/2本身是想得到结果0.5,但是学生忘记了算术运算符“/”是取整运算。语句2才得出了正确的结果。

2)局部变量初始化默认值是随机值。在C语言编程中,经常出现忘记对变量的赋初值,从而出现异常的运算结果。如下程序图1与结果图2,本应该输出的sum的值是45,add的是362880,但本程序输出的值显然是随机值,要想输出正确的结果,必须给sum与add分别赋初值0和1。

4)指针引用错误。指针式C语言的精华所在,也是难点所在,学生在这个知识点上所错误最多,而且错误也不易找到与修改,而有些隐藏较深的错误即使对于熟练的程序员来说也很难发现与排除。因此在学习C语言时,正确理解和使用指针是非常重要的。以下通过几个案例说明指针编程中几个常见问题及纠正方法:①使用未初始化的指针。如图5代码与图6结果,指针p在声明时未初始化,指向的是一个随机内存地址。它可能指向系数栈、全局变量或操作系数。当执行*p=12时,程序不加辨别的在p所指向的随机位置处写入一个12。这时程序可能立即崩溃(如图6),也可能等半小时然后崩溃,或者程序另一个部分数据随机破坏而用户毫无察觉。可见这种错误非常难查找,所以在使用指针之前一定要为指针变量初始化有效地址。

②无效指针引用。当指向无效地址的指针仍被引用时即发生无效指针引用,导致这类错误的一种可能是当q未初始化时执行p=q;。此时指针p也变为未初始化的。任何对*p的引用即造成无效指针引用。避免此类错误的惟一途径是用画图的方法记录每个步骤的指针引用情况,并确保全部指针都各有所指。由于和①同样的错误原因,无效指针引用也会导致程序莫名其妙地崩溃。③零指针引用。当试图在程序中引用指向零地址的指针时即发生零指针引用。例如图7 p=0;是一个无效指针,不指向任何内存块。所以试图对此内存块的读写即为无效的零指针引用结果如图8。将指针指向零地址是有充分的正当理由的,然而对零指针的引用(取出指针指向的地址中的内容)却是无效的。为了避免这类错误的出现,最好的方法是为程序的每一步画图记录指针引用情况。

此外,数组定义与引用的错误。在C语言中,对数组定义的理解虽然看似简单,但定义数组时下标类型出错,数组名作地址时理解出错,多维数组中数组元素的表示形式出错。

4 结论

在编译调试过程中,应熟悉C语言的语法结构,熟练掌握各种结构的用法,在良好的编程习惯下借助VC++6.0的调试功能即可解决“显性”问题。语法错误在经过大量练习的“洗礼”过后,已经微不足道,学生都可以轻松解决,以后更加困惑学生的将是隐性问题,逻辑上的错误VC++6.0不能指出,只能是学生在熟悉各种结构和算法,清晰掌握其中原理的基础上,逐个实现程序功能,逐一排错。

参考文献:

[1] 胡敬朋.基于VC++ 6.0的C程序编译问题分析及其应对策略[J].电脑知识与技术,2011,7(19):4584-4585.

[2] 李必信.一种分析和理解程序的方法——程序切片[J].计算机研究与发展,2000,37(3):284-291.

[3] Weiser M.Programmers Use Slices When Debugging[J] .Communications of the ACM,1982,25(7):446-452.

[4] Zhang Xiangyu,He Haifeng.Experimental Evaluation of Using Dynamic Slices for Fault Location[C]//California,USA:Proc.of the 6th International Symposium on Automated and Analysis-driven Debugging.2005.

[5] Sun Jirong,Li Zhshu,Ni Jianchen,etal.Software Fault Localization Based on Testing Requirement and Program Slice[C]// Guilin,China :Proc.of International Conference on Networking,Architecture and Storage,2007.

[6] 李晓玫,杨小平.Excel中的VBA程序设计[J].四川师范大学学报:自然科学版,2004,2004(4):423-426.

[7] 王林章,李宣东,郑国梁.模型驱动的软件测试研究[J].计算机科学,2005,32(10):230-235.