c语言笔记之小项目家庭收支记账软件
项目1——家庭收支记账软件
实现一个家庭收支记账软件,能够登记收入、登记支出,可以展示收支明细。
1.1 需求说明
1.1.1 菜单显示
进入系统,展示主菜单,输入各功能对应的数字编号选择要进行的操作,如下图:
1.1.2 登记收入
输入2,进入“登记收入”,需输入“本次收入金额”和“本次收入说明”,输入完成后会再次进入主菜单。
1.1.3 登记支出
输入3,进入“登记支出”,需输入“本次支出金额”和“本次支出说明”,输入完成后会判断余额是否充足,如果余额充足会再次进入主菜单。
如果余额不足,会给出相应的提示。
1.1.4 显示收支明细
输入1,进入“收支明细”,如下图所示:”
当没有任何收支明细时,提示"当前没有收支明细… 来一笔吧!"
显示完收支明细,会再次进入主菜单。
1.1.5 退出
用户输入4退出时,给出提示"你确定要退出吗? y/n",必须输入正确的y/n ,否则循环输入指令,直到输入y或者n。
1.2 流程分析
1.2.1 总流程图
1.2.2 登记收入流程图
1.2.3 登记支出流程图
1.2.4 收支明细流程图
1.2.5 退出流程图
回顾内容:
1.c语言规定的循环结构有哪些?
for/while/do…while
2.熟悉三种循环结构的使用场景
三种循环结构可以相互转换
3.循环结构的4个基本要素
①初始化条件
②循环条件
③循环体
④迭代条件
4.格式
for(①;②;④){
③
}
①
while(②){
③
④
}
①
do{
③
④
}while(②);
5.循环结构退出的情况都有哪些?
1.迭代循环条件返回0,false
2.使用break结束,循环的执行
6.c语言中的分支结构有哪些?
>if if..else switch-case结构
7.如上的两种分支结构如何选择?
凡是可以使用switch-case实现的结构都可以改写为if-else。反之不成立
switch-case,针对于有限的类型,且变量取值情况不多的场景。
此外的情况,都默认选择if-else
/**
* 完成项目1,家庭收支记账软件,
* 1.整体框架搭建
* 2.完成退出功能
* 收支明细
* 登记收入
* 登记支出,(关于余额的判断)
*
* 难点关注:
* 1.关于字符串的处理
* >字符串变量的声明:①char型数组 ② 字符指针③④
* char型数组可以修改细微的内容,但是字符指针不行
* 数组一旦初始化地址是不能变的,字符指针是一个变量,地址是可以变的
* >字符串相关的函数:
* strcat():字符串的连接
* strcpy()
* strcmp():比较大小
* 2.关于输入,输出相关的函数:
* scanf()/printf()
* getchar()/putchar()------>用的少
* puts()/gets()---->fgets()
* sprintf()/sscanf()---->输出到字符串
*
* 重点关注:
* 代码逻辑!比以前单独练习代码量更大,逻辑更复杂。
*
*/
#include <stdio.h>
#include <string.h>
/**
* 对代码进行升级
*
*/
// 声明结构体
struct FamilyAccount
{
int hasRecord; // 默认情况下没有收入或支出的明细
char details[3000]; // 用来存储收支的记录信息
double initBalance;
};
int loop = 1;
/**
* 退出功能
*/
void goExit()
{
printf("你确定要退出吗(y/n):");
char isExit;
while (1)
{
scanf("%c", &isExit);
scanf("%c", &isExit);
if (isExit == 'y' || isExit == 'n')
{
break;
}
else
{
printf("你输入有误,请重新输入(y/n):");
}
}
if (isExit == 'y')
{
loop = 0;
printf("欢迎再次来到家庭记账软件");
}
}
/**
* 显示收支明细
*/
void showDetails(struct FamilyAccount *fAccount)
{
if (!fAccount->hasRecord)
{
printf("当前没有收支明细.....来一笔吧!");
}
else
{
printf("%s\n", fAccount->details);
}
}
/**
* 登记收入
*/
void income(struct FamilyAccount *fAccount)
{
double addMoney;
printf("本次收入金额:");
scanf("%lf", &addMoney);
printf("本次收入说明:");
char addDetail[100];
scanf("%s", addDetail);
(*fAccount).initBalance += addMoney;
// 将用户的输入信息拼接为一个完整的字符串
char addDetails[300];
sprintf(addDetails, "收入\t%.2f\t\t%.2f\t\t\t%s\n", addMoney, fAccount->initBalance, addDetail);
// 将用户完整收入的信息添加到当前整体用户收支明细
strcat(fAccount->details, addDetails);
// 收入的登记情况
fAccount->hasRecord = 1;
printf("登记收入完成\n");
}
/**
* 登记收入
*/
void pay(struct FamilyAccount *fAccount){
printf("本次指出金额:");
double minusMoney;
scanf("%lf", &minusMoney);
if (minusMoney > fAccount->initBalance)
{
printf("余额不足\n");
}
else
{
fAccount->initBalance -= minusMoney;
printf("本次支出说明:");
char minusDetail[100];
scanf("%s", minusDetail);
// 将用户输入的信息拼接为一个完整的字符串
char minusDetails[300];
sprintf(minusDetails, "支出\t%.2f\t\t%.2f\t\t\t%s\n", minusMoney, fAccount->initBalance, minusDetail);
// 将用户完整收入的信息添加到当前整体用户收支明细里
strcat(fAccount->details, minusDetails);
fAccount->hasRecord = 1;
printf("登记支出完成\n");
}
}
void menu(struct FamilyAccount *fAccount)
{
do
{
printf("-----------------家庭收支记账软件-----------------\n");
printf(" 1 收支明细\n");
printf(" 2 登记收入\n");
printf(" 3 登记支出\n");
printf(" 4 退 出\n");
printf(" 请选择(1-4):\n");
int selection; // 记录用户的选择
scanf("%d", &selection);
switch (selection)
{
case 1:
showDetails(fAccount);
break;
case 2:
income(fAccount);
break;
case 3:
pay(fAccount);
break;
case 4:
goExit();
break;
default:
printf("输出错误请重新输入!\n");
getchar();
break;
}
} while (loop);
printf("退出");
}
int main()
{
// 声明结构体变量
struct FamilyAccount fAccount;
fAccount.hasRecord = 0;
// fAccount.details = "-----------------当前收支明细记录-----------------\n收支\t收支金额\t账户金额\t\t说明\n";
// 数组不能重新赋值,所以会报错,可以改成指针
strcpy(fAccount.details, "-----------------当前收支明细记录-----------------\n收支\t收支金额\t账户金额\t\t说明\n");
fAccount.initBalance = 1000;
// 显示界面
menu(&fAccount);
getchar();
getchar();
return 0;
}