目录
一、引言
在现代生活中,联系人信息管理已经成为人们日常生活中不可或缺的一部分。无论是工作还是社交,能够高效地管理联系人信息如姓名、性别、年龄、电话和地址等,都是一项重要的技能。为了解决这一需求,本文将带领大家一步步实现一个简单的通讯录管理系统,使用C语言编写,以便于存储、管理和查询联系人信息。
二、需求分析
1. 项目概述
本通讯录管理系统旨在提供一个友好的用户界面,允许用户对联系人信息进行增删改查等操作。同时,为了确保数据的持久化,系统还将支持将数据保存到文件中,以便在下次启动程序时能够恢复之前的联系人信息。
2. 功能需求
系统的基本功能需求包括:
-
添加联系人:允许用户输入并保存新的联系人信息。
-
删除联系人:根据姓名删除已存在的联系人信息。
-
修改联系人:对已存在的联系人进行信息修改。
-
查询联系人:根据姓名查询特定联系人的详细信息。
-
展示联系人:以列表形式展示所有已保存的联系人信息。
-
加载数据:程序启动时从指定文件加载历史联系人数据。
-
保存数据:在程序关闭前将当前联系人数据持久化到文件中。
3. 数据结构设计
为了有效存储联系人信息,我们定义了一个名为personInfo
的结构体,包含以下字段:
typedef struct personInfo
{
char name[NAME_MAX];//姓名
char gender[GENDER_MAX];//性别
int age;//年龄
char tel[TEL_MAX];//电话号码
char address[ADDRESS_MAX];//地址
}Per;
此结构体将帮助我们组织和存储每位联系人的信息。
三、功能设计
1. 初始化通讯录
初始化通讯录管理系统,为后续的操作做准备。
//初始化
void ContactInit(Con* p)
{
p->arr = NULL;
p->size = p->capacity = 0;
}
2. 添加联系人
用户可以通过输入相关信息添加新的联系人。该功能的实现需要检查当前容量,确保不会因为数组溢出导致程序崩溃。
//检查容量
void checkcapacity(Con* p)
{
if (p->size == p->capacity)
{
int newcapacity = p->capacity == 0 ? 4 : 2 * p->capacity;
DataType* tmp = (DataType*)realloc(p->arr, newcapacity * sizeof(DataType));
if (tmp == NULL)
{
perror("realloc fail");
exit(1);
}
//空间申请成功
p->arr = tmp;
p->capacity = newcapacity;
}
}
//顺序表尾插
void SLPushBack(Con* p, DataType x)
{
assert(p);
checkcapacity(p);
p->arr[p->size++] = x;
}
//添加数据
void ContactAdd(Con* p)
{
Per info;
printf("请输入要添加的联系人姓名:\n");
scanf("%s", info.name);
printf("请输入要添加的联系人性别:\n");
scanf("%s", info.gender);
printf("请输入要添加的联系人年龄:\n");
scanf("%d", &info.age);
printf("请输入要添加的联系人电话:\n");
scanf("%s", info.tel);
printf("请输入要添加的联系人地址:\n");
scanf("%s", info.address);
SLPushBack(p, info);
printf("添加成功!\n");
}
接下来,通过ContactAdd
函数实现添加联系人的具体逻辑。
void ContactAdd(Con* p) { Per info; printf("请输入要添加的联系人姓名:\n"); scanf("%s", info.name); printf("请输入要添加的联系人性别:\n"); scanf("%s", info.gender); printf("请输入要添加的联系人年龄:\n"); scanf("%d", &info.age); printf("请输入要添加的联系人电话:\n"); scanf("%s", info.tel); printf("请输入要添加的联系人地址:\n"); scanf("%s", info.address); SLPushBack(p, info); printf("添加成功!\n"); }
3. 删除联系人
删除联系人需要首先查找指定姓名的联系人是否存在,然后执行删除操作。
//查找数据
int FindByName(Con* p, char name[])
{
for (int i = 0; i < p->size; i++)
{
if (strcmp(p->arr[i].name, name) == 0)
return i;//找到了
}
return -1;//没有找到
}
//删除数据
void ContactDel(Con* p)
{
//前提是数据必须存在才能删除---查找数据是否存在
char name[NAME_MAX];
printf("请输入要删除的联系人姓名:\n");
scanf("%s", name);
int find = FindByName(p, name);
if (find < 0)
{
printf("要删除的联系人不存在!\n");
return;
}
SLErase(p, find);
printf("删除成功!\n");
}
4. 修改联系人
修改联系人的信息与删除联系人类似,首先需要查找联系人是否存在。
//查找数据
/*
int FindByName(Con* p, char name[])
{
for (int i = 0; i < p->size; i++)
{
if (strcmp(p->arr[i].name, name) == 0)
return i;//找到了
}
return -1;//没有找到
}
*/
//通讯录的修改
void ContactMod(Con* p)
{
//前提是数据必须存在才能修改---查找数据是否存在
char name[NAME_MAX];
printf("请输入要修改的联系人姓名:\n");
scanf("%s", name);
int find = FindByName(p, name);
if (find < 0)
{
printf("要修改的联系人不存在!\n");
return;
}
//直接修改
printf("请输入修改后的姓名:\n");
scanf("%s", p->arr[find].name);
printf("请输入修改后的性别:\n");
scanf("%s", p->arr[find].gender);
printf("请输入修改后的年龄:\n");
scanf("%d", &p->arr[find].age);
printf("请输入修改后的电话:\n");
scanf("%s", p->arr[find].tel);
printf("请输入修改后的地址:\n");
scanf("%s", p->arr[find].address);
printf("修改成功!\n");
}
5. 查询联系人
查询联系人的实现需要调用前面定义的查找函数。
//查找数据
/*
int FindByName(Con* p, char name[])
{
for (int i = 0; i < p->size; i++)
{
if (strcmp(p->arr[i].name, name) == 0)
return i;//找到了
}
return -1;//没有找到
}
*/
void ContactFind(Con* p)
{
char name[NAME_MAX];
printf("请输入要查找的联系人姓名:\n");
scanf("%s", name);
int find = FindByName(p, name);
if (find < 0)
{
printf("要查找的联系人不存在!\n");
return;
}
printf("%s\t%s\t%s\t%s\t\t%s\t\n", "姓名", "性别", "年龄", "电话", "地址");
printf("%s\t%s\t%d\t%s\t%s\t\n",
p->arr[find].name,
p->arr[find].gender,
p->arr[find].age,
p->arr[find].tel,
p->arr[find].address
);
}
6. 展示所有联系人
该功能可以一次性展示所有已保存的联系人,方便用户查看。
//展示通讯录
void ContactShow(Con* p)
{
//表头:姓名 性别 年龄 电话 地址
printf("%s\t%s\t%s\t%s\t\t%s\t\n", "姓名", "性别", "年龄", "电话", "地址");
for (int i = 0; i < p->size; i++)
{
printf("%s\t%s\t%d\t%s\t%s\t\n",
p->arr[i].name,
p->arr[i].gender,
p->arr[i].age,
p->arr[i].tel,
p->arr[i].address
);
}
}
7. 保存数据到文件
程序在关闭前需要将当前数据保存到文件中,以便下次使用。
//将数据保存到文件中
void SaveContact(Con* p) {
FILE* pf = fopen("contact.txt", "wb");
if (pf == NULL) {
perror("fopen error!\n");
return;
}
//将通讯录数据写入文件
for (int i = 0; i < p->size; i++)
{
fwrite(p->arr + i, sizeof(Per), 1, pf);
}
printf("通讯录数据保存成功!\n");
}
8. 加载数据
在程序启动时自动加载历史数据。
//从文件读取历史数据
void LoadContact(Con* p) {
FILE* pf = fopen("contact.txt", "rb");
if (pf == NULL) {
perror("fopen error!\n");
return;
}
//循环读取文件数据
Per info;
printf("正在导入历史数据...\n");
Sleep(1000);
while (fread(&info, sizeof(Per), 1, pf))
{
SLPushBack(p, info);
}
printf("历史数据导入通讯录成功!\n");
system("pause");
system("cls");
}
四、完整代码
1.Contact.h
#pragma once
#define NAME_MAX 20
#define GENDER_MAX 10
#define TEL_MAX 20
#define ADDRESS_MAX 100
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<string.h>
#include<windows.h>
//定义结构体存储个人信息(自定义类型)
typedef struct personInfo
{
char name[NAME_MAX];
char gender[GENDER_MAX];
int age;
char tel[TEL_MAX];
char address[ADDRESS_MAX];
}Per;
typedef Per DataType;//这里类型为自定义类型Per
//通讯录:底层为顺序表
typedef struct Contact
{
DataType* arr;
int size;//有效数据个数
int capacity;//容量
}Con;
//初始化通讯录
void ContactInit(Con* p);
//销毁通讯录
void ContactDestroy(Con* p);
//展示通讯录
void ContactShow(Con* p);
//添加数据
void ContactAdd(Con* p);
//删除数据
void ContactDel(Con* p);
//通讯录的修改
void ContactMod(Con* p);
//通讯录的查找
void ContactFind(Con* p);
//从文件读取历史数据
void LoadContact(Con* p);
//将数据保存到文件中
void SaveContact(Con* p);
2.Contact.c
#define _CRT_SECURE_NO_WARNINGS
#include"Contact.h"
//初始化
void ContactInit(Con* p)
{
p->arr = NULL;
p->size = p->capacity = 0;
}
//销毁
void ContactDestroy(Con* p)
{
if (p->arr)
{
free(p->arr);
}
p->arr = NULL;
p->size = p->capacity = 0;
}
//检查容量
void checkcapacity(Con* p)
{
if (p->size == p->capacity)
{
int newcapacity = p->capacity == 0 ? 4 : 2 * p->capacity;
DataType* tmp = (DataType*)realloc(p->arr, newcapacity * sizeof(DataType));
if (tmp == NULL)
{
perror("realloc fail");
exit(1);
}
//空间申请成功
p->arr = tmp;
p->capacity = newcapacity;
}
}
//顺序表尾插
void SLPushBack(Con* p, DataType x)
{
assert(p);
checkcapacity(p);
p->arr[p->size++] = x;
}
//删除指定位置的数据
void SLErase(Con* p, int pos)
{
assert(p);
assert(pos >= 0 && pos < p->size);
for (int i = pos; i <= p->size - 2; i++)
{
p->arr[i] = p->arr[i + 1];
}
p->size--;
}
//添加数据
void ContactAdd(Con* p)
{
Per info;
printf("请输入要添加的联系人姓名:\n");
scanf("%s", info.name);
printf("请输入要添加的联系人性别:\n");
scanf("%s", info.gender);
printf("请输入要添加的联系人年龄:\n");
scanf("%d", &info.age);
printf("请输入要添加的联系人电话:\n");
scanf("%s", info.tel);
printf("请输入要添加的联系人地址:\n");
scanf("%s", info.address);
SLPushBack(p, info);
printf("添加成功!\n");
}
//查找数据
int FindByName(Con* p, char name[])
{
for (int i = 0; i < p->size; i++)
{
if (strcmp(p->arr[i].name, name) == 0)
return i;//找到了
}
return -1;//没有找到
}
//删除数据
void ContactDel(Con* p)
{
//前提是数据必须存在才能删除---查找数据是否存在
char name[NAME_MAX];
printf("请输入要删除的联系人姓名:\n");
scanf("%s", name);
int find = FindByName(p, name);
if (find < 0)
{
printf("要删除的联系人不存在!\n");
return;
}
SLErase(p, find);
printf("删除成功!\n");
}
//展示通讯录
void ContactShow(Con* p)
{
//表头:姓名 性别 年龄 电话 地址
printf("%s\t%s\t%s\t%s\t\t%s\t\n", "姓名", "性别", "年龄", "电话", "地址");
for (int i = 0; i < p->size; i++)
{
printf("%s\t%s\t%d\t%s\t%s\t\n",
p->arr[i].name,
p->arr[i].gender,
p->arr[i].age,
p->arr[i].tel,
p->arr[i].address
);
}
}
//通讯录的修改
void ContactMod(Con* p)
{
//前提是数据必须存在才能修改---查找数据是否存在
char name[NAME_MAX];
printf("请输入要修改的联系人姓名:\n");
scanf("%s", name);
int find = FindByName(p, name);
if (find < 0)
{
printf("要修改的联系人不存在!\n");
return;
}
//直接修改
printf("请输入修改后的姓名:\n");
scanf("%s", p->arr[find].name);
printf("请输入修改后的性别:\n");
scanf("%s", p->arr[find].gender);
printf("请输入修改后的年龄:\n");
scanf("%d", &p->arr[find].age);
printf("请输入修改后的电话:\n");
scanf("%s", p->arr[find].tel);
printf("请输入修改后的地址:\n");
scanf("%s", p->arr[find].address);
printf("修改成功!\n");
}
//通讯录的查找
void ContactFind(Con* p)
{
char name[NAME_MAX];
printf("请输入要查找的联系人姓名:\n");
scanf("%s", name);
int find = FindByName(p, name);
if (find < 0)
{
printf("要查找的联系人不存在!\n");
return;
}
printf("%s\t%s\t%s\t%s\t\t%s\t\n", "姓名", "性别", "年龄", "电话", "地址");
printf("%s\t%s\t%d\t%s\t%s\t\n",
p->arr[find].name,
p->arr[find].gender,
p->arr[find].age,
p->arr[find].tel,
p->arr[find].address
);
}
//从文件读取历史数据
void LoadContact(Con* p) {
FILE* pf = fopen("contact.txt", "rb");
if (pf == NULL) {
perror("fopen error!\n");
return;
}
//循环读取文件数据
Per info;
printf("正在导入历史数据...\n");
Sleep(1000);
while (fread(&info, sizeof(Per), 1, pf))
{
SLPushBack(p, info);
}
printf("历史数据导入通讯录成功!\n");
system("pause");
system("cls");
}
//将数据保存到文件中
void SaveContact(Con* p) {
FILE* pf = fopen("contact.txt", "wb");
if (pf == NULL) {
perror("fopen error!\n");
return;
}
//将通讯录数据写入文件
for (int i = 0; i < p->size; i++)
{
fwrite(p->arr + i, sizeof(Per), 1, pf);
}
printf("通讯录数据保存成功!\n");
}
3.main.c
#define _CRT_SECURE_NO_WARNINGS
#include"Contact.h"
void menu()
{
printf("***************通讯录***************\n");
printf("****1.添加联系人 2.删除联系人****\n");
printf("****3.修改联系人 4.查找联系人****\n");
printf("****5.展示联系人 0.退出并保存****\n");
printf("************************************\n");
}
int main()
{
Con con;//创建
ContactInit(&con);//初始化
LoadContact(&con);//导入历史数据
int option = -1;
int(*pfunc[6])(Con * p) = { 0,ContactAdd,ContactDel,ContactMod,ContactFind,ContactShow }; //转移表
do
{
menu();
printf("请选择你的操作:\n");
scanf("%d", &option);
//转移表开始
if (option >= 1 && option <= 6)//根据对应的option执行不同操作
{
(*pfunc[option])(&con);
}
else if (option == 0)
{
printf("退出通讯录!\n");
}
else
{
printf("输入有误,请重新选择!\n");
}
system("pause");
system("cls");//转移表末尾
//我用的是转移表写,也可以正常使用switch-case语句,使用switch语句就把转移表那段注释掉
/*switch (option)
{
case 1:
ContactAdd(&con);
system("pause");
system("cls");
break;
case 2:
ContactDel(&con);
system("pause");
system("cls");
break;
case 3:
ContactMod(&con);
system("pause");
system("cls");
break;
case 4:
ContactFind(&con);
system("pause");
system("cls");
break;
case 5:
ContactShow(&con);
system("pause");
system("cls");
break;
case 0:
printf("退出通讯录!\n");
break;
default:
printf("输入有误,请重新选择!\n");
system("pause");
system("cls");
break;
}*/
} while (option != 0);
SaveContact(&con);//保存数据到文件
ContactDestroy(&con);//销毁
return 0;
}
五、测试运行
菜单界面
添加联系人
展示联系人
六、总结
本文通过一个简单的通讯录管理系统,介绍了C语言在文件操作、结构体、函数等方面的应用。通过学习本文,读者可以掌握C语言编程的基本技巧,为以后的项目开发奠定基础。当然,这个通讯录管理系统还有许多可以优化的地方,比如增加联系人信息的排序、分页显示等功能,感兴趣的读者可以继续完善。