一、引言
在日常生活中,我们经常需要管理大量的联系人信息,如姓名、性别、年龄、电话和地址等。为了方便地管理和查询这些信息,我们可以使用C语言编写一个通讯录管理系统。本文将带领大家一步步实现这个系统。
二、需求分析
1.项目概述
通讯录管理系统是一款用于存储、管理和操作联系人信息的程序。该系统允许用户添加、删除、修改、查找和展示联系人,并将数据持久化到文件中,以便在程序重新启动时可以恢复数据。
2.功能需求
添加联系人:允许用户添加新的联系人信息 删除联系人:根据用户输入的联系人姓名,删除对应的联系人信息。
修改联系人:允许用户修改已添加的联系人信息。 查询联系人:根据用户输入的联系人姓名,查询对应的联系人信息。
显示联系人:显示所有已添加的联系人信息。 加载数据:在程序启动时,系统需要从指定的文件中读取联系人数据,并恢复通讯录的状态。
保存数据: 在程序关闭前,系统需要将当前通讯录数据持久化到文件中,以便在下次启动程序时可以恢复数据。
3.数据结构设计
为了存储联系人信息,我们定义一个结构体如下:
代码语言:javascript复制typedef struct personInfo
{
char name[NAME_MAX];//姓名
char gender[GENDER_MAX];//性别
int age;//年龄
char tel[TEL_MAX];//电话号码
char address[ADDRESS_MAX];//地址
}Per;
三、功能设计
1.初始化通讯录
初始化通讯录管理系统,准备接收用户操作。
代码语言:javascript复制//初始化
void ContactInit(Con* p)
{
p->arr = NULL;
p->size = p->capacity = 0;
}
2. 添加联系人
提示用户输入联系人的姓名、性别、年龄、电话和地址。 提示用户添加成功。
代码语言:javascript复制//检查容量
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");
}
3. 删除联系人
提示用户输入要删除联系人的姓名。 在通讯录文件中查找对应的联系人。 如果找到,删除该联系人的信息,并提示用户删除成功。 如果未找到,提示用户联系人不存在。
代码语言:javascript复制//查找数据
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. 修改联系人
提示用户输入要修改联系人的姓名。 在通讯录文件中查找对应的联系人。 如果找到,允许用户修改联系人的信息,并提示用户修改成功。 如果未找到,提示用户联系人不存在。
代码语言:javascript复制//查找数据
/*
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. 查询联系人
提示用户输入要查询联系人的姓名。 在通讯录中查找对应的联系人。 如果找到,显示该联系人的详细信息。 如果未找到,提示用户联系人不存在。
代码语言:javascript复制//查找数据
/*
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("%st%st%st%stt%stn", "姓名", "性别", "年龄", "电话", "地址");
printf("%st%st%dt%st%stn",
p->arr[find].name,
p->arr[find].gender,
p->arr[find].age,
p->arr[find].tel,
p->arr[find].address
);
}
6. 展示所有联系人
读取通讯录中的所有联系人信息。 在屏幕上以表格形式展示所有联系人信息。
代码语言:javascript复制//展示通讯录
void ContactShow(Con* p)
{
//表头:姓名 性别 年龄 电话 地址
printf("%st%st%st%stt%stn", "姓名", "性别", "年龄", "电话", "地址");
for (int i = 0; i < p->size; i )
{
printf("%st%st%dt%st%stn",
p->arr[i].name,
p->arr[i].gender,
p->arr[i].age,
p->arr[i].tel,
p->arr[i].address
);
}
}
7. 保存文件
在程序退出前,保存所有更改到通讯录文件。
代码语言:javascript复制//将数据保存到文件中
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. 加载数据
程序启动时,自动加载通讯录文件中的历史数据。 如果文件不存在或为空,则初始化一个空的通讯录。
代码语言:javascript复制//从文件读取历史数据
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
代码语言:javascript复制#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 ContactDestory(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
代码语言:javascript复制#define _CRT_SECURE_NO_WARNINGS
#include"Contact.h"
//初始化
void ContactInit(Con* p)
{
p->arr = NULL;
p->size = p->capacity = 0;
}
//销毁
void ContactDestory(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("%st%st%st%stt%stn", "姓名", "性别", "年龄", "电话", "地址");
for (int i = 0; i < p->size; i )
{
printf("%st%st%dt%st%stn",
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("%st%st%st%stt%stn", "姓名", "性别", "年龄", "电话", "地址");
printf("%st%st%dt%st%stn",
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
代码语言:javascript复制#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);//保存数据到文件
ContactDestory(&con);//销毁
return 0;
}
五、测试运行
菜单界面
添加联系人
展示联系人
六、总结
本文通过一个简单的通讯录管理系统,介绍了C语言在文件操作、结构体、函数等方面的应用。通过学习本文,读者可以掌握C语言编程的基本技巧,为以后的项目开发奠定基础。当然,这个通讯录管理系统还有许多可以优化的地方,比如增加联系人信息的排序、分页显示等功能,感兴趣的读者可以继续完善。