49. 海豚记账簿软件(b站的一个小项目)

news2024/10/7 12:24:25

闲着也是闲着就跟着别人做了一个小项目

目录

1.需求和目标

2.整体功能描述

3.核心思路

4.全部代码


1.需求和目标

项目的需求,实现一个叫做“海豚记账簿”的基于命令行界面的家庭记账软件。

 

2.整体功能描述

这个软件相对简单,只需要基于命令行做纯文本的交互,不涉及图形化界面。作为一个记账软件,主要有两大功能:记账和查询。也就是说,软件需要能够记录家庭中每一笔收入、支出的账目,并提供查询收支明细的功能。而且为了让软件有真正的实用价值,需要对数据做持久化保存;我们这里只需要存放在一个指定的文本文件中。

项目采用分级菜单方式,每一级菜单应该有“返回主菜单”功能;主菜单有“退出”选项。

 

 

 

3.核心思路

记账软件处理的数据,就是收入或者支出的“账目”。每一条账目数据,都应该包含收支类型、金额、备注三部分,这可以构建一个结构体类型 AccountItem 来表示。

而程序运行的开始,应该读取保存在文件中的数据,读取之后应该是一个 AccountItem 类型的数组。

在流程控制方面,如果用户不选择退出,程序就不会结束,所以应该用一个while循环来处理整个流程;当用户确认退出时,更改一个标志位,用来退出循环。

每一级菜单做键盘选择后,可以用 switch 分支语句来处理;不同的功能模块,可以包装成函数。

4.全部代码

 account_item.h

#pragma once
#include "common.h"

//定义结构体类型
struct AccountItem {
	string itemType;
	int amount;
	string detail;//备注信息
};

//针对账目数据进行操作的函数声明

//加载账目数据
void loadDataFromFile(vector<AccountItem>& items);

//记账
void accounting(vector<AccountItem>& items);
void insertIntoFile(const AccountItem& item);
void income(vector<AccountItem>& items);
void outcome(vector<AccountItem>& items);

//查询
void query(const vector<AccountItem>& items);
void queryItems(const vector<AccountItem>& items);
void queryItems(const vector<AccountItem>& items, const string itemType);
void printItem(const AccountItem& item);

common.h

#pragma once
#include <iostream>
#include <fstream>
#include <string>
#include <vector>

#define INCOME "收入"
#define OUTCOME "支出"
#define FILENAME "D:\\C++project\\AccountBook.txt"

using namespace std;

//通用功能性函数声明
//绘制菜单的函数
void showMainMenu(); 
void showAccountMenu();
void showQueryMenu();

//读取键盘输入进行合法性校验的函数
char readMenuSelection(int options);
char readQuitConfirm();
int readAmount();

haitunaccount.cpp

#include "account_item.h"
#include "common.h"

int main() {
	//1.加载文件中的账目数据
	vector<AccountItem> items;
	loadDataFromFile(items);

	bool quit = false;
	while (!quit) {
		//2.显示主菜单
		showMainMenu();

		//3.读取键盘选择,并作合法性校验
		char key=readMenuSelection(3);

		switch (key) {
		case '1':    //1.记账
			showAccountMenu();  //显示记账菜单
			accounting(items);
			break;
		case '2':    //2.查询
			showQueryMenu();  //显示查询菜单
			query(items);
			break;
		case '3':    //3.退出
			cout << "\n确认退出?(Y/N):";
			if (readQuitConfirm() == 'Y')
				quit = true;
			break;
		default:
			break;
		}

		cout << endl;
	}
}

 

opperations.cpp

#include "account_item.h"
#include "common.h"


//
void loadDataFromFile(vector<AccountItem>& items) {
	ifstream input(FILENAME);

	//逐行读取每一条账目,包装成AccountItem
	AccountItem item;
	while (input >>item.itemType>>item.amount>>item.detail) {
		items.push_back(item);
	}

	input.close();
}

//-------------------------1.记账------------------------
//记账操作
void accounting(vector<AccountItem>& items) {
	

	//读取键盘选择,并作合法性校验
	char key = readMenuSelection(3);

	switch (key) {
	case '1':    //1.收入
		income(items);
		break;
	case '2':    //2.支出
		outcome(items);
		break;
	case '3':    //3.返回主菜单
		break;
	default:
		break;
	}
}

