MOOC清华《程序设计基础》第9章:自动售卖程序 v 2.0

txt配置文件:

5
苹果=3.5
香蕉=2.7
梨子=2.3
葡萄=3.3
橘子=1.8

我对照视频手打并debug的源代码:(保留了前几版和测试的痕迹)

//可以一边分析一边设计一边写代码
//先考虑整体框架,再考虑细节,称为“自顶向下,逐步求精” 

#include <iostream>
#include <fstream>
#include <cstdlib>
#include <cmath>
#include <iomanip>
#include <cstring>
using namespace std;

struct Fruit_t
{
	char name[20];
	double price;
};

bool GetFruits(Fruit_t* &fruits, int &fruit_number)
{
	ifstream fin("fruits.txt");
	if(!fin)  //如果txt文件损坏、打不开 
		return false;
	fin >> fruit_number;
	//test statements:测试证明文件是可以打开的,而且可以读入第一行的数字 
	//cout << fruit_number;
	fin >> ws;  //ws是whitespace的缩写,cin语句也可以这样用,跳过后面的回车空格制表符 
	fruits = new Fruit_t[fruit_number];
	for(int i = 0; i < fruit_number; i++)
	{
		char buffer[100];  //buffer是缓冲区的意思 
		fin.getline(buffer, 100);
		char* p = strchr(buffer, '=');  //strchr()函数的功能是在字符串中查找一个字符 
		*p = '\0';
		strcpy(fruits[i].name, buffer);
		//test statements:测试结果发现,bug原因是txt配置文件出了问题!明明是5种水果,第一行却是数字6 
		//cout << fruits[i].name << endl;
		fruits[i].price = atof(p + 1);
	}
	fin.close();  //debug记录:出错的原因是这一行写到for循环体内部去了,千万注意 
	return true;
}//注意GetFruits()函数一定要放到其他函数的前面来,否则文件的数据都没读出来,后面没法操作 

void ShowMenu()
{
	cout << "****************************************" << endl;
	cout << "* 欢迎使用自动售卖机,请输入您的选择。 *" << endl;
	cout << "* 1.  下订单                           *" << endl;
	cout << "* 2.  退出自动售卖                     *" << endl;
	cout << "****************************************" << endl;
}

void ShowSubMenu(Fruit_t* fruits, int fruit_number)
{
	cout << "++++++++++++++++++++++++++++++++++++++++" << endl;
	cout << "+ 开始处理订单,请输入您的选择。       +" << endl;
	for(int i = 0; i < fruit_number; i++)
	{
		cout << "+" << setw(2) << i + 1 << ".  购买";
		cout << fruits[i].name << "(" << fixed << setw(5) << setprecision(2) << fruits[i].price << "元/公斤)";
		int len = strlen(fruits[i].name);
		for(int j = 0; j < 13 - len; j++)
			cout << ' ';
		cout << "+" << endl; 
	}
	//cout << "+ x.  购买苹果(3.5元/公斤)           +" << endl;
	//cout << "+ x.  购买香蕉(2.7元/公斤)           +" << endl;
	cout << "+" << setw(2) << fruit_number + 1 << ".  结账                             +" << endl;
	cout << "+" << setw(2) << fruit_number + 2 << ".  放弃购买                         +" << endl;
	cout << "++++++++++++++++++++++++++++++++++++++++" << endl;
}//苹果是北方水果,香蕉是南方水果,所以北京那边香蕉比苹果贵,但在武汉苹果比香蕉贵
//子菜单的花边框用+组成,区别于主菜单的*边框 

int GetInteger()
{
	char buf[100] = {0};
	while(strlen(buf) == 0)  //用户直接输入回车 
		cin.getline(buf, 100);
	return atoi(buf);  //atoi函数是cstring头文件自带的 
}

double GetDouble()
{
	char buf[100] = {0};
	while(strlen(buf) == 0)  //用户直接输入回车
		cin.getline(buf, 100);
	return atof(buf);  //atof函数也是cstring头文件自带的 
}

