分享:菜鸟的练习--我的第一个小板凳

来源:互联网 发布:淘宝直播卖玉是真的吗 编辑:程序博客网 时间:2024/03/29 02:14

 

声明本人是超级菜鸟,高手看到不要见笑:)

 

十一前的一段时间又重新看了下C,于是就想利用假期写一个稍微大一点的东西,作为锻炼。

后来就决定写一个简单的族谱管理的小东西。

 

于是就有了这个百恶俱全,一无善处的小东西,基本上应该有的毛病一样不落,是一个非常典型的反面教材。

 

但是,即便这样,通过这个小小的实践,也让我受益匪浅,特别是对高内聚低耦合有了一些切肤的了解。

 

最大的一个收获就是要多加练习….

 

在此特别感谢我的老婆,在假期期间陪我宅在家中,没有任何怨言^_^

 

感谢曾经一生,没有他这个小小的东西甚至不会出现,特别感谢他为这个小东西做的一个界面可惜我现在这个版本的还没有加上他写的界面。

 

也感谢论坛的朋友:omegabombsenr0816aifei521jackyjkchensupermegaboy, brookmill, wanjingwei, aizibion. 排名不分先后:) 如果没有他们的指点这小东西十有八九会太监…

 

下面写一下做这个东西之前的一些个人心理路程吧。

 

开始的时候我想的很简单,就是把在控制台输入的东西输入到文本,然后从文本中读出来就OK了。这样就会有一个问题就是如何在文件中定位,我偷偷的翻了下书,这时候老毛病犯了,无论如何看不下去…心里跟小猫挠似地。后来我就想,就不要定为了,每次加载文件的时候把所有的内容都读取到内存中,修改增加或者删除内容之后就用内存中的数据再完全覆盖掉原来的文件。这样就避开了在文件中定位这个令我头大的问题,这个时候我决定使用文本模式。文本模式里面怎么区分个人的信息呢,我就想一行表示一个人,个人之间的信息用@号分隔,方便读取。

 

这个时候其实我已经想好了用结构数组来存储数据。

 

然后简单的想了一下应该设置的内容,姓名,性别,配偶,出生年月 ,排行,父母,死亡年月,然后想到世。(后来用strlen(DNAID)/2 来计算世。)

 

基本的想法有了,就开始实际的拼凑代码主要是太菜

 

---------------------------------------------------------------下面是一些过程--------------------------------

实现功能

1.    实现基本信息输入功能;

2.    要实现信息的查询、修改、删除、等功能;

3.    将信息保存至文本中;(要确保信息的完备性);

4.    将修改信息可以使用保存选项存储起来;(重要功能)

 

实现方法

1.    定义一个结构数组;

2.    读取数据文档,将数据保存在结构数组中;

3.    通过对数组的基本操作实现信息的增删改查等功能;

4.    保存的时候将结构数组中的数据保存到临时文本,然后删除旧的文本,将新文本重命名为旧文本名字;

【此方法的优缺点:不需要在文件中定位,比较简单。缺点:占用大量内存。】

需准备知识

1.    结构;

2.    数组;

3.    结构数组;

4.    文件访问(处理文件);

5.    函数;(递归函数)

6.    指针;

 

实现步骤

1.    菜单:

R(Root)     进入设置祖先模式;

A(Add)      进入输入信息模式;

C(Chenge)   进入修改模式;

D(Delete) 进入删除信息模式;

S(Select) 进入搜索模式;(1.查某人资料2.查某人兄弟姐妹资料3.查某人儿子资料4.查某人所有后代资料 5.查父亲资料);

H(Hold)   保存;

结构数组

1.    struct Family_People

{   

  char name[20];/*存放姓名*/

  char sex[4];/*存放性别*/

  char spouse_name[20];/*存放配偶姓名*/

char father_name[20];/*父亲名字*/

  char mother_name[20];/*母亲名字*/

  char birth_year[6];/*出生年*/

  char birth_moon[4];/*出生月*/

char birth_day[4];/*出生日*/

char DNAID[200];/*身份识别码*/

char Ancestors[4];/*如果Ancestors ='y'则表示先祖,一个族谱系统只能有一个先祖*/

/*char notes[20000];备注*/

  };

关于身份识别码:

DNAID作用是存放身份识别码,祖先用00表示,祖先的后代用0001,0002,0003表示其中0001中的01表示家庭排行;通过这种方式可以很方便的追踪需要的各种信息。

 

DNAID的设置,如果不能找到他的父亲的名字则提出警告,让其重新输入父名字。

 

如何设置祖先。设置祖先选项和其它增加选项不同,为独立的系统,选择这个系统之后祖先之后不必设置father_name,系统将DNAID设置为00;

 

读取数据文件,如果不存在Ancestors==’y’的值,则执行设置祖先函数;

 

@表示分割元数据;#表示一行结束;char * strtok (char * str, const char * delimiters);

 

2.       struct Family_People Index_List[100]