//记录一笔输入
void income(vector<AccountItem>& items) {
	//新构建一个AccountItem对象
	AccountItem item;

	//类型已经确定,就是收入
	item.itemType = INCOME;

	//与用户交互,键盘输入金额和备注信息
	cout << "\n本次收入金额:";
	item.amount = readAmount();

	cout << "\n备注:";
	getline(cin, item.detail);

	//添加到vector中
	items.push_back(item);
	//写入文件做持久化保存
	insertIntoFile(item);

	//显示成功信息
	cout << "\n-------------------------------记账成功-------------------------------\n" << endl;
	cout << "\n请按回车键返回主菜单..." << endl;

	string line;
	getline(cin, line);
}

//记录一笔支出
void outcome(vector<AccountItem>& items) {
	//新构建一个AccountItem对象
	AccountItem item;

	//类型已经确定,就是支出
	item.itemType = OUTCOME;

	//与用户交互,键盘输入金额和备注信息
	cout << "\n本次支出金额:";
	item.amount = -readAmount();

	cout << "\n备注:";
	getline(cin, item.detail);

	//添加到vector中
	items.push_back(item);
	//写入文件做持久化保存
	insertIntoFile(item);

	//显示成功信息
	cout << "\n-------------------------------记账成功-------------------------------\n" << endl;
	cout << "\n请按回车键返回主菜单..." << endl;

	string line;
	getline(cin, line);
}

//将一条账目写入文件中
void insertIntoFile(const AccountItem& item) {
	//创建一个ofstream对象,以追加方式进行写入
	ofstream output(FILENAME, ios::out | ios::app);

	output << item.itemType << "\t" << item.amount << "\t" << item.detail << endl;

	output.close();
}

//------------------------2.查询----------------------------
void query(const vector<AccountItem>& items) {

	//读取键盘选择,并作合法性校验
	char key = readMenuSelection(4);

	switch (key) {
	case '1':    //1.查询所有账目,并统计总收支
		queryItems(items);
		break;
	case '2':    //2.查询收入,统计总收入
		queryItems(items,INCOME);
		break;
	case '3':    //3.查询支出,统计总支出
		queryItems(items, OUTCOME);
		break;
	default:
		break;
	}
}

//查询账目功能函数
void queryItems(const vector<AccountItem>& items) {
	cout << "---------------------查询结果-----------------------" << endl;
	cout << "\n类型\t\t金额\t\t备注\n" << endl;

	//遍历所有账目,统计总收支
	int total = 0;
	for (auto item : items) {
		printItem(item);
		total += item.amount;
	}

	//输出信息
	cout << "======================================================\n" << endl;
	cout << "总收支:" << total << endl;
	cout << "\n请按回车键返回主菜单..." << endl;

	string line;
	getline(cin, line);
}

//函数重载
void queryItems(const vector<AccountItem>& items,const string itemType) {
	cout << "---------------------查询结果-----------------------" << endl;
	cout << "\n类型\t\t金额\t\t备注\n" << endl;

	//遍历所有账目,统计总收支
	int total = 0;
	for (auto item : items) {
		if (item.itemType == itemType) {
			printItem(item);
			total += item.amount;
		}
	}

	//输出信息
	cout << "======================================================\n" << endl;
	// 使用条件运算符输出不同的字符串,根据 itemType 的值来判断
	cout << ((itemType == INCOME) ? "总收入:" : "总支出:") << total << endl;
	cout << "\n请按回车键返回主菜单..." << endl;

	string line;
	getline(cin, line);
}

//打印输出一条账目信息
void printItem(const AccountItem& item) {
	cout << item.itemType << "\t\t" << item.amount << "\t\t" << item.detail << endl;
}

 

read_input.cpp

#include "common.h"

//读取键盘输入的选项,进行合法性校验
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;
	char ch;

	while (true) {
		getline(cin, str);

		ch = toupper(str[0]);
		//进行合法性校验
		if (str.size() != 1 || ch!='Y'&&ch!='N') {
			cout << "\n输入错误,请重新输入(Y/N):";
		}
		else
			break;
	}

	//输入合法
	return ch;
}

//读取键盘输入的金额数,并作合法性校验
int readAmount() {
	int amount;

	string str;
	while (true) {
		getline(cin, str);

		//进行合法性校验
		try {
			amount = stoi(str);//标准库函数,将str转换为int类型数据
			break;
		}
		catch (invalid_argument error) {
			cout << "输入错误,请正确输入数字:";
		}
	}

	//输入合法
	return amount;
}

 

menu.cpp