void DealOrder(Fruit_t* fruits, int fruit_number)
{
	//double apple_price = 3.5;
	//double apple_weight = 0;
	//double banana_price = 2.7;
	//double banana_weight = 0;
	double sum = 0;  //需严格注意变量的作用域 
	double* weight = new double[fruit_number];
	for(int i = 0; i < fruit_number; i++)
		weight[i] = 0;
	while(1)
	{
		//显示子菜单 
		ShowSubMenu(fruits, fruit_number);
		//todo:显示已买水果总价
		cout << "已购买水果总价: " << fixed << setprecision(2) << setw(8) << sum << "元" << endl; 
		cout << "您的选择是:";
		int input;
		//cin >> input;
		input = GetInteger();
		if(input > 0 && input <= fruit_number)
		{
			cout << "请输入称重(公斤):";
			double w = GetDouble();
			sum += fruits[input - 1].price * w;
			weight[input - 1] += w;
		}
		if(input == fruit_number + 1)
		{
			if(sum > 1E-6)  //确实买了水果 
			{
				cout << "您一共购买了";
				for(int i = 0; i < fruit_number; i++)
					if(fabs(weight[i]) > 1E-6)
						cout << weight[i] << "公斤" << fruits[i].name << ",";
				cout << "总价是" << sum << "元" << endl;
				system("pause");
			}
			break;
		}
		if(input == fruit_number + 2)
			break;
		/*
		switch(input)
		{
			case 1:
				//todo:处理买苹果
				cout << "请输入称重(公斤):";
				//cin >> weight;
				weight = GetDouble();
				sum += apple_price * weight; //注意分清weight和apple_weight 
				apple_weight += weight;
				break;
			case 2:
				//todo:处理买香蕉
				cout << "请输入称重(公斤):";
				//cin >> weight;
				weight = GetDouble();
				sum += banana_price * weight;
				banana_weight += weight;
				break;
			case 3:
				//todo:显示总价
				//cout << "已购买水果总价:" << fixed << setprecision(2) << setw(8) << sum << "元" << endl;
				if(sum > 1E-6)
				{
					cout << "您一共购买了";
					if(fabs(apple_weight) > 1E-6)  
					//加绝对值的原因是允许“买了苹果后嫌买多了又退几个”的情况 
						cout << apple_weight << "公斤苹果,";
					if(fabs(banana_weight) > 1E-6)  
					//加绝对值原因同上,退货的时候也要称重,所以存在负数,总重可能略小于0 
						cout << banana_weight << "公斤香蕉,";
					cout << "总价是" << sum << "元" << endl;
					//核心技巧:前面已经对sum作了输出流格式控制,然后所有跟sum发生计算关系的变量
					//都统一成了与sum相同的输出流格式,所以这里就不必再加格式控制符了 
					system("pause");
				}
			case 4:
				system("cls");
				return; 
		}
		*/
	}
	delete []weight;
	system("cls");
}

int main()
{
	Fruit_t* fruits = NULL;
	int fruit_number;
	//test statements:不加这一句也行 
	//GetFruits(fruits, fruit_number);
	if(!GetFruits(fruits, fruit_number))
	{
		cout << "配置文件错误!" << endl;
		return 0;
	}
	//测试代码:测试结果显示文件并没有完全读入结构体数组,说明GetFruits()函数有问题 
	//测试GetFruit()后发现:bug原因是txt配置文件出了问题!明明是5种水果,第一行却是数字6 
	//修改txt配置文件后,一切正常!所以:txt配置文件的容错性很低,有待修改! 
	//for(int i = 0; i < fruit_number; i++)
	//	cout << fruits[i].name << '=' << fruits[i].price << endl; 
	while(1)
	{
		ShowMenu();
		cout << "您的选择是:";
		int input;
		//cin >> input;
		input = GetInteger();
		switch(input)
		{
			case 1:
				DealOrder(fruits, fruit_number);
				break;
			case 2:
				delete []fruits;
				return 0;
		}
	}
}

经过删除多余注释和测试代码后的最终源代码:

//可以一边分析一边设计一边写代码
//先考虑整体框架,再考虑细节,称为“自顶向下,逐步求精” 

#include <iostream>
#include <fstream>
#include <cstdlib>
#include <cmath>
#include <iomanip>
#include <cstring>
using namespace std;

struct Fruit_t
{
	char name[20];
	double price;
};

