广州大学学生实验报告
报告日期:
学院 | 年级/专业/班 | 姓名 | 学号 | ||||
实验课程名称 | 程序设计基础(实验课) | 成绩 | |||||
实验项目名称 | 实验2 函数 | 指导 老师 |
一、实验目的及要求
1.掌握函数的定义方法,及函数调用的形式;
2.掌握函数实参与形参的对应关系,“值传递”与“地址传递”的方式与区别;
3.掌握函数的应用方法,熟悉函数的嵌套调用和递归调用的设计方法;
4.了解全局变量、局部变量、动态变量及静态变量的概念和使用方法;
5.综合应用顺序结构、选择结构和循环结构的设计方法设计函数和程序。
二、实验设备与平台
1. 实验设备:计算机
2. 平台:Windows操作系统,Microsoft Visual C++或其它合适的C++编程环境。
三、实验内容及步骤
编写程序,解下列问题,然后把编写的程序代码和运行结果截图复制到题目后面的空白处。
1、求三角形的面积。已知三角形的三边a、b、c,则三角形的面积为
其中,s=(a+b+c)/2。
(1)三角形的三边的边长由cin输入,需要判断这三边是否构成一个三角形。若是,则计算其面积并输出,否则输出“错误:不能构成三角形!”。
(2)程序中要包含两个函数,一个函数判断是否构成三角形,另一个函数计算三角形的面积。
程序代码:
// 程序设计基础实验2 函数
// 问题描述:
/*1、求三角形的面积。已知三角形的三边a、b、c,则三角形的面积为
area = sqrt(s*(s-a)*(s-b)*(s-c))
其中,s = (a + b + c) / 2。
(1)三角形的三边的边长由cin输入,需要判断这三边是否构成一个三角形。
若是,则计算其面积并输出,
否则输出“错误:不能构成三角形!”。
(2)程序中要包含两个函数,
一个函数判断是否构成三角形,
另一个函数计算三角形的面积。*/
#include<iostream>
using namespace std;
bool IsTriangle(double a, double b, double c); //判断是否构成三角形
double GetArea(double a, double b, double c); //获取三角形的面积
int main()
{
//声明三角形的三条边、三角形的面积变量
double a, b, c, area;
cout << "请输入三角形的三条边a、b、c:" << endl;
cin >> a >> b >> c;
if (IsTriangle(a, b, c)) //判断输入的三条边是否能构成三角形
{
area = GetArea(a, b, c); //计算三角形面积
cout << "三角形的面积为:" << area << endl;
}
else
{
cout << "错误:不能构成三角形!" << endl;
}
return 0;
}
//判断是否构成三角形
bool IsTriangle(double a, double b, double c)
{
if (a > 0 && b > 0 && c > 0) //三条边均需要大于零
{
if (a + b > c && a + c > b && b + c > a) //两边之和大于第三边
{
return 1;
}
else
return 0;
}
else
return 0;
}
//获取三角形的面积
double GetArea(double a, double b, double c)
{
double s = (a + b + c) / 2;
double area = sqrt(s * (s - a) * (s - b) * (s - c)); //三角形面积计算公式
return area;
}
运行结果截图:
案例1:(确定构成三角形)
心得与体会:
1、本题是一个很好的题目,它告诉我们,在做一件事或者是求解一样东西时,需要先判断前提条件是否成立,若条件都不成立,那么求解就没有意义了。例如,本题中的求解三角形面积,则先需要判断输入的边是否构成三角形。
2、编程求下式值,其中ni用函数来实现,且设参数n的默认值为2:
程序代码:
// 程序设计基础实验2 函数
// 问题描述:
/*2、编程求下式值,其中ni用函数来实现,且设参数n的默认值为2:
n^1+n^2+n^3+n^4+n^5+n^6+n^7+n^8+n^9+n^10,n = 1,2,3*/
// 分析可得:如上为等比数列求和,公比q = n, 求和项的个数"n" = 10
// 等比数列求和公式:S = a1*(1-q^n)/(1-q),其中a1为首项,q为公比,n为求和项的个数
#include<iostream>
#include <cmath> //使用函数pow()需要包含该头文件
using namespace std;
int Func(int n = 2); //获取三角形的面积
int main()
{
//声明自变量、计算结果
int n, result1, result3;
//数据初始化
result1 = 0;
result3 = 0;
n = 1;
result1 = Func(n);
cout << "当n为1时,求解的结果为:" << result1 << endl;
//函数参数为缺省时,n为2
cout << "当函数缺省时(n默认为2),求解的结果为:" << Func() << endl;
n = 3;
result3 = Func(n);
cout << "当n为3时,求解的结果为:" << result3 << endl;
}
//计算求和结果
int Func(int n)
{
//int a1 = n ^ 1; //首项 //此写法错误,原因是:在C++中^为异或运算,不是指数的符号
int a1 = n; //首项
int q = n; //公比
int num = 10; //求和项的个数
int S = 0; //等比数列求和结果
if (q == 1) //注意需要分类讨论,当q的值为1时
{
S = num * a1; //计算求和结果
}
else //当q的值不为1时
{
//S = a1 * (1 - q ^ num) / (1 - q); //不能直接使用^运算符
S = a1 * (1 - pow(q, num)) / (1 - q); //计算求和结果
}
return S;
}
运行结果截图:
心得与体会:
- 本题中采用了缺省的函数,我在平时写作业中比较少用到函数缺省参数。这次实验很好地让我重拾了函数缺省的写法。
- 本题中,我直接运用了高中数学中的等比数列的公式进行计算,提高算法效率。
- 在运用高中数学公式中,需要对参数n进行分类讨论。当n为1时,采用一种公式,当n不为1时,采用另外一种公式。
- 在编码过程中,我发生了编写错误。原因:之前暑假经常使用matlab进行编程,习惯了指数运算直接使用^,但这在C++中是不允许的。需要使用函数pow()来进行指数运算。
3、用递归法将一个整数n转换成字符串。如输入1234,应输出字符串“1234”。n的位数不确定,可以是任意位数的整数。
程序代码:
// 程序设计基础实验2 函数
// 问题描述:
/* 3、用递归法将一个整数n转换成字符串。
如输入1234,应输出字符串“1234”。
n的位数不确定,可以是任意位数的整数。*/
#include <iostream>
using namespace std;
// 递归函数,将整数n转换为字符串s,同时使用index跟踪字符串的当前位置
void IntToString(int n, char*& s, int& index);
int main()
{
int num = 0; //整数num
char* s = NULL; //指针s初值置为空
cout << "请输入一个整数:" << endl;
cin >> num;
int digits = num == 0 ? 1 : int(log10(abs(num))) + 1; //获取输入数据的位数
//依据整数的正负号,分别划分不同大小的数组
if (num >= 0)
{
s = new char[digits + 1]; //动态创建一个数组
}
else
{
s = new char[digits + 2]; //动态创建一个数组,比正整数多一位,用于存储负号
}
int index = 0; // 用于跟踪字符串位置的索引
if (s) //内容申请成功
{
IntToString(num, s, index); //调用函数,将整数转换为字符串
s[index] = '\0'; //添加串结束符
cout << "转换后的字符串为:" << endl;
cout << s << endl;
delete[] s; //释放s所指存储空间
s = NULL; //对指针变量赋NULL,清除其无意义的地址值
}
else //内存申请失败
{
cout << "转换失败:内存分配错误" << endl;
}
}
//整数转为字符函数
void IntToString(int n, char*& s, int& index)
{
if (n < 0)
{
s[index] = '-'; //存储整数符号
index++; //更新索引
n = abs(n); //取绝对值
}
if (n < 10) //数据仅为1位时
{
s[index] = '0' + n; //计算出一个字符值,其ASCII码值等于'0'的ASCII码值加上(n % 10)的值
}
else //数据大于1位时
{
IntToString(n / 10, s, index); //递归调用函数,不断缩小整数范围,以处理更高位的数字
s[index] = '0' + (n % 10); //逐个将整数的每位字符添加到下标为index的动态字符数组中
}
index++; //更新索引,指向下一个位置
}
运行结果截图:
案例1:(正整数转字符串)、
心得与体会:
- 原先我使用的是固定的字符数组进行存储整数转换后的字符串。但这并不符合题目“任意位数的整数”的要求。于是,我采用了动态数组的方法进行存储。
- 程序中隐含了两种范围的整数:非负数和负数。负数除了要求存储数位外,还要存储符号位:负号。这是容易在编程中遗漏的。
4、编写程序,计算下面公式并输出结果。
(1)编写一个函数计算n!
(2)编写主函数,由键盘输入n和m,调用(1)中的函数完成计算。
(3)输入n和m要给出提示,并检查n和m的合理性,不合理的输入应输出错误信息,并不再进行计算。
(4)运行程序,输出计算
程序代码:
// 程序设计基础实验2 函数
// 问题描述:
/* 4、编写程序,计算下面公式并输出结果。
(1)编写一个函数计算n!
(2)编写主函数,由键盘输入n和m,调用(1)中的函数完成计算。
(3)输入n和m要给出提示,并检查n和m的合理性,不合理的输入应输出错误信息,并不再进行计算。
(4)运行程序,输出计算:C85,C52,C70 */
#include<iostream>
using namespace std;
int getFactorial(int n); //获取n的阶层
int main()
{
//声明自变量、计算结果
int n, m, result;
//数据初始化
n = m = result = 0;
cout << "请分别输入排列组合中元素总数n、选择元素的个数m:(要求0=<m<=n)" << endl;
cin >> n >> m;
//检查n和m的合理性
if (n < 0 || m < 0)
{
cout << "出错!n和m的取值均应为大于等于零的数" << endl;
cout << "程序中断,不再进行运算" << endl;
}
else if (m > n)
{
cout << "出错!m的取值不能大于n" << endl;
cout << "程序中断,不再进行运算" << endl;
}
else //n和m均合理,进行计算操作
{
if (m == 0) //特别地,当m=0时,排列取值为1
{
result = 1;
}
else
{
result = getFactorial(n) / (getFactorial(n - m) * getFactorial(m));
}
cout << "C(" << n << "," << m << ") = " << result << endl;
}
}
//获取n的阶层
int getFactorial(int n)
{
if (n == 1)
return 1;
else
return n * getFactorial(n - 1); //递归调用求阶层的函数
}
运行结果截图:
心得与体会:
- 计算阶层过程中用到了递归的思想,递归是求解大问题分解为结构相同的子问题,子问题范围逐渐缩小,最终得到一个结果,然后再逐级返回。
2、在进行排列组合运算时,同样需要对n和m进行范围检测,符合范围的才能进行运算。