- 论坛徽章:
- 0
|
第二部分,函数
5.4.3 工资程序成长记:函数
自从上次小陈的工资程序得到老板的夸奖,口头许诺给他涨工资以后,老板再也没有找过他,涨工资的事自然再也没有下文了。这天,老板又找他去办公室。这下可把小陈高兴坏了,心想终于要给我涨工资了。于是赶紧到了老板的办公室,可刚进老板办公室,就发现情况有点不对,只见老板阴沉着脸坐在他那张硕大的老板椅上,手指还在不同地敲击着键盘。一见到小陈进来,就好像见到仇人似的,劈头盖脸地来了一句:
“小陈啊,你这个工资程序怎么搞得,怎么每次都要重新输入工资数据啊?你是不是想累死我啊?”
老板的话如同一个晴天霹雳,小陈差点没晕过去,心想,这下涨工资的事情泡汤了。听老板这一抱怨,他才想起来原来的工资程序没法读取现有的工资数据,也无法将已经输入的工资数据保存成文件以备下次使用。所以每次使用都要重新输入全部数据。小陈想想那成千上万的工资数据,心中暗想,这都没把这个可恶的老板累死,真是算他走运了。不过转念又想,他死了谁给我涨工资啊?于是,赶紧解释说:
“老板,这可能是工资程序存在的一个Bug。您也是知道的,程序中的Bug是在所难免的。让我回去修改修改,马上就好。”
就这样,小陈没有听到涨工资的好消息,去领了一个有问题的工资程序回来修改。好在他这几周还算勤快,在C++方面也进步了不少,他已经学到了函数,懂得了对一个问题“自顶向下、逐步求精”地进行分析,划分模块并用C++的函数加以解决。所以,对于最终解决这个问题,他还是很有信心的。
拿到问题后,小陈对这个问题进行了简单的分析。整体而言,这是一个典型的对数据进行处理的程序,它主要可以分为数据输入、数据处理和数据输出三个比较大的模块,而为了避免每次都输入数据,数据输入模块又可以细分成手工输入和文件读入,而数据输出部分,除了屏幕显示结果之外,相应地还应该包括将工资数据输出到文件。在最重要的数据处理模块,为了保证函数的职责单一而明确,需要将原来混杂在数据输入时进行的最大值最小值以及平均值的计算,移到数据处理模块中成为独立的子模块。经过这样的简单分析,小陈很快地画出了工资程序的模块图 :
有了程序的模块图,我们只要用函数实现每个模块,然后在主函数中对各个子模块加以调用,就解决整个问题了。很快,在模块图的指导下,小陈很快就用函数实现了每个模块,完成了新的工资程序:
// 工资程序V2
#include <iostream>
// 文件流对象头文件
#include <fstream>
using namespace std;
// 全局的工资数据文件名,使用一个不可修改的常量字符串表示
const string strFileName = "SalaryData.txt";
// 从数据文件读取工资数据
int Read(int* nSalary, int nCount)
{
// 读取过程中的临时变量
int n = 0; // 读取值
int i = 0; // 当前工资序号
// 打开工资数据文件SalaryData.txt用于读入数据
ifstream in(strFileName);
if(in.is_open()) // 如果成功打开文件
{
// 构造一个无限循环读取文件中的数据,
// 按行读取的数据保存到变量n
while(in>>n)
{
// 如果读取的数据个数大于数组的容量,则结束读取
if(i>=nCount)
break;
// 将读取的内容保存到数组
nSalary[i] = n;
++i; // 开始下一次读取
}
// 读取完毕,关闭文件
in.close();
}
// 输出读取结果,返回读取的数据个数
cout<<"读取"<<i<<"个工资数据"<<endl;
return i;
}
// 将工资数据写入数据文件
void Write(int* nSalary, int nCount)
{
// 打开工资数据文件SalaryData.txt用于输出
ofstream o(strFileName);
if(o.is_open()) // 如果成功打开文件
{
// 利用for循环,将数组中的数据输出到文件
for(int i = 0;i < nCount;++i)
{
o<<nSalary[i]<<endl;
}
// 输出完毕,关闭文件
o.close();
}
}
// 获取数组中的最大值
int GetMax(int* nSalary, int nCount)
{
int nMax = INT_MIN;
// 利用for循环遍历数组中所有数据元素
for(int i = 0;i < nCount; ++i)
{
if(nSalary[i]>nMax)
nMax = nSalary[i];
}
return nMax;
}
// 获取数组中的最小值
int GetMin(int* nSalary, int nCount)
{
int nMin = INT_MAX;
for(int i = 0;i < nCount; ++i)
{
if(nSalary[i]<nMin)
nMin = nSalary[i];
}
return nMin;
}
// 计算数组数据的平均值
float GetAver(int* nSalary, int nCount)
{
// 计算总和
int nTotal = 0;
for(int i = 0;i < nCount; ++i)
{
nTotal += nSalary[i];
}
// 计算平均值并返回
if(0!=nCount)
return (float)nTotal/nCount;
else
return 0.0f; // 特殊情况返回0
}
// 手工输入数据
int Input(int* nSalary,int nMax,int nCount)
{
// 用数组中已有数据数量作为输入的起点
int i = nCount;
for(; i < nMax; ++i) // 初始化语句留空
{
// 提示输入
cout<<"请输入"<<i<<"号员工的工资(-1表示输入结束):"<<endl;
// 将输入的数据保存到数组的nSalary[i]数据元素
int n = 0;
cin>>n;
// 检查输入是否合法
if(cin)
{
nSalary[i] = n;
}
else// 如果输入不合法,例如输入了英文字符,则提示用户重新输入
{
cout<<"输入错误,请重新输入"<<endl;
// 清理cin的输入标志位以重新输入
cin.clear();
// 清空输入缓冲区
cin.sync();
--i; // 将输入序号退后一个
continue; // 开始下一次循环
}
// 检查是否输入结束
if(-1 == nSalary[i])
{
break;
}
}
// 返回当前数组中共有的数据个数
return i;
}
// 查询工资数据
void Find(int* nSalary,int nCount)
{
while(true) // 构造无限循环进行查询
{
int n = 0;
// 输入提示
cout<<"请输入要查询的员工序号(0-"<<nCount-1
<<",-1表示结束查询):"<<endl;
// 获取用户输入的员工序号并保存到n
cin>>n;
// 对用户输入进行检查
if(!cin) // 如果用户输入不合法,例如输入了英文字符
{
cout<<"输入错误,请重新输入"<<endl;
// 清理cin的输入标志位以重新输入
cin.clear();
// 清空输入缓冲区
cin.sync();
continue; // 开始下一次查询
}
else if(-1 == n) // 检查是否结束
{
// 查询结束,用break结束循环
cout<<"查询完毕,感谢使用!"<<endl;
break;
}
else if(n<0||n>=nCount) // 检查输入是否超出序号范围
{
// 输入超出范围,用continue开始下一次循环
cout<<"输入的序号"<<n<<"超出了序号范围0-"
<<nCount-1<<",请重新输入。"<<endl;
// 开始下一次查询
continue;
}
// 输入合法,输出用户查询的员工工资
cout<<"员工序号:"<<n<<endl;
cout<<"员工工资:"<<nSalary[n]<<endl;
}
}
int _tmain(int argc, TCHAR* argv[])
{
// 定义保存员工数据的超大数组
const int MAX = 100000;
int nSalary[MAX];
// 从数据文件读取数据
int nCount = Read(nSalary,MAX);
// 用手工输入工资数据
nCount = Input(nSalary,MAX,nCount);
// 对输入的工资数据进行统计
cout<<"输入完毕。一共有"<<nCount<<"个工资数据"<<endl;
cout<<"最大值:"<<GetMax(nSalary,nCount)<<endl;
cout<<"最小值:"<<GetMin(nSalary,nCount)<<endl;
cout<<"平均值:"<<GetAver(nSalary,nCount)<<endl;
// 对工资数据进行查询
Find(nSalary,nCount);
// 将工资数据写入数据文件
Write(nSalary,nCount);
return 0;
}
经过函数改写后的工资程序,结构分明、思路清晰,分别利用各个函数实现了一个大问题所分解的各个模块,最终解决了这个大问题。当小陈将这个改写后的程序拿给老板用过之后,老板笑得合不拢嘴,一直夸奖说:
“不错不错,现在的程序不仅可以将输入的数据保存下来,下次可以接着用,再也不用我每次都重新输入了。还对用户的输入进行了很好的检查,防止了错误的发生。干的不错,下个月,涨工资,啊哈哈哈……”
老板的一句“涨工资”,又让小陈燃起了希望,心中想,这次的改写,让我见识了函数将一个大问题分解成多个小问题,然后各个击破的这种“大事化小,小事化了”解决问题的威力。C++真是个好东西,只要自己好好学,一定能够涨工资。
|
|