广州大学学生实验报告
学院 |
年级/专业/班 |
姓名 |
学号 |
||||
实验课程名称 |
程序设计基础(实验课) |
成绩 |
|||||
实验项目名称 |
实验3 数组、结构体及指针 |
指导 老师 |
实验A 数组字符串
一、实验目的及要求
1.了解数组与数学矩阵的关系;
2.掌握数组的定义、引用与初始化;
3.理解二维数组数据的存储顺序;
4.理解并掌握冒泡排序法、选择排序法;
5.掌握字符数组与字符串的定义、引用;
6.了解字符串处理函数的用法。
二、实验设备与平台
1. 实验设备:计算机
2. 平台:Windows操作系统,Microsoft Visual C++或其它合适的C++编程环境。
三、实验内容及步骤
编写程序,解下列问题,然后把编写的程序代码和运行结果截图复制到题目后面的空白处。
1、某班期末考试科目为数学(MT)、英语(EN)和物理(PH),有最多不超过30人参加考试。考试后要求:
(1)计算每个学生的总分和平均分;
(2)按总分成绩由高到低排出成绩的名次;
(3)打印出名次表,表格内包括学生编号、各科分数、总分和平均分;
(4)任意输入一个学号,能够查找出该学生在班级中的排名及其考试分数。
程序代码:
// 程序设计基础实验3 数组、结构体及指针
// 实验A 数组字符串
// 问题描述:
/*1、某班期末考试科目为数学(MT)、英语(EN)和物理(PH),有最多不超过30人参加考试。
考试后要求:
(1)计算每个学生的总分和平均分;
(2)按总分成绩由高到低排出成绩的名次;
(3)打印出名次表,表格内包括学生编号、各科分数、总分和平均分;
(4)任意输入一个学号,能够查找出该学生在班级中的排名及其考试分数。*/
#include<iostream>
#include<iomanip>
using namespace std;
//数组初始化
void Initial(int num, string*& p_Code, double*& p_MT, double*& p_EN, double*& p_PH, double*& p_TotalScore, double*& p_AvrScore, int*& p_Rank);
//学生考试成绩分数录入
void RigisterGrades(int num, string*& p_Code, double*& p_MT, double*& p_EN, double*& p_PH, double*& p_TotalScore, double*& p_AvrScore);
//交换函数:函数模板
template<typename T>
void Swap(T& element1, T& element2);
//按总分成绩排序 冒泡排序
void BubbleSort(int num, string*& p_Code, double*& p_MT, double*& p_EN, double*& p_PH, double*& p_TotalScore, double*& p_AvrScore);
//学生成绩排名生成
void PrdRank(int num, double* p_TotalScore, int*& p_Rank);
//考试成绩名次表打印
void DispGradesRank(int num, string* p_Code, double* p_MT, double* p_EN, double* p_PH, double* p_TotalScore, double* p_AvrScore, int* p_Rank);
//学生考试成绩查询
void SeekStudentGrades(int num, string* p_Code, double* p_MT, double* p_EN, double* p_PH, double* p_TotalScore, double* p_AvrScore, int* p_Rank);
//释放内存空间
void DeleteSpace(string*& p_Code, double*& p_MT, double*& p_EN, double*& p_PH, double*& p_TotalScore, double*& p_AvrScore, int*& p_Rank);
int main()
{
//double array_MT[30], array_EN[30], array_PH[30], num; //动态数组使用,而不采用固定数组
//定义指针并将其赋空值
int* p_Rank;
double* p_MT, * p_EN, * p_PH, * p_TotalScore, num;
double* p_AvrScore;
string* p_Code;
p_Rank = NULL;
p_MT = p_EN = p_PH = p_TotalScore = p_AvrScore = NULL;
p_Code = NULL;
cout << "请输入考试参与人数:" << endl;
cin >> num;
Initial(num, p_Code, p_MT, p_EN, p_PH, p_TotalScore, p_AvrScore, p_Rank); //数据初始化
RigisterGrades(num, p_Code, p_MT, p_EN, p_PH, p_TotalScore, p_AvrScore); //学生成绩录用
BubbleSort(num, p_Code, p_MT, p_EN, p_PH, p_TotalScore, p_AvrScore); //学生成绩排序
PrdRank(num, p_TotalScore, p_Rank); //学生成绩排名生成
DispGradesRank(num, p_Code, p_MT, p_EN, p_PH, p_TotalScore, p_AvrScore, p_Rank); //学生成绩打印
SeekStudentGrades(num, p_Code, p_MT, p_EN, p_PH, p_TotalScore, p_AvrScore, p_Rank); //学生成绩查询
DeleteSpace(p_Code, p_MT, p_EN, p_PH, p_TotalScore, p_AvrScore, p_Rank); //释放指针所指空间
return 0;
}
//数组初始化
void Initial(int num, string*& p_Code, double*& p_MT, double*& p_EN, double*& p_PH, double*& p_TotalScore, double*& p_AvrScore, int*& p_Rank)
{
//动态创建数组
p_MT = new double[num];
p_EN = new double[num];
p_PH = new double[num];
p_TotalScore = new double[num];
p_AvrScore = new double[num];
p_Code = new string[num];
if (p_MT && p_EN && p_PH && p_TotalScore && p_AvrScore && p_Code) //内存分配成功
{
//为数组赋初值
for (int i = 0; i < num; i++)
{
p_Code[i] = " ";
p_MT[i] = p_EN[i] = p_PH[i] = p_TotalScore[i] = p_AvrScore[i] = 0;
}
}
else
{
cout << "内存申请出错!" << endl;
}
}
//学生考试成绩分数录入
void RigisterGrades(int num, string*& p_Code, double*& p_MT, double*& p_EN, double*& p_PH, double*& p_TotalScore, double*& p_AvrScore)
{
cout << "请依次输入每位学生的学生编号、数学分数、英语分数、物理分数:" << endl;
cout << "(注意:输入学生编号后使用按下回车,然后输入分数,分数之间用空格间隔)" << endl;
for (int i = 0; i < num; i++)
{
cout << "学生编号:";
cin >> p_Code[i];
bool isExist = 0;
for (int j = 0; j < i; j++) //遍历已录入的成绩表
{
if (p_Code[i] == p_Code[j]) //当前输入的学生编号已存在于成绩表中
{
isExist = 1;
cout << "该学生编号的成绩已录入,无需再次录入" << endl;
i--;
cout << "请继续录用下一个学生的成绩" << endl;
break;
}
}
if (!isExist) //该学生编号不存在成绩表中时,继续录用
{
cout << "数学成绩、英语成绩、物理成绩:";
cin >> p_MT[i] >> p_EN[i] >> p_PH[i]; //输入该学生的相关数据
p_TotalScore[i] = p_MT[i] + p_EN[i] + p_PH[i]; //计算该学生的总分
p_AvrScore[i] = p_TotalScore[i] / 3.0; //计算该学生的平均分
}
}
}
整型交换函数
//void Swap_int(int& num1, int& num2) //进行两元素的交换
//{
// int temp;
// temp = num1;
// num1 = num2;
// num2 = temp;
//}
字符串交换函数
//void Swap_string(string& code1, string& code2) //进行两元素的交换
//{
// string temp;
// temp = code1;
// code1 = code2;
// code2 = temp;
//} //这样子写不够高效。改进:使用泛型程序设计。
//交换函数:函数模板
template<typename T>
void Swap(T& element1, T& element2)
{
T temp;
temp = element1;
element1 = element2;
element2 = temp;
}
//按总分成绩排序 冒泡排序 //把高成绩冒在数组前面
void BubbleSort(int num, string*& p_Code, double*& p_MT, double*& p_EN, double*& p_PH, double*& p_TotalScore, double*& p_AvrScore)
{
int i, j;
bool exchange;
for (i = 0; i < num - 1; i++)
{
exchange = false; //判别因子
for (j = num - 1; j > i; j--)
if (p_TotalScore[j] > p_TotalScore[j - 1]) //相邻元素反序时
{
Swap(p_TotalScore[j], p_TotalScore[j - 1]); //将总分中的两元素交换
Swap(p_AvrScore[j], p_AvrScore[j - 1]); //将平均分中的两元素交换
Swap(p_MT[j], p_MT[j - 1]); //将数学分数中的两元素交换
Swap(p_EN[j], p_EN[j - 1]); //将英语分数中的两元素交换
Swap(p_PH[j], p_PH[j - 1]); //将物理分数中的两元素交换
Swap(p_Code[j], p_Code[j - 1]); //将学生编号中的两元素交换
exchange = true;
}
if (!exchange) //本趟没有发生交换,结束算法
break;
}
}
//学生成绩排名生成:学生成绩相同时,他们的成绩排名应相同
void PrdRank(int num, double* p_TotalScore, int*& p_Rank)
{
p_Rank = new int[num]; //申请内存空间
if (p_Rank)
{
for (int i = 0; i < num; i++)
{
if (i == 0)
{
p_Rank[i] = 1; //总分第一的无需进行比较
}
else //总分非第一的同学,需要判断是否与前一位同学总分相同
{
//总分与上一名学生相同,则排名与其相同;总分不同,则排名+1
p_Rank[i] = p_TotalScore[i] < p_TotalScore[i - 1] ? p_Rank[i - 1] + 1 : p_Rank[i - 1];
}
}
}
else
{
cout << "内存申请出错!" << endl;
}
}
//考试成绩名次表打印
void DispGradesRank(int num, string* p_Code, double* p_MT, double* p_EN, double* p_PH, double* p_TotalScore, double* p_AvrScore, int* p_Rank)
{
cout << "-----------------------------------------考试成绩名次表打印-----------------------------------------" << endl;
cout << "学生编号" << '\t' << "数学成绩" << '\t' << "英语成绩" << '\t' << "物理成绩" << '\t' << "总分 " << '\t' << "平均分 " << '\t' << "排名" << endl;
for (int i = 0; i < num; i++)
{
cout << p_Code[i] << '\t' << '\t' << p_MT[i] << '\t' << '\t' << p_EN[i] << '\t' << '\t' << p_PH[i]
<< '\t' << '\t' << p_TotalScore[i] << '\t' << '\t' << setprecision(4) << p_AvrScore[i] << '\t' << '\t' << p_Rank[i] << endl;
}
cout << "----------------------------------------考试成绩名次表分割线-----------------------------------------" << endl;
}
//学生考试成绩查询
void SeekStudentGrades(int num, string* p_Code, double* p_MT, double* p_EN, double* p_PH, double* p_TotalScore, double* p_AvrScore, int* p_Rank)
{
string temp_code;
cout << "请输入需要查询的学生的编号:" << endl;
cin >> temp_code;
int i = 0;
for (; i < num; i++)
{
if (temp_code == p_Code[i])
{
cout << "-----------------------------------------考试成绩查询结果打印----------------------------------------" << endl;
cout << "学生编号" << '\t' << "数学成绩" << '\t' << "英语成绩" << '\t' << "物理成绩" << '\t' << "总分 " << '\t' << "平均分 " << '\t' << "排名" << endl;
cout << p_Code[i] << '\t' << '\t' << p_MT[i] << '\t' << '\t' << p_EN[i] << '\t' << '\t' << p_PH[i]
<< '\t' << '\t' << p_TotalScore[i] << '\t' << '\t' << setprecision(4) << p_AvrScore[i] << '\t' << '\t' << p_Rank[i] << endl;
cout << "------------------------------------------考试成绩查询分割线-----------------------------------------" << endl;
break;
}
}
if (i == num)
cout << "查询出错,无该学生编号的成绩" << endl;
}
//释放内存空间
void DeleteSpace(string*& p_Code, double*& p_MT, double*& p_EN, double*& p_PH, double*& p_TotalScore, double*& p_AvrScore, int*& p_Rank)
{
//释放指针所指的内存空间
delete[]p_Code;
delete[]p_MT;
delete[]p_EN;
delete[]p_PH;
delete[]p_TotalScore;
delete[]p_AvrScore;
delete[]p_Rank;
//将指针变量赋NULL值,以清除其无意义的地址值
p_Code = NULL;
p_MT = NULL;
p_EN = NULL;
p_PH = NULL;
p_TotalScore = NULL;
p_AvrScore = NULL;
p_Rank = NULL;
}
运行结果截图:
案例1:(正确运行结果)
案例2:(输入出错检测)
心得与体会:
- 在对程序学生成绩按照由高到低进行排序时,因考虑到学生成绩相同时,他们的成绩排名应相同。这一点在我设计时没有考虑到,而是在我进行测试时,才想到的。
- 在设计一些查询、打印相关函数时,参数无需设置为引用,这样子可以提高程序的正确性。这一点容易遗漏。
- 分数可以设置为整型,也可以设置为浮点型。就看个人如何定义分数。但是平均分不应该设置为整型,因为平均分在计算过程中可能会产生小数部分。
- 在编程过程中,由于学生编号与学生分数的变量类型不同,因此它们可能要分别设计两个函数来做某一样相同的功能,例如:两元素交换。但其实他们仅仅只是变量类型不同,函数中所执行的操作完全相同。这就用到了泛型程序设计中的函数模板!进而简化代码量,去除繁琐的代码。
- 需要设置一些差错检测,例如:录入成绩时,用户重复录入,需要提示该学生编号的成绩已录入。又如:根据学生编号进行查询成绩时,查找不到该学生编号时,需要提示“无该学生编号的成绩”。
2、不用字符串处理函数将两个字符串连接,即将字符串b连接到字符串a的后面,变成字符串c。
程序代码:
// 程序设计基础实验3 数组、结构体及指针
// 实验A 数组字符串
// 问题描述:
/*2、不用字符串处理函数将两个字符串连接,即将字符串b连接到字符串a的后面,变成字符串c。*/
#include<iostream>
#include<string>
using namespace std;
int main()
{
string a, b; //定义字符串a和字符串b以及它们对应的长度
int aSize, bSize, cSize;
a = b = " ";
cout << "请分别输入字符串a和字符串b:" << endl;
cin >> a >> b;
aSize = a.size(); //获取字符串a和b的长度,并求出字符串c的长度
bSize = b.size();
cSize = aSize + bSize;
char* p_char = NULL; //定义一个指针变量,用于指向动态字符数组
p_char = new char[cSize + 1]; //动态创建一个字符数组
if (p_char) //内存申请成功
{
//遍历字符串a中的每个字符
for (int i = 0; i < aSize; i++)
{
p_char[i] = a[i]; //将字符串a复制到字符串c的前半段
}
//遍历字符串b中的每个字符
for (int i = 0; i < bSize; i++)
{
p_char[i + aSize] = b[i]; //将字符串b复制到字符串c的后半段
}
p_char[cSize] = '\0'; //添加串结束符
cout << "将字符串b连接到字符串a的后面,变成字符串c:" << endl;
//打印字符串c
for (int i = 0; i < cSize; i++)
{
cout << p_char[i];
}
delete[]p_char; //释放p_char所指的存储空间
p_char = NULL; //将指针变量置为空,清除其无意义的地址值
}
else
{
cout << "内存申请出错" << endl;
}
return 0;
}
运行结果截图:
心得与体会:
- 在该程序中,我结合了string类型和字符数组进行编码,使得程序更加直接、简捷。
2、值得注意的是,在动态申请字符数组空间时,应该多预留一位给串结束符’\0’。
实验B结构实验
一、实验目的
1.掌握结构的概念;
2.学会通过结构成员来使用结构;
3.学会通过函数的参数使用结构;
4.学会结构变量成员值的输出。
二、实验设备与平台
1. 实验设备:计算机
2. 平台:Windows操作系统,Microsoft Visual C++或其它合适的C++编程环境。
三、实验内容
1、定义一个结构变量(包括年、月、日),计算该日在本年中为第几天?(注意考虑闰年问题),要求写一个函数days,实现上面的计算。由主函数将年月日传递给days函数,计算后将日子传递回主函数输出。
程序代码:
// 程序设计基础实验3 数组、结构体及指针
// 实验B 结构实验
// 问题描述:
/*1、定义一个结构变量(包括年、月、日),计算该日在本年中为第几天?
(注意考虑闰年问题),要求写一个函数days,实现上面的计算。
由主函数将年月日传递给days函数,计算后将日子传递回主函数输出。*/
#include<iostream>
using namespace std;
#define Month 12
struct Time
{
int year; //年份
int month; //月份
int day; //日份
};
//计算该日在本年中为第几天
int days(Time t);
//初始化
void Initial(Time& t);
//输入
void Input(Time& t);
int main()
{
Time t;
Initial(t); //初始化
Input(t); //数据输入
//计算该日在本年中为第几天
cout << t.year << "年"<<t.month<<"月" <<t.day<<"日" << "在本年中为第" << days(t) << "天" << endl;
return 0;
}
//初始化
void Initial(Time& t)
{
t.year = t.month = t.day = 0; //年月日初值均为零
}
//输入
void Input(Time& t)
{
cout << "请输入年:" << endl;
cin >> t.year;
cout << "请输入月:" << endl;
cin >> t.month;
cout << "请输入日:" << endl;
cin >> t.day;
}
//计算该日在本年中为第几天
int days(Time t)
{
int* p_Month = new int[Month]; //动态数组,存储该年的每月的天数
int daysOfYear = 0; //
if (p_Month) //内存申请成功
{
//1、3、5、7、8、10、12月均为31天
p_Month[0] = p_Month[2] = p_Month[4] = p_Month[6] = p_Month[7] = p_Month[9] = p_Month[11] = 31;
//4、6、9、11月均为30天
p_Month[3] = p_Month[5] = p_Month[8] = p_Month[10] = 30;
//判断该年是否为闰年
if ((t.year % 4 == 0 && t.year % 100 != 0) || t.year % 400 == 0) //能被4整除但不能被100整除 或 能被400整除的 为闰年
{
p_Month[1] = 29; //闰年2月有29天
}
else
{
p_Month[1] = 28; //平年2月有28天
}
//累加该日的月份之前的所有天数
for (int i = 0; i < t.month - 1; i++) //这里容易发生错误:月份-1 =数组p_Month的下标
{
daysOfYear += p_Month[i];
}
//加上该日,即为该日在本年中为第几天
daysOfYear += t.day;
}
else //内存申请失败
{
cout << "内存申请出错!" << endl;
}
delete[]p_Month; //释放指针所指内存空间
p_Month = NULL; //将指针的值置为空,清除其无意义的地址值
return daysOfYear; //返回该年的总天数
}
运行结果截图:
心得与体会:
- 在编写程序过程中,又出现了错误。出错原因:月份与程序设计中的数组下标不相等。正确的关系为:月份 - 1 = 数组p_Month的下标
2、编写一个程序,用结构表示一个学生的信息,每个学生的信息包括:学号、姓名、三门成绩。要求从键盘输入学生的数据,并输出成绩表(包括每个学生的学号、姓名、三门成绩及平均分数),并输出平均分在前3名的学生的姓名及平均分。
程序代码:
// 程序设计基础实验3 数组、结构体及指针
// 实验B 结构实验
// 问题描述:
/*2、编写一个程序,用结构表示一个学生的信息,每个学生的信息包括:学号、姓名、三门成绩。
要求从键盘输入学生的数据,
并输出成绩表(包括每个学生的学号、姓名、三门成绩及平均分数),
并输出平均分在前3名的学生的姓名及平均分。*/
#include<iostream>
#include<iomanip>
using namespace std;
struct Student
{
string code; //学生学号
string name; //学生姓名
double MT; //数学成绩
double EN; //英语成绩
double PH; //物理成绩
double TotalScore; //总分
double AvrScore; //平均分数
};
//学生信息初始化
void Initial(int num, Student*& p);
//学生信息录入
void Rigister(int num, Student*& p);
//交换函数
template<typename T>
void Swap(T& element1, T& element2);
//按总分成绩排序 冒泡排序
void BubbleSort(int num, Student*& p);
//学生成绩表打印
void DispGradesTable(int num, Student* p);
//打印平均分排名前几的学生相关数据
void DispTop(int numStudent, Student* p);
//释放内存空间
void DeleteSpace(Student*& p);
int main()
{
int numStudent;
cout << "请输入学生数量:" << endl;
cin >> numStudent;
Student* p_Student = NULL;
Initial(numStudent, p_Student); //学生信息初始化
Rigister(numStudent, p_Student); //学生信息录入
DispGradesTable(numStudent, p_Student); //学生成绩表打印
BubbleSort(numStudent, p_Student); //学生成绩排序
DispTop(numStudent, p_Student); //求平均分排在前几的学生信息
DeleteSpace(p_Student); //释放指针所指空间
return 0;
}
//学生信息初始化
void Initial(int num, Student*& p)
{
p = new Student[num]; //动态结构数组
if (p) //内存分配成功
{
//为数组赋初值
for (int i = 0; i < num; i++)
{
p[i].code = p[i].name = " ";
p[i].MT = p[i].EN = p[i].PH = p[i].TotalScore = p[i].AvrScore = 0;
}
}
else
{
cout << "内存申请出错!" << endl;
}
}
//学生信息录入
void Rigister(int num, Student*& p)
{
cout << "请依次输入每位学生的学生编号、学生姓名、数学分数、英语分数、物理分数:" << endl;
cout << "(注意:输入学生编号后使用按下回车,然后输入学生姓名和分数,姓名与分数、分数与分数之间用空格间隔)" << endl;
for (int i = 0; i < num; i++)
{
cout << "学生编号:";
cin >> p[i].code;
bool isExist = 0;
for (int j = 0; j < i; j++) //遍历已录入的成绩表
{
if (p[i].code == p[j].code) //当前输入的学生编号已存在于信息表中
{
isExist = 1;
cout << "该学生编号的成绩已录入,无需再次录入" << endl;
i--;
cout << "请继续录用下一个学生的成绩" << endl;
break;
}
}
if (!isExist) //该学生编号不存在信息表中时,继续录用
{
cout << "学生姓名:";
cin >> p[i].name;
cout << "数学成绩、英语成绩、物理成绩:";
cin >> p[i].MT >> p[i].EN >> p[i].PH; //输入该学生的相关数据
p[i].TotalScore = p[i].MT + p[i].EN + p[i].PH; //计算该学生的总分
p[i].AvrScore = p[i].TotalScore / 3.0; //计算该学生的平均分
}
}
}
//学生成绩表打印
void DispGradesTable(int num, Student* p)
{
cout << "-------------------------------------------学生成绩表打印-------------------------------------------" << endl;
cout << "学生编号" << '\t' << "学生姓名" << '\t' << "数学成绩" << '\t' << "英语成绩" << '\t' << "物理成绩" << '\t' << "平均分 " << endl;
for (int i = 0; i < num; i++)
{
cout << p[i].code << '\t' << '\t' << p[i].name << '\t' << '\t' << p[i].MT << '\t' << '\t' << p[i].EN << '\t' << '\t' << p[i].PH
<< '\t' << '\t' << setprecision(4) << p[i].AvrScore << endl;
}
cout << "------------------------------------------学生成绩表分割线------------------------------------------" << endl;
}
//打印平均分排名前几的学生相关数据
void DispTop(int numStudent, Student* p)
{
int n = 0;
cout << "请输入需要打印前几名的学生信息:" << endl;
cin >> n;
//判断总学生数是大于需要求的排名前几的学生
if (n > numStudent) //学生数较少时,只能打印出所有学生的信息
{
cout << "仅有" << numStudent << "名学生,只能打印出排名前" << numStudent << "的学生信息" << endl;
cout << "---------------------------------------排名前" << numStudent << "的学生信息打印--------------------------------------- " << endl;
cout << "学生姓名" << '\t' << "平均分 " << endl;
for (int i = 0; i < numStudent; i++)
{
cout << p[i].name << '\t' << '\t' << fixed << setprecision(2) << p[i].AvrScore << endl;
}
}
else //学生数较多时,可以打印出所需的前几的学生的信息
{
cout << "---------------------------------------排名前" << n << "的学生信息打印--------------------------------------- " << endl;
cout << "学生姓名" << '\t' << "平均分 " << endl;
for (int i = 0; i < n; i++)
{
cout << p[i].name << '\t' << '\t' << fixed << setprecision(2) << p[i].AvrScore << endl;
}
}
cout << "-----------------------------------------------分割线-----------------------------------------------" << endl;
}
//交换函数:函数模板
template<typename T>
void Swap(T& element1, T& element2)
{
T temp;
temp = element1;
element1 = element2;
element2 = temp;
}
//按总分成绩排序 冒泡排序
void BubbleSort(int num, Student*& p)
{
int i, j;
bool exchange;
for (i = 0; i < num - 1; i++)
{
exchange = false; //判别因子
for (j = num - 1; j > i; j--)
if (p[j].TotalScore > p[j - 1].TotalScore) //相邻元素反序时
{
Swap(p[j].code, p[j - 1].code); //将学生编号中的两元素交换
Swap(p[j].name, p[j - 1].name); //将学生姓名中的两元素交换
Swap(p[j].TotalScore, p[j - 1].TotalScore); //将总分中的两元素交换
Swap(p[j].AvrScore, p[j - 1].AvrScore); //将平均分中的两元素交换
Swap(p[j].MT, p[j - 1].MT); //将数学分数中的两元素交换
Swap(p[j].EN, p[j - 1].EN); //将英语分数中的两元素交换
Swap(p[j].PH, p[j - 1].PH); //将物理分数中的两元素交换
exchange = true;
}
if (!exchange) //本趟没有发生交换,结束算法
break;
}
}
//释放内存空间
void DeleteSpace(Student*& p)
{
delete[]p; //释放指针所指的内存空间
p = NULL; //将指针变量赋NULL值,以清除其无意义的地址值
}
运行结果截图:
案例1:(正确运行结果)
案例2:(输入出错检测)
心得与体会:
- 该题目与本实验中的实验A第一题相似,第一题我用了很多个数组的方式,分别存储学生编号、学生姓名、学生成绩。而本题中采用结构体,极大提高了编码的扩展性。当需要添加多一个科目的成绩时,我不再需要添加一个该科目成绩的数组,而只需在结构体中添加多一个属性。
- 题目中隐含了一个条件,当班级学生只有2名时,查询平均分前三的同学信息时,应只输出2名,而无法输出3名。这是在编程中容易搞错的、忽略的。
- 在编写录入学生信息的函数时,没有使用结构指针的引用。这导致数据没有办法录入。所以在一些需要更改、写入操作的函数编写时,需要注意参数是否设置为引用。
实验C 指针实验
一、实验目的
1.掌握指针的概念;
2.学会通过指针处理普通变量和一维数组;
3.学会通过指针处理动态分配的内存;
4.学会将一个问题提炼出数学模型,学会利用数学模型编写程序的方法。
二、实验设备与平台
1. 实验设备:计算机
2. 平台:Windows操作系统,Microsoft Visual C++或其它合适的C++编程环境。
三、实验内容
1、 要求使用指针处理下面的问题,输入四个整数,按由小到大的顺序输出;然后将程序改为:输入四个字符串,按由小到大顺序输出。(使用指针或指针数组)
程序代码:
// 程序设计基础实验3 数组、结构体及指针
// 实验C 指针实验
// 问题描述:
/*1、要求使用指针处理下面的问题,输入四个整数,按由小到大的顺序输出;
然后将程序改为:输入四个字符串,按由小到大顺序输出。(使用指针或指针数组)*/
#include <iostream>
using namespace std;
#define N 4 //定义需要输入的个数
//数据输入
template<typename T>
void input(int num, T* p);
//元素交换
template<typename T>
void Swap(T& element1, T& element2);
// 对整数数组进行排序
void BubbleSort_Int(int num, int* p);
// 对字符串数组进行排序
void BubbleSort_string(int num, string* p);
//排序结果打印
template<typename T>
void Disp(int num, T* p);
int main()
{
int* p_Int = new int[N];
string* p_String = new string[N];
if (p_Int && p_String) //内存申请成功
{
//整数输入
cout << "请输入需要排序的" << N << "个整数:" << endl;
input(N, p_Int);
//字符串输入
cout << "请输入需要排序的" << N << "个字符串:" << endl;
input(N, p_String);
//排序
BubbleSort_Int(N, p_Int);
BubbleSort_string(N, p_String);
//打印由小到大排序后的结果
cout << N << "个整数由小到大排序后的结果为:" << endl;
Disp(N, p_Int);
cout << N << "个字符串由小到大排序后的结果为:" << endl;
Disp(N, p_String);
delete[]p_Int; //释放指针所指的空间
delete[]p_String;
p_Int = NULL; //将指针置为空,清除其无意义的地址值
p_String = NULL;
}
else //内存申请失败
{
cout << "内存申请出错!" << endl;
}
return 0;
}
//数据输入
template<typename T>
void input(int num, T* p)
{
for (int i = 0; i < N; i++)
{
cin >> p[i];
}
}
//元素交换
template<typename T>
void Swap(T& element1, T& element2)
{
T temp = element1;
element1 = element2;
element2 = temp;
}
// 对整数数组进行排序小到大排序 传入一个指针参数,并通过指针(间址)运算来操作
void BubbleSort_Int(int num, int* p)
{
int i, j;
bool exchange;
for (i = 0; i < num - 1; i++)
{
exchange = false; //判别因子
for (j = num - 1; j > i; j--)
{
if (*(p+j - 1) > *(p+j)) //相邻元素反序时
{
Swap(*(p + j - 1), *(p + j)); //将这两个元素进行交换
exchange = true;
}
}
if (!exchange) //本趟没有发生交换,结束排序算法
break;
}
}
// 对字符串数组进行排序小到大排序
void BubbleSort_string(int num, string* p)
{
int i, j;
bool exchange;
for (i = 0; i < num - 1; i++)
{
exchange = false; //判别因子
for (j = num - 1; j > i; j--)
{
if ((*(p + j - 1)).size() > (*(p + j)).size()) //相邻字符串长度反序时
{
Swap(*(p + j - 1), *(p + j)); //将这两个元素进行交换
exchange = true;
}
}
if (!exchange) //本趟没有发生交换,结束排序算法
break;
}
}
//排序结果打印
template<typename T>
void Disp(int num, T* p)
{
for (int i = 0; i < N; i++)
{
cout << p[i] << " ";
}
cout << endl;
}
运行结果截图:
心得与体会:
- 在平时写代码中,我较少地用到间址操作,而是用数组形式来写入数据、修改数据。在本次题目中,我在冒泡排序中用指针的间址操作来写,一开始还有点不习惯,但其实就是通过首地址加上移动单位,再添加间址运算符*。
- 在设计代码过程中,我发现整数排序和字符串排序,它们的排序算法略微不同。整数排序中,我们仅需要比较两元素的大小,而在字符串排序中,我们需要比较两字符串的长度。
- 我利用泛化程序设计中的函数模板来写整数、字符串的写入和排序结果的打印。这样子大大减少了代码量,增强了程序的扩展性。
2、 通过指针和动态存储处理下面的问题:利用随机函数模拟产生300个1~12月出生的人数,统计本次运行得到的数据中,各个月的出生率是多少。
程序代码:
// 程序设计基础实验3 数组、结构体及指针
// 实验C 指针实验
// 问题描述:
/*2、通过指针和动态存储处理下面的问题:利用随机函数模拟产生300个1~12月出生的人数,
统计本次运行得到的数据中,各个月的出生率是多少。*/
#include<iostream>
#include<stdlib.h> // 包含两个头文件,用于设置随机数
#include<time.h>
#include<iomanip> //用于格式控制的头文件
using namespace std;
int main()
{
int* p_birthMonth = new int[12]; //动态分配一个包含12个整数的数组,用于存储每个月的出生人数
srand(time(nullptr)); // 设置随机数种子
//数组初始化
for (int i = 0; i < 12; i++)
{
p_birthMonth[i] = 0; //初始化每月出生人口为零
}
//模拟生成300个1~12月出生的人数
for (int i = 0; i < 300; i++)
{
int birthMonth = 1 + rand() % (12 - 1 + 1); //产生一个1~12之间的随机数,表示出生月份
p_birthMonth[birthMonth - 1]++; //对应月份的出生人口+1 注意:这里容易发生出错,月份为1存储于下标为0元素中
}
//计算各个月份的出生率
for (int i = 0; i < 12; i++)
{
double birthMonthRate = (p_birthMonth[i] / 300.0) * 100; //计算出生率
cout << i + 1 << "月份的出生率为:" <<fixed << setprecision(2) << birthMonthRate << "%" << endl; //打印出生率结果
}
delete[]p_birthMonth; //释放动态分配的内存
p_birthMonth = NULL; //将指针变量置为空,清除其无意义的地址值
return 0;
}
运行结果截图:
心得与体会:
1、在使用数组时,要把握好数组下标与某个变量之间的关系。例如,在本题中,数组下标与月份的关系为:下标 = 月份-1。这是在写程序中容易出错的。