#include "common.h"
//绘制菜单的函数
void showMainMenu() {
	system("cls");    // 调用system函数,清屏,对windows有效

	cout << "--------------------------------------------------------" << endl;
	cout << "|================ 欢迎使用海豚记账簿 ==================|" << endl;
	cout << "|                                                      |" << endl;
	cout << "|****************     1 记  账     ********************|" << endl;
	cout << "|****************     2 查  询     ********************|" << endl;
	cout << "|****************     3 退  出     ********************|" << endl;
	cout << "|______________________________________________________|" << endl;

	cout << "\n请选择(1 - 3):";
}
void showAccountMenu()
{
	cout << "-------------------------------------------------------" << endl;
	cout << "|===============   选择记账种类   ====================|" << endl;
	cout << "|                                                     |" << endl;
	cout << "|***************    1 收  入      ********************|" << endl;
	cout << "|***************    2 支  出      ********************|" << endl;
	cout << "|***************    3 返回主菜单  ********************|" << endl;
	cout << "|_____________________________________________________|" << endl;

	cout << "\n请选择(1 - 3):";
}

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):";
}

 

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

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

相关文章

【数据结构OJ题】移除元素

原题链接&#xff1a;https://leetcode.cn/problems/remove-element/ 目录 1. 题目描述 2. 思路分析 3. 代码实现 1. 题目描述 2. 思路分析 方法一&#xff1a;暴力删除&#xff0c;挪动数据覆盖。即遍历整个nums[ ]数组&#xff0c;遇到值等于val的元素&#xff0c;就将整…

Eclipse如何自动添加作者、日期等注释

一、创建类时自动添加注释 1、Window->Preferences 2、Java->Code Syle->Code Templates->Code->New Java files->Edit->要添加的注释->Apply 二、选中要添加的类或者方法通过AltShiftJ快捷键添加 1、Window->Preferences 2、Java->Code Syle…

IP地址、网关、子网掩码

通过SSH将Ubuntu的盘映射到Windows下面去&#xff0c;以及在VsCode通过SSH Server或者在MobaXterm中通过SSH连接到远程ubuntu服务器&#xff0c;但由于之前Ubuntu的网络是自动连接的&#xff0c;IPv4经常会改变&#xff0c;就会导致上述三个远程连接都需要重新配置。 故由DHCP自…

ETHERCAT转PROFIBUS网关连接安川伺服支持EtherCAT总线吗

捷米JM-DP-ECT&#xff0c;是自主研发的一款PROFIBUS从站功能的通讯网关&#xff0c;它的主要功能是将ETHERCAT设备接入到PROFIBUS网络中。 JM-DP-ECT这个小小的网关可不简单&#xff0c;连接到PROFIBUS总线中做为从站使用&#xff0c;连接到ETHERCAT总线中做为从站使用。 1.2…

DAY03_Spring—SpringAOPAOP切入点表达式AOP通知类型Spring事务管理

目录 一 AOP1 AOP简介问题导入1.1 AOP简介和作用1.2 AOP中的核心概念 2 AOP入门案例问题导入2.1 AOP入门案例思路分析2.2 AOP入门案例实现【第一步】导入aop相关坐标【第二步】定义dao接口与实现类【第三步】定义通知类&#xff0c;制作通知方法【第四步】定义切入点表达式、配…

kafka-保证数据不重复-生产者开启幂等性和事务的作用?

1. 生产者开启幂等性为什么能去重&#xff1f; 1.1 场景 适用于消息在写入到服务器日志后&#xff0c;由于网络故障&#xff0c;生产者没有及时收到服务端的ACK消息&#xff0c;生产者误以为消息没有持久化到服务端&#xff0c;导致生产者重复发送该消息&#xff0c;造成了消…

SpringMVC -- REST风格开发,RESTful快速开发、RESTful注解开发

&#x1f40c;个人主页&#xff1a; &#x1f40c; 叶落闲庭 &#x1f4a8;我的专栏&#xff1a;&#x1f4a8; c语言 数据结构 javaweb 石可破也&#xff0c;而不可夺坚&#xff1b;丹可磨也&#xff0c;而不可夺赤。 REST 一、REST简介1.1REST风格简介 二、RESTful入门案例2.…

SpringBoot集成Logback日志

SpringBoot集成Logback日志 文章目录 SpringBoot集成Logback日志一、什么是日志二、Logback简单介绍三、SpringBoot项目中使用Logback四、概念介绍一、日志记录器Logger1.1、日志记录器对象生成1.2、记录器的层级结构1.3、过滤器1.4、logger设置日志级别1.5、java代码演示1.6、…

【资料分享】全志科技T507-H工业核心板规格书

1 核心板简介 创龙科技SOM-TLT507是一款基于全志科技T507-H处理器设计的4核ARM Cortex-A53全国产工业核心板&#xff0c;主频高达1.416GHz。核心板CPU、ROM、RAM、电源、晶振等所有元器件均采用国产工业级方案&#xff0c;国产化率100%。 核心板通过邮票孔连接方式引出MIPI C…

