目标
需求说明
界面说明
登记收入界面:
登记支出界面
收支明细界面
退出界面
项目代码改进要求
自己完成的代码
版本1
#include<stdio.h>
#include<string.h>
void choose(int button,int i);
//项目--家庭收支软件
static double total=10000;//总金额
#define SIZE 100
//用来接收收支信息
struct Count{char *name;double money;char info[100];
}count[100];
int main()
{int d=0;char c='0';int i=0;//统计记录个数printf("---------家庭收支软件--------\n");printf(" 1.收支明细\n 2.登记收入\n 3.登记支出\n 4.退出\n");while(1){printf("请选择(1-4):");scanf("%d",&d);getchar();//接收回车enterif(d==4){printf("是否确认退出(y/n):");//输入的是字符串scanf("%c",&c);getchar();//接收回车enter,一定要记得接收回车符if(c=='y'){break;//退出while循环}}else{choose(d,i);if(d==2||d==3){i++;}}}fflush(stdin);//刷新getchar();return 0;
}
void choose(int button,int i)
{int k;if(button==1)//收支明细{printf("---------当前收支明细记录--------\n");printf("收支\t\t收支金额\t\t总金额\t\t说明\n");if(i==0){printf("无\t\t0.00\t\t\t%.2f\t无\n",total);}else{for(k=0;k<i;k++){printf("%s\t\t%.2f\t\t\t%.2f\t%s\n",count[k].name,count[k].money,total,count[k].info);}}printf("\n---------------------------------\n");}else if(button==2)//登记收入{count[i].name="收入";printf("本次收入金额:");scanf("%lf",&count[i].money);printf("本次收入说明:");scanf("%s",count[i].info);total+=count[i].money;}else if(button==3)//登记支出{count[i].name="支出";printf("本次支出金额:");scanf("%lf",&count[i].money);printf("本次支出说明:");scanf("%s",count[i].info);total-=count[i].money;}}
版本2
#include<stdio.h>
#include<string.h>
void choose(int button,int i);
//项目--家庭收支软件
static double total=10000;//总金额
//用来接收收支信息
struct Count{char *name;//每一次收支的名称:收入or支出double money;//每一次收支的金额char info[100];//每一次收支的信息double all;//每一次收支后的总金额
}count[100];
int main()
{int d=0;char c='0';int i=0;//统计记录个数printf("---------家庭收支软件--------\n");printf(" 1.收支明细\n 2.登记收入\n 3.登记支出\n 4.退出\n");while(1){printf("请选择(1-4):");scanf("%d",&d);getchar();//接收回车enterif(d==4){printf("是否确认退出(y/n):");//输入的是字符串scanf("%c",&c);getchar();//接收回车enter,一定要记得接收回车符if(c=='y'){break;//退出while循环}else if(c=='n'){continue;}else{printf("输入错误\n");} }else{choose(d,i);if(d==2||d==3){i++;}}}fflush(stdin);//刷新getchar();return 0;
}
void choose(int button,int i)
{int k;if(button==1)//收支明细{printf("---------当前收支明细记录--------\n");printf("收支\t\t收支金额\t\t总金额\t\t说明\n");if(i==0){printf("无\t\t0.00\t\t\t%.2f\t无\n",total);printf("当前没有收支明细...来一笔吧!\n");}else{for(k=0;k<i;k++){printf("%s\t\t%.2f\t\t\t%.2f\t%s\n",count[k].name,count[k].money,count[k].all,count[k].info);}}printf("\n---------------------------------\n");}else if(button==2)//登记收入{count[i].name="收入";printf("本次收入金额:");scanf("%lf",&count[i].money);printf("本次收入说明:");scanf("%s",count[i].info);total+=count[i].money;count[i].all=total;}else if(button==3)//登记支出{count[i].name="支出";printf("本次支出金额:");double temp=0;//临时存储支出金额scanf("%lf",&temp);getchar();//过滤enterif(temp>total){printf("当前余额不足,不能支出\n");}else{count[i].money=temp;printf("本次支出说明:");scanf("%s",count[i].info);total-=count[i].money;count[i].all=total;} }}
案例代码
案例代码版本1
#include<stdio.h>
#include<string.h>
//项目--家庭收支软件(teacher)--代码版本1
int main()
{//所有的局部变量在使用前要初始化int loop=1;//控制最外层do--while循环int num=0;//用户选择的数字char quit='0';//用户选择是否退出的操作:y/ndouble total=1000;//总金额double money=0;//每次收支金额char detail[100];//每次收支说明char info[3000]="";//要显示的所有明细char s[1000]="";//每次收支明细的临时数组int n=0;//统计是否有至少一笔收支明细记录,1为有,0为无//初始化detail数组memset(detail,0,sizeof(detail));do{printf("------家庭收支软件--------\n");printf("--------1.收支明细--------\n--------2.登记收入--------\n--------3.登记支出--------\n--------4.退出-----------\n");printf("请选择(1-4):");scanf("%d",&num);getchar();//过滤enterswitch(num){//使用switch对每种选择结果做出反应case 1://收支明细printf("收支\t\t收支金额\t总金额\t说明\n");printf("%s",info);if(!n){printf("当前没有收支明细..来一笔吧!\n");}break;case 2://登记收入printf("本次收入金额:");scanf("%lf",&money);getchar();//enterprintf("本次收入说明:");scanf("%s",detail);getchar();//entertotal+=money;sprintf(s,"收支\t\t%.2f\t\t%.2f\t%s\n",money,total,detail);strcat(info,s);n=1;//有一笔明细记录break;case 3://登记支出printf("本次支出金额:");scanf("%lf",&money);getchar();//enterif(money>total){printf("能够支出的金额不够\n");}else{printf("本次支出说明:");scanf("%s",detail);getchar();//entertotal-=money;sprintf(s,"收支\t\t%.2f\t\t%.2f\t%s\n",money,total,detail);strcat(info,s);n=1;//有一笔明细记录}break;case 4://退出do{printf("确认是否退出(y/n):");scanf("%c",&quit);getchar();//enterif(quit=='y'||quit=='n'){break;//跳出此do-while循环}else{printf("输入错误!\n");}}while(1);//循环执行退出询问if(quit=='y'){loop=0;//结束最外层do-while循环}break;}}while(loop);//循环输出getchar();return 0;
}
案例代码版本2
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
//项目--家庭收支软件(teacher)--代码版本2--结构体+函数
//所有的局部变量在使用前要初始化
int loop=1;//控制最外层do--while循环
char info[3000]="";//要显示的所有明细
char s[1000]="";//每次收支明细的临时数组
int num=0;//用户选择的数字
char quit='c';//用户选择是否退出的操作:y/n//家庭账户结构体
struct Account{double total;//总金额double money;//每次收支金额char detail[100];//每次收支说明int n;//统计是否有至少一笔收支明细记录,1为有,0为无};//支出
void pay(struct Account*count)
{printf("本次支出金额:");scanf("%lf",&(*count).money);getchar();//enterif((*count).money>(*count).total){printf("能够支出的金额不够\n");}else{printf("本次支出说明:");scanf("%s",(*count).detail);getchar();//enter(*count).total-=(*count).money;sprintf(s,"收支\t\t%.2f\t\t%.2f\t%s\n",(*count).money,(*count).total,(*count).detail);strcat(info,s);(*count).n=1;//有一笔明细记录}
}
//收入
void income(struct Account*count)
{printf("本次收入金额:");scanf("%lf",&(*count).money);getchar();//enterprintf("本次收入说明:");scanf("%s",(*count).detail);getchar();//enter(*count).total+=(*count).money;sprintf(s,"收支\t\t%.2f\t\t%.2f\t%s\n",(*count).money,(*count).total,(*count).detail);strcat(info,s);(*count).n=1;//有一笔明细记录}
//所有明细
void show(struct Account*count)
{printf("收支\t\t收支金额\t总金额\t说明\n");printf("%s",info);if(!(*count).n){printf("当前没有收支明细..来一笔吧!\n");}}
//退出
void esc()
{do{printf("确认是否退出(y/n):");scanf("%c",&quit);getchar();//enterif(quit=='y'||quit=='n'){break;//跳出此do-while循环}else{printf("输入错误!\n");}}while(1);//循环执行退出询问if(quit=='y'){loop=0;//结束最外层do-while循环}
}
//显示菜单
void menu(struct Account*count)
{do{printf("------家庭收支软件--------\n");printf("--------1.收支明细--------\n--------2.登记收入--------\n--------3.登记支出--------\n--------4.退出-----------\n");printf("请选择(1-4):");scanf("%d",&num);getchar();//过滤enterswitch(num){//使用switch对每种选择结果做出反应case 1://收支明细show(count);break;case 2://登记收入income(count);break;case 3://登记支出pay(count);break;case 4://退出esc();break;}}while(loop);//循环输出
}
int main()
{struct Account*count;//在使用指针时要为指针分配内存空间 struct Account*count=(struct Account*)malloc(20*sizeof(struct Account*));//初始化结构体成员(*count).n=0;//初始化detail数组memset((*count).detail,0,sizeof((*count).detail));(*count).money=0;(*count).total=1000; menu(count);getchar();return 0;
}
写代码时遇到的知识点
1.使用memset()去初始化局部变量
C语言中系统只会自动初始化全局变量
定义变量时一定要进行初始化,尤其是数组和结构体这种占用内存大的数据结构。在使用数组的时候经常因为没有初始化而产生“烫烫烫烫烫烫”这样的野值,俗称“乱码”
memset() 函数可以说是初始化内存的“万能函数”,通常为新申请的内存进行初始化工作。它是直接操作内存空间
使用# include <string.h>
void *memset(void *s, int c, unsigned long n);
memset(s,0,3000);
函数的功能是:将指针变量 s 所指向的前 n 字节的内存单元用一个“整数” c 替换,注意 c 是 int 型。s 是 void* 型的指针变量,所以它可以为任何类型的数据进行初始化。
memset(s,0,3000);
将数组s的前3000个字节的内存单元全部初始化为0,即对数组进行清0
记忆: memset(s,0,sizeof(s));
结构体中的字符数组和字符指针
1)
C语言只有在定义字符数组的时候才能用“=”来初始化变量,其它情况下是不能直接用“=”来为字符数组赋值的,要为字符数组赋值可以用string.h头文件中的strcpy函数来完成。
例如:
char a[10] = “123”; /正确,在定义的时候初始化/
char a[10];
a = “123”; /错误,不能用“=”直接为字符数组赋值/
strcpy(a, “123”); /正确,使用strcpy函数复制字符串/
所以这里不能使用myFamilyAccout.details=”xx”;
补充:
用char c[20]定义的,用strcpy拷贝来赋值, strcpy(c, “123”);
用char *p定义的,用=来赋值,p=”iio”;(记得分配地址给指针)
struct mem
{
char name[20];
char name;
};
结构体中使用charname出现问题的解决方案:
char name[20];是有着自己连续的一块内存空间的
char *name;仅仅是个指针,是一个标记,没有分配用来保存字符串的空间
要使用指针,记得分配空间,不然肯定各种错误
有2种解决方案:
1、
char *name;
char n[20];
name=n;
2、
char *name;
name=(char *)malloc(sizeof(char)*20);
由于大小为20个字节,所以除了最后一位字符串结束标记外还可以存放19个字节。
前者效率高些,后者用完后可以用free()释放空间
案例
#include<stdio.h>
#include<stdlib.h>
#define NUM 2
struct mem
{char *name;char phone[10];
};
void main()
{struct mem man[NUM];char c[20];int i;for(i=0;i<NUM;i++){man[i].name=(char*)malloc(20*sizeof(char));//为结构体指针动态分配地址//方式2:新建立一个数组,让指针指向数组地址//man[i].name=c;printf("input name:\n");gets(man[i].name);printf("input phone:\n");gets(man[i].phone);}printf("name\t\t\tphone\n\n");for(i=0;i<NUM;i++){printf("%s\t\t\t%s\n",man[i].name,man[i].phone);free(man[i].name);//释放指针内存空间}getchar();
}