bool GetFruits(Fruit_t* &fruits, int &fruit_number)
{
	ifstream fin("fruits.txt");
	if(!fin)  //如果txt文件损坏、打不开 
		return false;
	fin >> fruit_number;
	fin >> ws;  //ws是whitespace的缩写,cin语句也可以这样用,跳过后面的回车空格制表符 
	fruits = new Fruit_t[fruit_number];
	for(int i = 0; i < fruit_number; i++)
	{
		char buffer[100];  //buffer是缓冲区的意思 
		fin.getline(buffer, 100);
		char* p = strchr(buffer, '=');  //strchr()函数的功能是在字符串中查找一个字符 
		*p = '\0';
		strcpy(fruits[i].name, buffer);
		fruits[i].price = atof(p + 1);
	}
	fin.close();  //debug记录:出错的原因是这一行写到for循环体内部去了,千万注意 
	return true;
}//注意GetFruits()函数一定要放到其他函数的前面来,否则文件的数据都没读出来,后面没法操作 

void ShowMenu()
{
	cout << "****************************************" << endl;
	cout << "* 欢迎使用自动售卖机,请输入您的选择。 *" << endl;
	cout << "* 1.  下订单                           *" << endl;
	cout << "* 2.  退出自动售卖                     *" << endl;
	cout << "****************************************" << endl;
}

void ShowSubMenu(Fruit_t* fruits, int fruit_number)
{
	cout << "++++++++++++++++++++++++++++++++++++++++" << endl;
	cout << "+ 开始处理订单,请输入您的选择。       +" << endl;
	for(int i = 0; i < fruit_number; i++)
	{
		cout << "+" << setw(2) << i + 1 << ".  购买";
		cout << fruits[i].name << "(" << fixed << setw(5) << setprecision(2) << fruits[i].price << "元/公斤)";
		int len = strlen(fruits[i].name);
		for(int j = 0; j < 13 - len; j++)
			cout << ' ';
		cout << "+" << endl; 
	}
	cout << "+" << setw(2) << fruit_number + 1 << ".  结账                             +" << endl;
	cout << "+" << setw(2) << fruit_number + 2 << ".  放弃购买                         +" << endl;
	cout << "++++++++++++++++++++++++++++++++++++++++" << endl;
}//苹果是北方水果,香蕉是南方水果,所以北京那边香蕉比苹果贵,但在武汉苹果比香蕉贵
//子菜单的花边框用+组成,区别于主菜单的*边框 

int GetInteger()
{
	char buf[100] = {0};
	while(strlen(buf) == 0)  //用户直接输入回车 
		cin.getline(buf, 100);
	return atoi(buf);  //atoi函数是cstring头文件自带的 
}

double GetDouble()
{
	char buf[100] = {0};
	while(strlen(buf) == 0)  //用户直接输入回车
		cin.getline(buf, 100);
	return atof(buf);  //atof函数也是cstring头文件自带的 
}

void DealOrder(Fruit_t* fruits, int fruit_number)
{
	double sum = 0;  //需严格注意变量的作用域 
	double* weight = new double[fruit_number];
	for(int i = 0; i < fruit_number; i++)
		weight[i] = 0;
	while(1)
	{
		//显示子菜单 
		ShowSubMenu(fruits, fruit_number);
		//todo:显示已买水果总价
		cout << "已购买水果总价: " << fixed << setprecision(2) << setw(8) << sum << "元" << endl; 
		cout << "您的选择是:";
		int input;
		input = GetInteger();
		if(input > 0 && input <= fruit_number)
		{
			cout << "请输入称重(公斤):";
			double w = GetDouble();
			sum += fruits[input - 1].price * w;
			weight[input - 1] += w;
		}
		if(input == fruit_number + 1)
		{
			if(sum > 1E-6)  //确实买了水果 
			{
				cout << "您一共购买了";
				for(int i = 0; i < fruit_number; i++)
					if(fabs(weight[i]) > 1E-6)
						cout << weight[i] << "公斤" << fruits[i].name << ",";
				cout << "总价是" << sum << "元" << endl;
				system("pause");
			}
			break;
		}
		if(input == fruit_number + 2)
			break;
	}
	delete []weight;
	system("cls");
}

int main()
{
	Fruit_t* fruits = NULL;
	int fruit_number;
	if(!GetFruits(fruits, fruit_number))
	{
		cout << "配置文件错误!" << endl;
		return 0;
	}
	while(1)
	{
		ShowMenu();
		cout << "您的选择是:";
		int input;
		//cin >> input;
		input = GetInteger();
		switch(input)
		{
			case 1:
				DealOrder(fruits, fruit_number);
				break;
			case 2:
				delete []fruits;
				return 0;
		}
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值