防火墙第四次作业

1. 什么是IDS&#xff1f; IDS是&#xff1a;入侵检测系统&#xff08;intrusion detection system&#xff0c;简称“IDS”&#xff09;是一种对网络传输进行即时监视&#xff0c;在发现可疑传输时发出警报或者采取主动反应措施的网络安全设备。它与其他网络安全设备的不同之…

K8s中的核心技术Helm

1.helm的引入 &#xff08;1&#xff09;编写yaml文件 &#xff08;2&#xff09;编写deployment文件 &#xff08;3&#xff09;编写service文件 &#xff08;4&#xff09;编写Ingress文件 2.helm的引入解决的问题&#xff1f; &#xff08;1&#xff09;使用helm可以把…

CommStudio for .NET Crack

CommStudio for .NET Crack CommStudio for.NET使您的应用程序可以轻松地使用串行端口和调制解调器进行通信。CommStudio for.NET是一套全面的组件和可视化调试工具&#xff0c;可将远程系统和设备与visual Studio 2005和visual Studio 2008集成。开发与遗留系统和外部设备集成…

IAR开发环境的安装、配置和新建STM32工程模板

IAR到环境配置到新建工程模板-以STM32为例 一、 简单介绍一下IAR软件1. IAR的安装&#xff08;1&#xff09; 下载IAR集成开发环境安装文件&#xff08;2&#xff09; 安装 2. 软件注册授权 二、IAR上手使用(基于STM32标准库新建工程)1、下载标准库文件2、在IAR新建工程&#x…

99%的人做效果图都会忽略的问题!为什么你的效果图没有亚洲面孔?

不知道各位设计师有没有发现一个问题&#xff0c;我们做了不少效果图&#xff0c;也积攒了很多素材&#xff0c;但是出现在我们效果图的人物几乎都是外国人&#xff01; 可能你会说是亚洲人的素材实在太少&#xff0c;但本质是对“人”不够重视&#xff0c;觉得随便“复制粘贴”…

信息安全技术工业控制系统安全控制应用指南学习笔记

工业控制系统安全控制基线 根据工业控制系统在国家安全、经济建设、社会生活中的重要程度&#xff0c;遭到破坏后对国家安全、社会秩序、公共利益以及公民、法人和其他组织的合法权益的危害程度等&#xff0c;结合信息安全等级保护标准划分及实施效果分析&#xff0c;结合工业…

超简单的ssm的疫情上报系统java学生防控打卡统计 jsp源代码mysql

本项目为前几天收费帮学妹做的一个项目&#xff0c;Java EE JSP项目&#xff0c;在工作环境中基本使用不到&#xff0c;但是很多学校把这个当作编程入门的项目来做&#xff0c;故分享出本项目供初学者参考。 一、项目描述 疫情上报系统 软件介绍 使用SSM框架搭建后台 前端采…

MYSQL06高级_为什么使用索引、优缺点、索引的设计、方案、聚簇索引、联合索引

文章目录 ①. 为什么使用索引②. 索引及其优缺点③. InnoDb - 索引的设计④. InnoDb中的索引方案⑤. 索引 - 聚簇索引⑥. 索引 - 二级索引 ①. 为什么使用索引 ①. 索引是存储引擎用于快速找到数据记录的一种数据结构,就好比去图书馆找书,或者新华字典里找字,相当于一个目录,可…

react搭建在线编辑html的站点——引入grapes实现在线拖拉拽编辑html

文章目录 ⭐前言⭐搭建react ts项目⭐引入grapes 插件⭐结束 ⭐前言 大家好&#xff0c;我是yma16&#xff0c;本文分享关于react搭建在线编辑html的站点。 react 发展历史 React是由Facebook开发的一种JavaScript库&#xff0c;用于构建用户界面。React最初发布于2013年&…

MySQL两种存储引擎及索引对比

MySQL两种存储引擎及索引对比 前言存储引擎主要区别相关命令存储引擎1: MyISAM存储引擎2: InnoDB其他存储引擎: 索引聚集&#xff08;聚簇&#xff09;索引二级索引 常见面试题为什么 DBA 都建议表中一定要有主键&#xff0c;而且推荐使用整型自增&#xff1f;为什么要有主键&a…

ElasticSearch7.6入门学习笔记

在学习ElasticSearch之前&#xff0c;先简单了解一下Lucene&#xff1a; Doug Cutting开发 是apache软件基金会4 jakarta项目组的一个子项目 是一个开放源代码的全文检索引擎工具包不是一个完整的全文检索引擎&#xff0c;而是一个全文检索引擎的架构&#xff0c;提供了完整的…