一、 实验目的和要求
(1)掌握正确的函数定义与调用,需要时会正确使用函数声明。会正确设置形式参数,理解参数传递及程序的执行流程。
(2)理解各种不同存储类别变量的生命期与作用域
(3)进一步熟悉调试器的使用,会利用调试器进行查错改错,会跟踪程序运行的每一步,观察变量的变化情况。
二、实验环境(实验设备)
硬件: 微型计算机
软件: Windows 操作系统、Microsoft Visual Studio 2010
实验题目(1)【见实验教材实验四的题目2】:
编程序exp4_2.c,巧用函数调用,打印不同行数和字符构成的等腰三角形。具体要求:定义一个函数原型void DrawTriangle (int n,char c); ,实现功能为打印一个n行的由字符c组成的等腰三角形。主程序调用该函数,实现打印5行“ '* ’ ”、10行“ '# ’ ”的等腰三角形。
实验解答:
① 源程序exp4_2.c的代码是:
#include <stdio.h>
void DrawTriangle(int n, char c)
{
for (int i = 0; i < n; i++)
{
for (int j = 0; j <= n - i; j++)
{
printf(" ");
}
for (int j = 0; j <= 2 * i; j++)
{
printf("%c", c);
}
printf("\n");
}
printf("\n\n");
}
int main()
{
int n = 0;
char c = '0';
DrawTriangle(5, '*');
DrawTriangle(10, '#');
return 0;
}
②主函数中只保留打印’*’组成三角形的一条调用语句,然后改变控制行数的第一个实参,测试当该值为多大时,你的屏幕无法正常显示该等腰三角形,试分析原因。(提示:模拟DOS界面可以查看属性,观赛屏幕缓冲区的大小和窗口大小,再进行测试分析)。如果希望刚才的实参提供后仍然能正常显示,可以有什么办法?
当值为81时,屏幕无法正常显示’*’。因为屏幕缓冲区的宽度为160和窗口宽度为158。
把屏幕缓冲区的宽度调整为162(或更大)后,刚才的实参提供后仍然能正常显示。
实验题目(2)【见实验教材实验四的题目5】:
编程序exp4_5.c,验证歌德巴赫猜想:2000以内的正偶数(不包括2)都能够分解为两个质数之和。(算法提示:将整数分解为两个整数,然后判断它们是否均为质数。若是,则满足题意并输出;否则重新进行分解和判断。其中,判断一个整数是否为质数采用函数实现。每个偶数只要得到一种分解就停止,不必要求出该偶数的所有质数和组合)。
实验解答: 源程序exp4_5.c的代码是:
#include <stdio.h>
#include <math.h>
int judgePrime(int n)
{
int i, k;
int judge = 1;
if (n == 1) { judge = 0; }
k = (int)sqrt((double)n);
for (i = 2; judge && i <= k; i++)
{
if (n % i == 0) { judge = 0; }
}
return judge;
}
int main()
{
int x = 0, y = 0, number = 0, num1 = 0, num2 = 0;
for (int number=4; number<=2000;number+=2)
{
for (x = 2; x < number / 2; x++)
{
num1 = x;
if (judgePrime(num1) == 0)
{
num1 = 0;
}
num2 = number - x;
if (judgePrime(num2) == 0)
{
num2 = 0;
}
if (num1 && num2)
{
printf(" %4d = %2d + %d\n", number, num1, num2);
break;
}
}
}
return 0;
}
实验题目(3)【见实验教材实验四的题目7】:
编程序exp4_7.c,用递归方法实现求解两个整数的最大公约数,并与迭代方法作比较。
实验解答:
①程序exp4_7.c代码如下:
#include<stdio.h>
int gcd(int m, int n)
{
if (m > n)
return gcd(m - n, n);
else if (m < n)
return gcd(m, n - m);
else if (m == n)
return m;
}
int main()
{
int m, n;
printf("Input m,n:\n");
scanf_s("%d%d", &m, &n);
printf("GCD is: %d\n", gcd(m, n));
}
② 多次运行程序,输入不同的数据,请填写下表
你输入的数据 你程序的输出结果
12 6 GCD is: 6
348 3 GCD is: 3
90 8 GCD is: 2
24 8 GCD is: 8
实验题目(4)【见实验教材实验四的题目8】:
用调试器观察程序exp4_8.c的运行过程,并记录各种变量在每一步执行时的变化情况,在表格中填写每一个跟踪步每个变量对应的值。程序代码如下。
#include <stdio.h>
int a = 1;
int f(int a)
{
auto int b = 2;
static int c = 3;
a = a+1;
b = b+1;
c = c+1;
return (a+b+c);
}
int main()
{
int i;
for (i=0;i<3;i++)
{
a = a+2;
printf("%d \n",f(a));
}
return 0;
}
提示:首先选择“调试”菜单,再选择“窗口”子菜单,再选择打开“监视1”窗口,在其中输入&a、&b、&c、&i进行观察,点开这些地址符前面的+号,就可以看到对应变量的值,注意观察地址值的变化以区分目前空间是哪个变量在作用域,尤其同名变量。下表中在某位置该变量不可见则不填内容。
跟踪点(黄色跟踪箭头指在这一行) | 全局变量a | f的形参a | f 自动局部变量b | f 静态局部变量c | 主函数的i |
---|---|---|---|---|---|
main函数的左大括号处 | 1 | ||||
第1次for行 | 1 | -858993460 | |||
a = a+2; | 1 | 0 | |||
printf行 | 3 | 0 | |||
按F11到f函数左大括号处 | 3 | 3 | |||
auto int b = 2; | 3 | -858993460 | 3 | ||
a = a+1; | 3 | 2 | 3 | ||
b = b+1; | 4 | 2 | 3 | ||
c = c+1; | 4 | 3 | 3 | ||
return (a+b+c); | 4 | 3 | 4 | ||
第1次f函数右大括号处 | 4 | 3 | 4 | ||
按F10回到主函数的printf行 | 3 | 0 | |||
按F10到第2次for行 | 3 | 0 | |||
a = a+2; | 3 | 1 | |||
printf行 | 5 | 1 | |||
按F11到f函数左大括号处 | 5 | 4 | |||
auto int b = 2; | 5 | -858993460 | 4 | ||
a = a+1; | 5 | 2 | 4 | ||
b = b+1; | 6 | 2 | 4 | ||
c = c+1; | 6 | 3 | 4 | ||
return (a+b+c); | 6 | 3 | 5 | ||
第2次f函数右大括号处 | 6 | 3 | 5 | ||
按F10回到主函数的printf行 | 5 | 1 | |||
按F10到第3次for行 | 5 | 1 | |||
a = a+2; | 5 | 2 | |||
printf行 | 7 | 2 | |||
按F11到f函数左大括号处 | 7 | 5 | |||
auto int b = 2; | 7 | -858993460 | 5 | ||
a = a+1; | 7 | 2 | 5 | ||
b = b+1; | 8 | 2 | 5 | ||
c = c+1; | 8 | 3 | 5 | ||
return (a+b+c); | 8 | 3 | 6 | ||
第3次f函数右大括号处 | 8 | 3 | 6 | ||
按F10回到主函数的printf行 | 7 | 2 | |||
按F10到第4次for行 | 7 | 2 | |||
主函数的return 0;处 | 7 | 3 |
四、实验小结(包括问题和解决方法、心得体会、意见与建议、实验出错信息及解决方案等)
(一)实验中遇到的主要问题及解决方法
- 函数调用时传递的参数类型和个数不对,问同学后得到解决。
- 递归没有终止条件,debug后找到问题,然后修改代码。
(二)实验心得
- 对递归有了初步的理解
- 函数的使用应多加练习。