【C++学习系列】1.小谷记账踩坑记

文章目录

  • 前言
  • 1.基础支持
  • 2. 几个小坑
    • 2.1 为什么要用引用传值
    • 2.2 头文件的作用
    • 2.3 while true的使用和跳出
  • 3. 未解决的问题


前言

是尚硅谷的C++第一季的项目,我跟着敲下来了,发现几个坑点,记录下来;


1.基础支持

有这个则只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<AccountItem>& 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";elsebreak;    }return toupper(str[0]);
}

2. 几个小坑

2.1 为什么要用引用传值

// ------------1. 记账操作------------//
void accounting(vector<AccountItem> &items){switch (readMenuSelection(3)){case '1':income(items);break;case '2':expand(items);break;default:break;}
}

所有的AccountItem的Vector结构体都要引用传值,是因为在输出记账record的时候,没有读取文件,而是直接变量的vector实现的。

2.2 头文件的作用

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 中。

2.3 while true的使用和跳出

这个很难总结,自己体会把。
···
cin>>str;
getline(cin, str);
的区别, 第一个 不带 空格,断行
第二个带空格断行,
···
会给下一个等待键盘输入的方法,放入 \n, 很不友好,建议使用 getline(cin, str)
在这里插入图片描述

这个函数原来用的第一种方式,造成 item.detail 收到了 断行

3. 未解决的问题

我用vscode 编码的, 写入的数据 中午是乱码,但是piple走通了。

git地址:https://github.com/justinge/cpp_xiaogu

全体代码也贴一下:

