通讯录
1.前言
通过C语言进阶的学习,我们了解了结构体、枚举、动态内存分配和文件操作,现在通过这些知识来实现一个通讯录,达到对近期学习的总结。
2.要求
- 实现一个通讯录,存储联系人的信息,这些信息包括联系人的姓名、年龄、性别、地址、电话
- 添加联系人的信息
- 删除指定联系人的信息
- 查找指定联系人的信息
- 修改指定联系人的信息
- 显示所有联系人的信息
- 对联系人进行排序(按照年龄/姓名)
- 动态增长空间
- 在退出通讯录的时候把信息到保存到文件中
- 在通讯录打开的时候,可以把文件中的信息加载到通讯录中
第9、10项可以先忽略,在实现前8项后可以在其基础上进行修改。
3.实现
3.1准备
创建一个模块(contact.h和contact.c)和一个测试文件(test.c),contact.h实现对函数的声明,contact.c实现通讯录,test.c测试通讯录
3.2菜单
- 提供菜单,提供选择
- do while循环不管判断条件先执行一次,可以提供选择(是继续还是退出)
- input作为判断条件,当其为0时,循环停止,刚好对应退出通讯录
注意
这里写错了,menu函数必须在选择前。
3.3选择
- 根据不同的选择,提供不同的函数
- 使用枚举,对应不同的选择
注意
menu函数必须在选择前,这里写错了。
3.4联系人信息
- 结构体在test.c和contact.c中将被使用,为了方便,结构体直接定义在头文件,再在两源文件引用头文件就可以使用同一个结构体。因此库函数的头文件直接在contact.h中包含即可
- 我们在进行增加、删除、查找这些操作时,都需要了解当前通讯录的人数,所以再次创建一个结构体,其包括当前通讯录的人数、people类型的指针和当前通讯录的最大容量。
疑惑
(1)为什么需要people的指针?不直接创建一个数组来存储不是更简单?
一是people很大,更何况是由其组成的数组,如果有100个联系人就需要创建100元素的数组,如果更大呢?所以包含一个只有4字节或8字节的指针能节省空间;
二是用数组来记录联系人的信息,我们创建数组的元素个数是100,但如果只有15个联系人岂不是浪费很大空间,如果有200个联系人,空间岂不是又不够。所以只使用动态内存分配来分配空间,当不够时就扩容,当空间太大就缩小。使用动态内存开辟返回开辟空间的起始地址,所以用指针来接收。
(2)为什么包含当前通讯录的最大容量?
当通讯录人数达到当前最大容量时,可以进行扩容。
3.5初始化通讯录
疑惑
(1)为什么传地址?
还是为了节省空间,我们知道结构体存在内存对齐,这就意味着会浪费一些字节的空间,所以干脆将其指针传过去,函数形参只占4/8字节。
(2)为什么不直接初始化?
可能会对通讯录初始化时进行其他操作。
初始化通讯录
(1)我们将最初的最大容量定义为3,以后每次扩容增加的容量定义为2。
(2)记得函数在contact.h中声明,在contact.c中实现。其中,动态内存开辟可能失败,记得判断返回值是否是空指针。(后面不再提醒)
疑惑
好像只是开辟了空间,并没有对其进行初始化?
其实calloc开辟空间后,同时会将其初始化为0。这也是我为什么用calloc。
3.6增加联系人
增加联系人
(1)判断是否达到最大容量
(2)增加联系人
con->num恰好可以作为“数组下标”
3.7显示所有联系人信息
先实现这个功能,看看增加联系人后的效果
显示联系人
疑惑
在打印中,负号表示向左边对齐,数字限定打印的范围。
3.8查找指定联系人
先查找再删除,所以先实现这个功能
查找联系人
3.8删除指定联系人信息
删除联系人
3.9修改指定联系人信息
修改联系人
3.9排序联系人信息
排序联系人信息
qsort是快速排序函数,我在前面讲过qsort。
3.10释放申请的空间
4.优化
我们每次执行代码时,都得重新输入数据,在我们关闭程序时这些数据又都会消失。有什么办法解决这个问题?
4.1在退出通讯录的时候把信息到保存到文件中
4.2在通讯录打开的时候把文件中的信息加载到通讯录中
5.总结
实现通讯录用到了结构体、枚举、动态内存、文件的写入和读取以及各种各样的函数,有助于加强对C语言进阶知识的理解和掌握。
相较于扫雷和三子棋,通讯录简单点,但仍有不足,希望指正!谢谢!