Index_List[0]

 

 

 

过程

1.首先编写void Fun_Set(void)函数,调用此函数则会在指定文本中写入输入数据;

  (开发过程中遇到的问题:如何打开文件,如何向文件中写入数据。目前设计进度,完成基本功能,数据校验部分未涉及)

 

2.编写int Fun_Get(struct Family_People *Stu);完成功能:从文本中读取数据,并保存到struct Family_People Stu[X]中;

  (开发中遇到的问题。由于对构造类型数组了解不够,开始的时候不知道如何将数据返回给主函数。造成一定困扰。其次如何从文本中循环读取数据,并将数据存放到构造类型数组中也有一定困扰,原因是对语法掌握不熟练,while语句和if语句。while语句后面多了一个分号,if-else if -else 语句的语法搞成if if if 。一方面是对语法的本质了解不透,另一方面也是因为练习过少导致。特别需要注意的是,一定要细心。任何粗心大意都会导致很郁闷的错误),此函数返回Stu数组中元素的个数;

 

3.实现了最基本的两项功能以后,编写查找函数void Fun_Select(struct Family_People *Fam,int element_num);(查找函数比较简单,首先执行Fun_Get函数, 然后在数组中执行查找即可)element_num就是 Fam数组中元素的个数;

 

4.编写一递归函数,完成功能,搜索输入姓名的所有子孙后代。并以图表形式显示。设计思路

void select_all(struct Family_People *Fam,int element_num,char *name)

{

 

for(i=0;i<element_num;i++)

 {

   if((strcmp(Fam[i].father,name))==0)

     {

         printf("%s",Fam[i].name);

         select_all(Fam,element_num,Fam[i].name);

      }//end if 

 }//end for

}//end select_all

 

 

5.修改void Fun_Set(void)函数,使其接受形参。void Fun_Set(struct Family_People *Fam,int element_num);

 

6.增加自动添加DNAID,和世系。编写函数int Fun_Select_Sub(struct Family_People *Fam,int element_num,char *select_name),void itoa_me(int n,char *s)。修改Fun_Set函数。

 

 

7.设计表格化输出:

   printf("|-------|------|-------|-------|-------|----------|------|----------|----|/n");

   printf("| 姓名  | 性别 |  配偶 | 父亲  | 母亲  | 生    日 | 排行 | 故去     | 世 |/n");

   printf("|-------|------|-------|-------|-------|----------|------|----------|----|/n");

   printf("|%-7s|%-6s|%-7s|%-7s|%-7s|%-10s| %-5s|%-10s| %-3s|/n",Fam[i].name,Fam[i].sex,Fam[i].spouse_name,Fam[i].father_name,Fam[i].mother_name,Fam[i].birthday,Fam[i].top,Fam[i].deathday,Fam[i].generation);

   printf("|-------|------|-------|-------|-------|----------|------|----------|----|/n");

 

设置文字输出显示颜色,使用函数void textcolor(int color)失败

 

8.计划添加函数祖先增加模式;祖先模式包括一个拷贝函数,将现有的文件复制;

 

9.未完成功能包括,删除函数,修改函数,保存函数;(删除函数就是将其Fam[i].name设置为"",然后用一个循环将内存中的数据存到文本中)修改函数需要一个查找儿子函数以便更改姓名的同时,更改受其影响的儿子信息,同时需要一个查询其所有后代的函数,以便更新受其影响的DNAID,同事修改函数还需要将内存中的数据存储到myfile.txt中。

 

删除函数需要注意事项。删除此某人就是将某人这房全部删掉,谨慎使用。首先将所有相关姓名置空,然后用保存函数保存,再从文本中读入内存。

 

10.计划实现动态分配内存。技术储备已完成。

 

曾经一生:

1:新创建一个族谱。

2:加载一个族谱文件。

3:退出。

---------------------------------一级菜单。

当内存中存在族谱树时,也就是在新创建或是加载一个族谱树后。

显示以下菜单:

1:保存。

2:添加一个成员。

3:删除一个成员。

4:查找一个成员。

5:修改某个成员的信息。

6:在屏幕上输出全部成员的信息。

7:退出。

-----------------------------------二级菜单。

 

内部要求:要求将家谱信息看作树形结构处理,并可存储在外存。数据可一次读入内存;外部要求:这一级要求系统具备下列基本功能。A)家庭成员信息存储:将每个家庭成员的基本信息存储在计算机中(可永久保存)。家庭成员的基本信息至少应包括:(姓名,出生地,出生日期,死亡日期,性别,身高,学历,职业,最高职务/职称,…);B)家族关系存储:将各家庭成员之间的关系,存储在计算机中(可永久保存);C)更新:家谱数据的更新(修改、删除、加入);D)输出:将家谱以较友好的格式输出(显示);E)查询:按基本信息查询成员,按亲戚关系查询

 

注意事项:

1.认真细心。

--------------------------------------------------------------------

下面是源代码: