是尚硅谷的C++第一季的项目,我跟着敲下来了,发现几个坑点,记录下来;
有这个则只require once
#pragram once
关键数据结构
Struct AccountItem{
string itemType;
int amount;
string detail;
}
关键方法:C++ 读取文件的四种方式
ref:https://blog.csdn.net/weixin_62210536/article/details/127248352
ifstream input(FILENAME); 是基于运算符自身的性质,会将一切空格当作终止条件,这样的话就无法输出空格信息,采用这种方法会将一行信息进行分段读出,对于类对象的信息读取是很有用的。
// 读取文件
void loadDataFromFile(vector& items){
ifstream input(FILENAME);
// 遇见空格 /t 等就断开
AccountItem item;
while (input >> item.itemType && input >> item.amount && input >> item.detail){
items.push_back(item);
}
input.close();
}
// 写入文件
// 讲一条账目写入文件
void insertItemIntoFile(AccountItem item){
// 如果没有文件,那么生成空文件;如果有文件,那么在文件尾追加。
ofstream output(FILENAME, ios::out | ios::app);
output << item.itemType << "\t" << item.amount << "\t" << item.detail << endl;
output.close();
}
ifstream 和ofstream 是两个标准库;
读入数据:返回int
// 读取键盘输入的金额数
int readAmount()
{
int amount;
string str;
while(true){
getline(cin, str);
try{
amount = stoi(str);
break;
}catch(invalid_argument e){
cout << "输入错误,请正确输入数字:";
}
}
return amount;
}
读入数据:返回char
char readQuitConfirm(){
string str;
while (true)
{
getline(cin, str);
if(str.size()!=1||toupper(str[0])!='Y' && toupper(str[0]) != 'N')
cout << "请输入 Y 或者 N";
else
break;
}
return toupper(str[0]);
}
// ------------1. 记账操作------------//
void accounting(vector &items){
switch (readMenuSelection(3))
{
case '1':
income(items);
break;
case '2':
expand(items);
break;
default:
break;
}
}
所有的AccountItem的Vector结构体都要引用传值,是因为在输出记账record的时候,没有读取文件,而是直接变量的vector实现的。
C++ 只能引入头文件(.h文件),而不能引用.cpp文件,所以.cpp 文件只有一个。
g++ demo.cpp xx1.cpp xx2.cpp xx3.cpp -o demo
会生成一个 demo.exe 的文件 头文件在demo.cpp 中包含并定义,N多方法在 xx1.cpp, xx2.cpp, xx3.cpp中实现。这一点坑了我很长时间。
另外一个方式可以 把函数直接定义和实现在 common.h account_item.h 中。
这个很难总结,自己体会把。
···
cin>>str;
getline(cin, str);
的区别, 第一个 不带 空格,断行
第二个带空格断行,
···
会给下一个等待键盘输入的方法,放入 \n, 很不友好,建议使用 getline(cin, str)
这个函数原来用的第一种方式,造成 item.detail 收到了 断行
我用vscode 编码的, 写入的数据 中午是乱码,但是piple走通了。
git地址:https://github.com/justinge/cpp_xiaogu
全体代码也贴一下:
#include
#include
#include
#include
#define FILENAME "./account_items.txt"
#define INCOME "收入"
#define EXPAND "支出"
using namespace std;
struct AccountItem{
string itemType;
int amount;
string detail;
};
void showMainMenu();
char readMenuSelection(int options);
char readQuitConfirm();
void showAccountingMenu();
void showQueryMenu();
void income(vector &items);
void expand(vector &items);
void accounting(vector &items);
void query(vector &items);
void loadDataFromFile(vector &items);
int main(){
cout << "justin 盖建明" << endl;
vector items;
loadDataFromFile(items);
bool quit = false;
while(!quit){
showMainMenu();
char key = readMenuSelection(3);
switch (key)
{
case '1': // 1.记账
/* code */
showAccountingMenu();
accounting(items);
break;
case '2': // 查看账单
showQueryMenu();
query(items);
break;
case '3':
cout << "\n确认要退出:Y是,N不是(Y/N): ";
if (readQuitConfirm()=='Y'){
quit = true;
}
break;
default:
break;
}
}
return 1;
}
void showMainMenu(){
cout << "主菜单" < options){
cout << "请输入所需要的菜单错误!";
}else{
break;
}
}
return str[0];
}
char readQuitConfirm(){
string str;
while(true){
cin>>str;
if (str.size()!=1 || toupper((str[0]) != 'Y' && toupper(str[0])!= 'N')){
cout << "请输入:Y or N!" << endl;
}else{
break;
}
}
return str[0];
}
void showAccountingMenu(){
cout << "-------------------------------------------------------" << endl;
cout << "|=============== 选择记账种类 ====================|" << endl;
cout << "| |" << endl;
cout << "|*************** 1 收 入 ********************|" << endl;
cout << "|*************** 2 支 出 ********************|" << endl;
cout << "|*************** 3 返回主菜单 ********************|" << endl;
cout << "|_____________________________________________________|" << endl;
cout << "\n请选择(1 - 3):";
}
void accounting(vector &items){
char key = readMenuSelection(3);
switch (key)
{
case '1':
income(items);
break;
case '2':
expand(items);
break;
default:
break;
}
}
void insertItemIntoFile(AccountItem item){
ofstream output(FILENAME, ios::out | ios::app);
output << item.itemType << "\t" << item.amount << "\t" << item.detail << endl;
output.close();
}
int readAmount(){
string str;
int amount;
while(true){
getline(cin, str);
try{
amount = stoi(str);
break;
}catch(invalid_argument e){
cout << "输入错误,请正确输入数字:" << endl;
}
}
return amount;
}
void income(vector &items){
AccountItem item;
item.itemType = INCOME;
cout << "请输入金额:";
item.amount = readAmount();
cout << "\n备注:";
getline(cin,item.detail);
items.push_back(item);
insertItemIntoFile(item);
// 显示成功信息
cout << "\n------------------------记账成功!--------------------------\n" << endl;
cout << "\n请按回车键返回主菜单..." << endl;
string line;
getline(cin, line);
}
void expand(vector &items){
AccountItem item;
item.itemType = EXPAND;
cout << "请输入金额:" << endl;
item.amount = -readAmount();
cout << "\n备注:" << endl;
getline(cin,item.detail);
items.push_back(item);
insertItemIntoFile(item);
// 显示成功信息
cout << "\n------------------------记账成功!--------------------------\n" << endl;
}
void printItems(AccountItem item){
cout << item.itemType << "\t\t" << item.amount << "\t\t" << item.detail << endl;
}
void queryItems(vector items){
cout << "---------------- 查询结果 ---------------------" << endl;
cout << "\n类型\t\t金额\t\t备注\n" << endl;
int total = 0;
for (AccountItem item : items)
{
total+=item.amount;
printItems(item);
}
// 输出信息
cout << "===================================================\n" << endl;
cout << "总收支:" << total << endl;
}
void queryItems(vector items,string itemType){
cout << "---------------- 查询结果 ---------------------" << endl;
cout << "\n类型\t\t金额\t\t备注\n" << endl;
int total = 0;
for (AccountItem item : items)
{
if (item.itemType!=itemType)
continue;
total+=item.amount;
printItems(item);
}
// 输出信息
cout << "===================================================\n" << endl;
cout << ((itemType == INCOME) ? "总收入:":"总支出:") << total << endl;
}
void query(vector &items){
char key = readMenuSelection(4);
switch (key)
{
case '1':
queryItems(items);
break;
case '2':
queryItems(items,INCOME);
break;
case '3':
queryItems(items,EXPAND);
default:
break;
}
cout << "\n请按回车键返回主菜单..." << endl;
string line;
getline(cin, line);
}
void loadDataFromFile(vector &items){
ifstream input(FILENAME);
AccountItem item;
while(input>> item.itemType >> item.amount >> item.detail){
items.push_back(item);
}
input.close();
}