基于顺序表的C语言通讯录实现(含数据持久化)
在软件开发中,数据持久化是一个至关重要的功能。今天我们要分析的是一个基于顺序表实现的C语言通讯录程序,它不仅具备了基本的联系人管理功能,还实现了完整的数据持久化机制。这意味着用户的通讯录数据可以在程序关闭后依然保存,下次启动时自动恢复,大大提升了程序的实用性。基于顺序表的通讯录系统设计与实现-CSDN博客,这次是加入了通讯录的文件导入和保存。目录前言正文1. 整体架构设计2. 数据持久化实现数据加
前言
在软件开发中,数据持久化是一个至关重要的功能。今天我们要分析的是一个基于顺序表实现的C语言通讯录程序,它不仅具备了基本的联系人管理功能,还实现了完整的数据持久化机制。这意味着用户的通讯录数据可以在程序关闭后依然保存,下次启动时自动恢复,大大提升了程序的实用性。在本篇文章之前已经用顺序表实现了通讯录,链接如下:基于顺序表的通讯录系统设计与实现-CSDN博客,这次是加入了通讯录的文件导入和保存。
目录
正文
1. 整体架构设计
该通讯录程序采用经典的三层架构:
-
SeqList层:底层数据结构,提供动态数组管理
-
Contact层:业务逻辑层,处理通讯录的具体操作
-
Application层:用户界面层,提供交互接口
这种分层设计使得代码结构清晰,各模块职责明确,便于维护和扩展。
2. 数据持久化实现
数据加载机制
void LoadContact(Contact* con)
{
FILE* pf = fopen("contact.txt", "rb");
if (pf == NULL)
{
perror("fopen error!\n");
return;
}
//循环读取文件数据
peoInfo info;
while (fread(&info, sizeof(info), 1, pf))
{
SLPushBack(con, info);
}
printf("历史数据导入成功!\n");
}
技术特点:
-
使用二进制读取模式("rb"),高效直接
-
循环读取直到文件末尾,自动处理任意数量的联系人
-
文件不存在时给出友好提示,不会导致程序崩溃
-
无缝集成到现有架构中,使用
SLPushBack函数添加数据
数据保存机制
void SaveContact(Contact* con)
{
FILE* pf = fopen("contact.txt", "wb");
if (pf == NULL)
{
perror("fopen error!\n");
return;
}
//将通讯录数据写入文件
for (int i = 0; i < con->size; i++)
{
fwrite(&(con->arr[i]), sizeof(peoInfo), 1, pf);
}
printf("通讯录数据保存成功!\n");
}
技术特点:
-
使用二进制写入模式("wb"),保证数据格式一致
-
遍历整个顺序表,确保所有数据都被保存
-
覆盖式写入,保证文件内容与内存数据完全同步
-
明确的成功提示,让用户安心退出
3. 初始化与销毁流程
智能初始化
void ContactInit(Contact* con)
{
SLInit(con);
LoadContact(con);
}
初始化过程分为两步:
-
调用
SLInit初始化顺序表结构 -
调用
LoadContact加载历史数据
这种设计确保了程序启动时能够自动恢复之前的工作状态。
安全的销毁流程
void ContactDesTroy(Contact* con)
{
SaveContact(con);
SLDestroy(con);
}
销毁过程同样分为两步:
-
先保存数据到文件
-
再释放内存资源
这个顺序至关重要,确保了数据不会丢失。
4. 顺序表核心实现
动态容量管理
void SLCheckCapacity(SL* ps)
{
if (ps->capacity == ps->size)
{
int newCapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
SLDataType* tmp = (SLDataType*)realloc(ps->arr, newCapacity * sizeof(SLDataType));
if (tmp == NULL)
{
perror("realloc fail!");
exit(1);
}
ps->arr = tmp;
ps->capacity = newCapacity;
}
}
扩容策略分析:
-
初始容量:4个元素,避免过度分配
-
扩容倍数:每次翻倍,保证均摊时间复杂度为O(1)
-
错误处理:内存分配失败时安全退出
-
使用realloc:智能处理内存重新分配
高效的数据访问
void ContactShow(Contact* con)
{
printf("%-10s %-6s %-6s %-15s %-20s\n", "姓名", "性别", "年龄", "电话", "地址");
for (int i = 0; i < con->size; i++)
{
printf("%-10s %-6s %-6d %-15s %-20s\n",
con->arr[i].name,
con->arr[i].gender,
con->arr[i].age,
con->arr[i].tel,
con->arr[i].addr);
}
}
显示优化:
-
使用格式化输出,保证列对齐
-
左对齐显示,提高可读性
-
直接通过索引访问,时间复杂度O(1)
5. 业务逻辑实现
联系人查找功能
int FindByName(Contact* con, char name[])
{
for (int i = 0; i < con->size; i++)
{
if (0 == strcmp(con->arr[i].name, name))
{
return i;
}
}
return -1;
}
查找策略:
-
顺序查找,时间复杂度O(n)
-
使用
strcmp进行精确字符串匹配 -
返回索引位置,便于后续操作
联系人删除操作
void ContactDel(Contact* con)
{
char name[NAME_MAX];
printf("请输入要删除的联系人姓名:\n");
scanf("%s", name);
int find = FindByName(con, name);
if (find < 0)
{
printf("要删除的联系人数据不存在\n");
return;
}
SLErase(con, find);
printf("删除成功!\n");
}
删除流程:
-
通过姓名查找联系人
-
验证联系人是否存在
-
调用
SLErase执行删除操作 -
提供明确的用户反馈
联系人修改功能
void ContactModify(Contact* con)
{
char name[NAME_MAX];
printf("请输入要修改的联系人姓名:\n");
scanf("%s", name);
int find = FindByName(con, name);
if (find < 0)
{
printf("要删除的联系人数据不存在\n");
return;
}
// 直接修改数组中的元素
printf("请输入新的联系人的姓名:\n");
scanf("%s", con->arr[find].name);
// ... 其他字段修改
printf("修改成功!\n");
}
修改特点:
-
直接通过索引修改数组元素,效率高
-
原地修改,无需移动其他数据
-
提供完整的字段修改支持
6. 用户界面设计
清晰的菜单系统
void menu()
{
printf("******************************************\n");
printf("********* 通讯录 *********\n");
printf("********1.添加联系人 2.删除联系人******\n");
printf("********3.修改联系人 4.查找联系人******\n");
printf("********5.展示联系人 0.退出通讯录******\n");
printf("******************************************\n");
}
菜单设计简洁明了,功能划分清晰,用户可以直观地选择所需操作。
主程序循环
int main()
{
Contact con;
ContactInit(&con);
int n = 0;
do
{
menu();
printf("请输入你的选择:\n");
scanf("%d", &n);
switch (n)
{
case 1:
ContactAdd(&con);
break;
// 其他功能分支...
case 0:
printf("退出通讯录!\n");
break;
default:
printf("输入错误,请重新输入:\n");
break;
}
} while (n);
ContactDesTroy(&con);
return 0;
}
程序流程特点:
-
自动初始化,加载历史数据
-
循环菜单,支持连续操作
-
安全的退出处理,自动保存数据
-
完善的错误输入处理
7. 文件格式设计
程序采用二进制格式存储数据,具有显著优势:
// 写入:直接内存拷贝 fwrite(&(con->arr[i]), sizeof(peoInfo), 1, pf); // 读取:直接内存填充 fread(&info, sizeof(info), 1, pf)
二进制格式的优点:
-
高性能:无需数据格式转换
-
完整性:保持所有数据类型原样
-
紧凑性:相比文本格式更节省空间
-
一致性:读写操作完全对称
总结
技术亮点
-
完整的数据持久化:实现了数据的自动保存和加载
-
健壮的错误处理:文件操作和内存分配都有完善的错误处理
-
高效的数据结构:顺序表提供O(1)的随机访问能力
-
用户友好的界面:清晰的操作提示和反馈
-
模块化设计:各层职责明确,便于维护和扩展
性能分析
优势:
-
随机访问:O(1)时间复杂度
-
缓存友好:连续内存布局
-
尾插操作:均摊O(1)时间复杂度
-
数据展示:高效的顺序遍历
劣势:
-
插入删除:平均需要移动O(n)个元素
-
内存管理:扩容时可能需要数据复制
实际应用价值
这个通讯录程序已经具备了实际使用的基本条件:
-
数据安全:自动保存确保数据不丢失
-
操作简便:直观的菜单和提示
-
性能良好:能够快速处理常见操作
-
稳定可靠:完善的错误处理机制
扩展建议
虽然当前版本功能完整,但仍可进一步改进:
-
增量保存:每次修改后立即保存,避免退出时数据丢失风险
-
数据备份:支持多个通讯录文件和版本管理
-
搜索优化:实现按电话号码、地址等多条件查询
-
数据验证:添加输入数据的有效性检查
-
批量操作:支持联系人的批量导入导出
这个基于顺序表的通讯录实现不仅是一个优秀的数据结构教学示例,更是一个具备完整数据持久化功能的实用工具,很好地展示了C语言在系统编程和文件操作方面的强大能力。
更多推荐
所有评论(0)