#include<iostream>
#include<string>
#include<fstream>
#include<vector>
#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<AccountItem> &items);
void expand(vector<AccountItem> &items);
void accounting(vector<AccountItem> &items);
void query(vector<AccountItem> &items);
void loadDataFromFile(vector<AccountItem> &items);
int main(){cout << "justin 盖建明" << endl;vector<AccountItem> 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 << "主菜单" <<endl;cout << "1. 记账" <<endl;cout << "2. 查看" << endl;cout << "3. 结束" << endl;cout << "请输入所需要的菜单!(1-3)" <<endl;
}
void showQueryMenu() 
{	cout << "-------------------------------------------------------" << endl;cout << "|===============   选择查询条件   ====================|" << endl;cout << "|                                                     |" << endl;cout << "|***************  1 统计所有账目  ********************|" << endl;cout << "|***************  2 统 计 收 入   ********************|" << endl;cout << "|***************  3 统 计 支 出   ********************|" << endl;cout << "|***************  4 返回主菜单    ********************|" << endl;cout << "|_____________________________________________________|" << endl;cout << "\n请选择(1 - 4):";
}
char readMenuSelection(int options){string str;while(true){getline(cin,str);if (str.size() !=1 ||str[0] - '0' <= 0 || str[0] - '0' > 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<AccountItem> &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<AccountItem> &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<AccountItem> &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<AccountItem> 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<AccountItem> 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<AccountItem> &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<AccountItem> &items){ifstream input(FILENAME);AccountItem item;while(input>> item.itemType >> item.amount >> item.detail){items.push_back(item);}input.close();
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/34412.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

大华智慧园区综合管理平台文件上传漏洞复现(HW0day)

0x01 产品简介 “大华智慧园区综合管理平台”是一款综合管理平台&#xff0c;具备园区运营、资源调配和智能服务等功能。平台意在协助优化园区资源分配&#xff0c;满足多元化的管理需求&#xff0c;同时通过提供智能服务&#xff0c;增强使用体验。 0x02 漏洞概述 大华智慧园…

Vue+SpringBoot项目开发:登录页面美化,登录功能实现(三)

写在开始:一个搬砖程序员的随缘记录上一章写了从零开始VueSpringBoot后台管理系统&#xff1a;Vue3TypeScript项目搭建 VueTypeScript的前端项目已经搭建完成了 这一章的内容是引入element-plus和axios实现页面的布局和前后端数据的串联&#xff0c;实现一个登陆的功能&#x…

「何」到底该读「なん」还是「なに」?柯桥学日语

「何」到底该读「なん」还是「なに」&#xff1f; 首先&#xff0c;讲一个规律&#xff0c;大家记住就行。当「何」后面所接单词的第一个发音在“た”、“だ”、“な”行时&#xff0c;读作“なん”。一般这种情况下&#xff0c;后面跟的是の、でも、です和だ。 用例&#xff…

php后端实现调用高德地图进行POI搜索

对于当前位置或者选定省市位置进行查询 接口实现 /*** 查询地址* ApiTitle (查询地址)* ApiSummary (查询地址)* ApiMethod (POST)* ApiRoute (/api/demo/address)* ApiParams (name"dart", type"integer", requiredtrue, description"省…

【软件工程】数据流图/DFD概念符号/流程图分层/数据字典

【软件工程】数据流图/DFD概念符号/流程图分层/数据字典 目录 【软件工程】数据流图/DFD概念符号/流程图分层/数据字典 一、数据流图 ( DFD ) 简介 二、数据流图 ( DFD ) 概念符号 1、数据流 2、加工 ( 核心 ) 3、数据存储 4、外部实体 三、数据流图 ( DFD ) 分层 1、…

python制作小程序制作流程,用python编写一个小程序

这篇文章主要介绍了python制作小程序代码宠物运输&#xff0c;具有一定借鉴价值&#xff0c;需要的朋友可以参考下。希望大家阅读完这篇文章后大有收获&#xff0c;下面让小编带着大家一起了解一下。 1 importtkinter2 importtkinter.messagebox3 importmath4 classJSQ:5 6 7 d…

并发编程--------JUC集合

并发集合 一、ConcurrentHashMap 1.1 存储结构 ConcurrentHashMap是线程安全的HashMap ConcurrentHashMap在JDK1.8中是以CASsynchronized实现的线程安全 CAS&#xff1a;在没有hash冲突时&#xff08;Node要放在数组上时&#xff09; synchronized&#xff1a;在出现hash…

运算符重载

这里写目录标题 运算符重载在全局范围内重载运算符运算符重载时要遵循的规则运算符重载到底以成员函数的形式更好还是全局函数&#xff08;友元函数&#xff09;的形式更好重载例题&#xff08;属于友元函数的 运算符重载函数&#xff09; 运算符重载 运算符重载其实就是定义一…

022 - STM32学习笔记 - 扩展外部SDRAM(一) - 初识SDRAM和FMC

022 - STM32学习笔记 - 扩展外部SDRAM&#xff08;一&#xff09; - 初识SDRAM和FMC 之前学习了I2C读写EEPROM和SPI读写FLASH&#xff0c;学完之后在学习一种新的存储介质–SDRAM。 一、初识SDRAM 我们知道在stm32内部是有一定大小的SRAM&#xff08;256Kb&#xff09;和FLA…

无人驾驶实战-第十二课(强化学习自动驾驶系统)(完)

在七月算法上报了《无人驾驶实战》课程&#xff0c;老师讲的真好。好记性不如烂笔头&#xff0c;记录一下学习内容。 课程入口&#xff0c;感兴趣的也可以跟着学一下。 ————————————————————————————————————————— 强化学习&#xff…

c++日志工具之——log4cpp

1、log4cpp概述 Log4cpp是一个开源的C类库&#xff0c;它提供了C程序中使用日志和跟踪调试的功能&#xff0c;它的优点如下&#xff1a; 提供应用程序运行上下文&#xff0c;方便跟踪调试&#xff1b; 可扩展的、多种方式记录日志&#xff0c;包括命令行、文件、回卷文件、内…

阿里云服务器搭建WordPress建站教程基于Windows系统

本教程是使用阿里云服务器镜像系统选择的是Windows操作系统&#xff0c;手动安装WordPress博客网站全过程。本教程介绍如何在Windows操作系统的ECS实例上搭建WordPress网站。 目录 准备工作 搭建WordPress网站 解析WordPress网站域名 准备工作 创建Windows操作系统的ECS实…

Docker mysql+nacos单机部署

docker 网络创建 由于nacos需要访问mysql的数据&#xff0c;因此mysql容器和nacos容器之间需要进行通信。容器间通信有很多方式&#xff0c;在这里采用同一网络下的方式进行实现。因此需要创建网络。创建网络的命令如下&#xff1a; docker network create --driver bridge n…

HICP学习--BGP综合小实验

需要完善 一、实验拓扑 二、实验需求 1、R2-7每台路由器均存在一个环回接口用于建立邻居&#xff0c;同时还存在一个环回来代表连接用户的接口;最终这些连接用户的接口网络需要可以和R1/8的环回通讯 2、AS2网段地址172.16.0.0/16 减路由条目数量 三、实验步骤 首先配置IP R…

tensorflow / tensorflow-gpu cuda cudNN tensorRT 安装,启用显卡加速

tensorflow / tensorflow-gpu cuda cudNN tensorRT 安装,启用显卡加速 说明 Tensorflow-GPU 已被移除。请安装 tensorflow 。 tensorflow 通过 Nvidia CUDA 支持 GPU 加速操作。 自 2019 年 9月发布 的 TensorFlow2.1 以来&#xff0c;tensorFlow 和 tensorflow-GPU 一直是同…

智慧城市美术效果Unity实现笔记流程

智慧城市美术效果Unity实现笔记流程&#xff1a; 参考 对标 效果图&#xff1a; 参考资料&#xff1a; 方案一&#xff1a; fBlender GIS 获取城市 房屋道路等数据 安装BlenderGIS插件 落叶大师智慧城市效果解析 方案二&#xff1a; CityEngine2022地块生成 写实类-参考图&…

c语言每日一练(6)

前言&#xff1a;每日一练系列&#xff0c;每一期都包含5道选择题&#xff0c;2道编程题&#xff0c;博主会尽可能详细地进行讲解&#xff0c;令初学者也能听的清晰。每日一练系列会持续更新&#xff0c;暑假时三天之内必有一更&#xff0c;到了开学之后&#xff0c;将看学业情…

华为运动健康,十年创新天地宽

我听一位朋友讲过这样一个故事。某天早上&#xff0c;急诊科的医生迎来了一位患者&#xff0c;患者进来后直接说&#xff1a;“大夫&#xff0c;我房颤了。” 这位医生非常诧异&#xff0c;因为心脏房颤确实非常危急&#xff0c;但很多时候并没有明显的生理体征&#xff0c;患者…

JavaScript之BOM+window对象+定时器+location,navigator,history对象

一.BOM概述 BOM即浏览器对象模型,它提供了独立于内容而与窗口进行交互的对象 BOM的顶级对象是window 二.window对象的常见事件 1.窗口加载事件window.onload window.onload function(){} 或者 window.addEventListener("onload" , function(){}); window.onlo…

Mybatis-plus动态条件查询QueryWrapper的使用

Mybatis-plus动态条件查询QueryWrapper的使用 一&#xff1a;queryWrapper介绍 queryWrapper是mybatis plus中实现查询的对象封装操作类&#xff0c;可以封装sql对象&#xff0c;包括where条件&#xff0c;order by排序&#xff0c;select哪些字段等等&#xff0c;他的层级关…