十六进制数,这可能是一个地址值。回到程序我们发现原来在这三个赋值语句中混淆了a、b与*a、*b的区别,前者是指针变量,它们的值是所指向变量的指针(即地址),后者才是所指向变量的值(该错误也可通过在程序中设置printf语句来发现,这个留给大家去实践)。
纠正这个错误后,程序就能得到正确的运行结果,至此该程序的调试工作就完成了。 上面仅是两个简单的示例,复杂的大型程序的调试工作要比它繁琐得多。读者应养成勤思考、多研究的习惯,在实践中不断积累经验。
15.5 上机实验设计
实 验 概 述
任何一门计算机语言的学习都离不开上机实践这一重要环节,C语言的学习也不例外。学习者应该培养独自编写程序及上机调试程序的能力。学习C语言应该保证至少有32小时的上机时间,与理论授课时间比最好能达到1:1。
1.实验目的
实验的目的不仅是为了验证理论课学到的知识和自己所编写的程序是否正确,更重要的在于:
(1) 熟悉计算机系统的操作方法。通过对C语言(Turbo C 3.0)程序开发环境的了解掌握,为以后学习掌握新的计算机语言开发环境打下基础,起到举一反三、触类旁通之功效。
(2) 巩固、加深对理论课的理解。教材上的一些语法规定,听起来可能枯燥无味,而通过多次上机,反复实践就能够自然地、熟练地掌握它们。
(3) 培养上机调试程序的能力。程序从编写到能够正确运行,必须经过调试这一重要环节。调试能力的高低往往取决于经验,学习者虽可以借鉴他人已有的经验,但更重要的是通过自己动手,直接实践来学习积累。学习者应变被动学习为主动学习,即除了将自己编写的程序上机调试至能正确运行外,还可对一些正确的程序人为设置一些错误和障碍并进行调试,观察并分析出现的问题,从中获得更多的收获。
2.实验步骤
对于每次上机实验,一般要求按以下步骤进行:
(1) 准备工作。上机前应将本次实验的源程序准备好,即在纸上清晰、工整的书写好源程序,并手工检查无误(如大小写、标点符号有无错误等)再上机,以提高上机的效率,对有疑问处可在纸上作上记号,以便上机实验时观察、研究。
(2) 上机输入源程序及调试程序。在TC的集成开发环境的编辑器中输入源程序,然后开始编译调试,注意当出现问题的时候,你应先自行处理,多多思考,以培养独自分析并解决问题的能力,如确实解决不了,再向旁人请教。
(3) 书写实验报告。上机完成后,应按以下几方面来整理实验报告: ① 实验题目及源程序清单。 ② 运行结果及发现的问题。
③ 本次实践的经验所得及问题分析。 ④ 实验报告单的参考格式如下页所示。
? 297 ?
C语言程序设计实验报告单 班级 实验时间 实验题目 学号 实验地点 姓名 实验目的 实验要求 实验内容 及 主要步骤 实验 程序清单 实践经验 及 问题分析 ? 298 ?
实验一 TC 3.0的集成开发环境及简单C程序的运行
1.目的及要求
(1) 了解你所使用的计算机系统的基本操作方法,并学会使用。
(2) 了解TC 3.0的集成开发环境及如何在该环境下来编辑、编译、连接和运行一个C程序。
(3) 输入并运行简单的C程序,了解并掌握C语言源程序的特点。 2.实验内容
(1) 学习从开机到进入TC 3.0系统的操作,包括机器的冷启动及TC集成环境的进入、 退出等。
(2) 学习使用TC 3.0的集成开发环境。读者试用File|New菜单来编辑下面这个简单的程序(文件名取为hello.c),在输入过程中请注意区分大小写,因为C是区分大小写的。
#include ?stdio.h? void main() {
printf(?Hello, world! \\n?); }
输入完成后,接下来是对该程序做编译、连接,用键F9或Compile|Compile、Compile|Link或Compile|Make或Compile|Build all即可完成,得到可执行的EXE文件(注意要保证你的源程序输入没有任何错误,否则还要调试修改)。之后就可以运行这个EXE文件了(用集成环境下的Run|Run菜单或按Ctrl?F9热键),要观察运行结果用Window|User screen菜单或热键Alt?F5,当然也可直接在DOS提示符下像DOS的外部命令一样运行它。如果要保存该文件,选择File|Save菜单或热键F2将该文件取一个名称(hello.c)保存到指定的路径下,今后如果要再次装入这个文件进行编辑、修改、运行,可以用File|Open(F3)菜单选择打开这个文件。
(3) 输入例1.1(取名为LT1_1.c)并编译运行。要注意的是,需要重新选择File|New菜单新建一个源程序文件,不能接着刚才的实验内容来做。
(4) 输入例1.2(取名为LT1_2.c)并编译运行,了解如何在运行时向程序输入数据。 (5) 输入例1.3、例1.4并编译运行。 注意:
以后的实验给文件取名的规则为:对例题以LT后跟编号的形式给出,如LT1_1.c,其中LT表示例题,1_1表示例题号;对习题以XT后跟编号的形式给出,如XT3_6.c,其中XT表示习题,3_6表示习题号;实验给出的例子以SY后跟编号的形式给出,如SY5_1.c,其中SY表示实验,5_1表示第五个实验的第一个例子。
实验二 数据类型及其输入和输出
1.目的及要求
(1) 掌握C语言的基本数据类型,熟悉如何定义整型、字符型、实型变量及对它们的赋值方法。
(2) 掌握以上类型的数据在C中如何用scanf()和printf()函数来进行输入输出操作。 (3) 掌握转义字符的使用。
(4) 进一步熟悉TC环境下对程序的编辑、编译、连接和运行。
? 299 ?
2.实验内容
(1) 学习整型变量的赋值方式及其输入输出,掌握输入输出函数中处理整型数据的格式符。输入以下程序(取名为SY2_1.c)。
#include ?stdio.h?
void main() {
unsigned d?65534; int a, b, c, e, f, g, h; a?3, b?014, c?0x2e; printf(?input e, f, g, h: \\n?);
scanf(??d?o?x?d?, &e, &f, &g, &h); printf(?a??d, b??d, c??d, d??d\\n?, a, b, c, d); printf(?e??o, f??x, g??d, h??u\\n?, e, f, g, h); }
编译成功后运行,当出现提示“input e, f, g, h:”时输入10□010□0x10□?3?CR?(说明:□表示空格,?CR?表示按回车键)。按Alt?F5观察输出的结果为:
a?3, b?12, c?46, d??2 e?12, f?8, g?16, h?65533
在使用scanf函数输入八进制、十六进制数时,可以不用先导“0”和“0x”,如本例运行时直接输入10□10□10□?3
请读者根据printf()和scanf()函数中格式控制符的含义自行分析该结果。若将本程序scanf()参数内的&符号除去,会出现什么结果?为什么?
(2) 学习字符变量的赋值方式及输入输出。初步掌握字符数据和整型数据的互相赋值方式。输入并运行以下程序(取名为SY2_2.c)。
#include ?stdio.h?
void main() {
char ch1, ch2; ch1??A?, ch2??a?;
printf(?ch1??c, ch2??c\\n?, ch1, ch2); printf(?ch1??d, ch2??d\\n?, ch1, ch2); }
在此基础上将第三行改成“int ch1, ch2;”并运行程序。 再将第四行改为“ch1?65, ch2?ch1?32;”并运行程序。 (3) 学习格式化的输出。输入并运行例4.8和4.9。 (4) 学习使用转义符。输入并运行例2.2、习题2.6。
实验三 运算符、表达式及最简单的C程序设计
1.目的及要求
(1) 熟悉C语言的算术运算符、关系运算符、逻辑运算符、逗号运算符、赋值运算符及其表达式。
(2) 进一步了解掌握scanf()。
? 300 ?
(3) 学习getchar()、putchar()的使用。 (4) 学习简单的顺序程序设计。 2.实验内容
(1) 输入以下程序,认真分析各表达式,推测正确的运行结果,然后编译运行该程序。 #include ?stdio.h? void main() {
int a, b, c; int x, y, z; a?1, b??1, c?2; x?a??; y?15?a || b??; z???b&&(c?b?a);
printf(?\\na??2d, b??2d, c??2d\\n?, a, b, c); printf(?x??2d, y??2d, z??2d\\n?, x, y, z); }
当编译成功后运行该程序,按Alt?F5观察到的结果为: a?2, b?0, c?2
x?1, y?1, z?0
读者可能推测的结果是: a?2, b?1, c??1
x?1, y?1, z?1
为什么有差异呢?我们通过集成环境中的Debug|Watches和单步跟踪工具来调试观察, 分六次选择Debug|Watches下的Add watch子项加入要观察的六个变量a、b、c、x、y、z。 之后用F8单步执行程序,当程序运行到“y?15?a || b??;”语句时,可以看到a、x的值是正确的,运行完该语句后可以发现y的值为1,b的值为?1,这说明该语句中的b??没有被执行;再用F8执行完下一条语句,发现b的值为0,说明??b被执行了,z的值为0,c的值为2,这说明赋值表达式c?b?a没有被执行。通过以上的跟踪观察我们可以看到差异的原因是由于逻辑运算符||、&&后的两个表达式没有被执行到,不被执行的原因是什么呢?回顾学过的知识,我们知道逻辑运算有时会短路。对于||运算符,当左边的操作数结果为真时,右边的操作数就不再进行计算;对于&&运算符,当左边的操作数结果为假时,右边的操作数就不再进行计算了。由于15?a等于1,所以b??不被计算;由于??b等于零,所以(c?b?a)也不被计算。
(2) 输入下面的程序并运行。 #include ?stdio.h? void main() {
char ch1, ch2;
printf(?\\n请输入两个字符: \\n?); ch1?getchar(); ch2?getchar();
printf(?\\n输出结果为: \\n?); putchar(ch1);
? 301 ?