顺序表实现通讯录项目

上次我们实现了顺序表的增删查改等操作

这次我们在基于顺序表的基础上实现通讯录项目

上次顺序表中我们是对整型数据进行操作,而如果我们要实现通讯录,就需要存放不同的联系人数据,但是要存放联系人数据应该要怎么做呢?没错,我们可以使用结构体类型。

首先,我们在顺序表的基础上再增加一个Contact.h的头文件和一个Contact.c的源文件。同时在SeqList.h的头文件中包含Contact.h的头文件。

我们定义一个结构体类型struct PersonInfo来存放联系人的数据

还记得在SeqList.h的头文件中我们将int类型重定义为SLDataType,那么现在我们要在顺序表中存放的不再是整型,而是结构体类型,所以我们直接将int修改为struct PersonInfo。

同时我们之前SeqList.c源文件中实现的查找方法和打印方法要注释掉,因为在打印方法中,我们打印的是整型数字,但现在我们要打印的是联系人数据,同理在查找方法中,我们要查找的数据是结构体类型,两个结构体类型的数据不能直接进行比较。所以我们先给他注释掉,避免运行出现错误。

我们接下来要完成哪些操作呢?

其实和顺序表是类似的,如下:

//初始化通讯录
void InitContact(contact* con);
//添加通讯录数据
void AddContact(contact* con);
//删除通讯录数据
void DelContact(contact* con);
//展示通讯录数据
void ShowContact(contact* con);
//查找通讯录数据
void FindContact(contact* con);
//修改通讯录数据
void ModifyContact(contact* con);
//销毁通讯录数据
void DestroyContact(contact* con);

我们要先在Contact.h的头文件中进行声明

但是我们可以看到编译器在这里报错了,为什么呢?原因是编译器在Contact.h的头文件中,不认识这个contact,为什么不认识呢?因为这个是未定义标识符,我们既没有声明也没有包含与这个有关的头文件。我们要知道通讯录本质其实是以顺序表为底层,进行封装来实现的。所以应该是顺序表中的SL* sl。

此时编译器就没有报错,但是如果我们这样写的话容易造成误会,所以我们为它改个名,我们可以利用tepedef进行前置声明为contact。

现在就不会报错了!


通讯录的初始化

其实就是顺序表的初始化,我们这里可以直接调用SeqList.c中的SLInit函数进行通讯录的初始化

通讯录的销毁

同初始化一样,直接调用顺序表的销毁就行。

我们来调试一下看看:


通讯录的增删查改

1.添加通讯录数据

我们在scanf输入数据时,可以直接创建一个结构体变量info用来存放联系人的数据,保存完数据在info之后,我们可以把数据插入到顺序表中(之前讲到过头插尾插还有指定插入,我们这里都可以,推荐使用尾插,因为数据是按照输入顺序排序的),注意这里的con 和info两个参数,是将输入在info中的数据插入到顺序表con中。

我们来调试一下:


2.删除通讯录数据

在删除之前我们要先查找联系人数据,一般都是通过姓名查找联系人,创建一个字符数组name来存放输入的联系人姓名,这里为什么是字符数组name而不是结构体info呢?原因是我们只需要存放姓名,不需要存放其他数据,而且在我们通过姓名查找时,循环遍历顺序表中的每一组数据,通过strcmp字符函数比较输入的字符和在顺序表中的字符的返回值来判断找没找到,找到了就返回下标,没找到就返回-1,找到时我们可以通过返回的下标来完成指定删除,所以我们直接调用SLErase函数来完成对通讯录中的数据进行删除。

这里为方便测试我们先将通讯录的展示完成,我们先将表头打印出来,然后再循环打印顺序表中的每组数据

我们来运行测试一下:


3.修改通讯录数据

先输入要修改的联系人姓名存放在字符数组name中,修改前需要先查找,如果该联系人存在则直接修改,输入新的姓名 性别 年龄 电话 地址存放在顺序表中。

测试运行一下


4.查找通讯录数据

查找和修改、删除类似,如果我们成功找到该数据,直接将该联系人数据打印出来,怎么直接打印呢?很简单,我们通过Findbyname函数能够获得该联系人在顺序表中的下标,得到下标就能直接打印了。

测试运行一下:


基本功能实现好之后,我们现在来制作一下通讯录的菜单

这里我们就不细讲了,直接上图:

到了这里,我们已经完成了通讯录的功能,但是这里我们可以发现我们每次运行时,数据都会丢失,我们每次运行都需要重新输入数据,这不仅繁琐,而且不能长时间存放数据,用完就会销毁。

那我们有没有什么办法来防止数据丢失呢?这里我们可以使用文本操作来保存数据。

文本操作

1.读取数据

我们使用fopen以二进制读的形式(rb)打开contact.txt文件,返回的地址存放在pf中(文本操作使用的是FILE*的指针),然后再循环读取数据,fread函数的返回值是成功读取的元素总数,还有四个参数,分别是void* ptr ,ptr是指向要接收数据的缓存区的指针,我们这里要接收的是从pf中读取的数据,所以我们要&info取出info的地址存放在ptr中接收pf中的地址(获取其中的数据);size_t size则是每次读取的字节数,我们这里读取存放数据的结构体的大小;size_t count是读取的元素个数,我们这里读取一个结构体;FILE* stream是指定读取数据的文件流,这里我们从FILE*pf中读取数据。

我们是不是可以在初始化后,将通讯录中的数据读取出来呢,我们每读取一次,就使用尾插(直到读取为空时fread返回0就跳出循环了),将info中读取到的数据插入到顺序表中,这样就能将上次输入在通讯录的数据保存在文件中以便在下次操作时插入到顺序表中,完成将历史数据导入到通讯录,这样数据就不会丢失了

2.写入数据

写入数据和读取数据是类似的,只不过我们是将顺序表中的数据通过fwrite写入到pf文件中保存起来。两者的区别是前者fread是从FILE* stream中读取数据到void* ptr中,而fwrite则是将void* ptr中的数据写入到FILE* stream中。

所以,我们也可以在销毁前将输入完成后的数据写入到文件中保存起来,这样就可以在下次调用通讯录功能时,将联系人数据从文件中读取出来。

最后我们来运行看看:

这里我们添加了两个联系人数据,我们再次运行展示联系人看看数据有没有丢失。

数据保存下来了,并没有丢失。

OK,到这里我们通讯录项目也算是完成了!

  • 23
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值