1.通讯录的介绍
顺序表是通讯录的底层结构。
通讯录是将顺序表的类型替换成结构体类型来储存用户数据,通过运用顺序表结构来实现的。
用户数据结构:
typedef struct PersonInfo
{
char name[12];
char sex[10];
int age;
char tel[11];
char addr[100];
}PeoInfo;
2. 通讯录功能的实现
2.1 构建菜单
将通讯录的所有功能都一一列出来,让用户一目了然。
Contact.c:
void menu()
{
printf("*******************************************\n");
printf("******* 1.添加联系人 2.查找联系人 ******\n");
printf("******* 1.修改联系人 2.删除联系人 ******\n");
printf("******* 1.查看通讯录 0.退出通讯录 ******\n");
printf("*******************************************\n");
}
测试结果如下:
2.2 构建选择操作
Contact.c:
int op = -1;
do {
menu();
printf("请选择您的操作:\n");
scanf("%d", &op);
switch (op)
{
case 1:
//添加联系人
break;
case 2:
//查找联系人
break;
case 3:
//修改联系人
break;
case 4:
//删除联系人
break;
case 5:
//查看通讯录
break;
case 0:
//退出通讯录
printf("通讯录退出中.....\n");
break;
}
} while(op);
测试结果如下:
2.3 构建通讯录数据类型
Contact.c:
typedef struct PersonInfo
{
char name[NAME_MAX];//使用宏便于后期修改代码
char sex[SEX_MAX];
int age;
char tel[TEL_MAX];
char addr[ADDR_MAX];
}PeoInfo;
2.4 通讯录的初始化和销毁
Contact.h:
//初始化通讯录
void InitContact(contact* con);//实际初始化的是顺序表
//销毁通讯录数据
void DestroyContact(contact* con);
Contact.c:
void InitContact(contact* con)
{
SLInit(con);
}
void DestroyContact(contact* con)
{
SLDestory(con);
}
2.5 增加联系人
Contact.h:
void AddContact(contact* con);
Contact.c:
void AddContact(contact* con)
{
SLCheckCapacity(con);
printf("请输入联系人姓名:\n");
scanf("%s", con->arr[con->size].name);
printf("请输入联系人性别:\n");
scanf("%s", con->arr[con->size].sex);
printf("请输入联系人年龄:\n");
scanf("%d", &con->arr[con->size].age);
printf("请输入联系人电话:\n");
scanf("%s", con->arr[con->size].tel);
printf("请输入联系人住址:\n");
scanf("%s", con->arr[con->size].addr);
con->size++;
}
测试结果如下:
2.6 展示联系人
Contact.h:
void ShowContact(contact* con);
Contact.c:
void ShowContact(contact* con) {
printf("%-20s\t%-5s\t%-4s\t%-12s\t%-20s\n", "姓名", "性别", "年龄", "电话", "住址");
for (int i = 0; i < con->size; i++)
{
printf("%s %s %d %s %s\n",
con->arr[i].name,
con->arr[i].sex,
con->arr[i].age,
con->arr[i].tel,
con->arr[i].addr
);
}
}
测试结果如下:
2.7 查找联系人
Contact.h:
void FindContact(contact* con);
Contact.c:
//查找通讯录数据
int FindByName(contact* con, char name[])//根据需求设计查找的方式
{
for (int i = 0; i < con->size; i++)
{
if (strcmp(con->arr[i].name, name) == 0)
{
return i;
}
}
return -1;
}
void FindContact(contact* con)
{
char name[NAME_MAX];
printf("请输入要查找人的名字:\n");
scanf("%s", name);
int FindIndex = FindByName(con, name);
if (FindIndex < 0)
{
printf("联系人不存在!\n");
return;
}
printf(%-20s\t%-5s\t%-4s\t%-12s\t%-20s\n, "姓名", "性别", "年龄", "电话", "住址");
printf(%-20s\t%-5s\t%-4s\t%-12s\t%-20s\n,
con->arr[FindIndex].name,
con->arr[FindIndex].sex,
con->arr[FindIndex].age,
con->arr[FindIndex].tel,
con->arr[FindIndex].addr
);
}
测试结果如下:
2.8 删除联系人
Contact.h:
void DelContact(contact* con);
Contact.c:
void DelContact(contact* con)
{
//删除之前一定要查找
printf("请输入要删除的联系人的姓名:\n");
char name[NAME_MAX];
scanf("%s", name);
int ret = FindByName(con, name);
//找不到,不能执行删除
if (ret < 0)
{
printf("要删除的联系人不存在!\n");
return;
}
//执行删除操作
SLErase(con, ret);
}
测试结果如下:
2.9 修改联系人
Contact.h:
void ModifyContact(contact* con);
Contact.c:
void ModifyContact(contact* con)
{
//修改之前进行查找
char name[NAME_MAX];
printf("请输入要修改联系人的姓名:\n");
scanf("%s",name);
int findIndex = FindByName(con, name);
//没有找到,不能执行修改操作
if (findIndex < 0)
{
printf("要修改的联系人不存在!\n");
return;
}
//找到了,执行修改操作
printf("请输入姓名:\n");
scanf("%s", con->arr[findIndex].name);
printf("请输入年龄:\n");
scanf("%d", &con->arr[findIndex].age);
printf("请输入性别:\n");
scanf("%s", con->arr[findIndex].sex);
printf("请输入电话:\n");
scanf("%s", con->arr[findIndex].tel);
printf("请输入地址:\n");
scanf("%s", con->arr[findIndex].addr);
printf("修改联系人成功!\n");
}
//找到了,执行修改操作
测试结果如下:
3. 通讯录功能优化
上面我们已经实现的通讯录的基本功能,但是我们会发现程序一旦结束,通讯录里储存的数据便会丢失。对于这种情况我们该如何解决呢?
答:将通讯录数据以二进制多大的方式储存到文件里
3.1 储存数据
Contact.h:
void SaveContact(contact* con)
Contact.c:
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(Info), 1, pf);
}
printf("通讯录数据保存成功!\n");
fclose(pf);
}
测试结果如下:
3.2 读取数据
Contact.h:
void LoadContact(contact* con);
Contact.c:
void LoadContact(contact* con) {
FILE* pf = fopen("contact.txt", "rb");
if (pf == NULL) {
perror("fopen error!\n");
return;
}
//循环读取⽂件数据
Info info = { 0 };
while (fread(&info, sizeof(Info), 1, pf))
{
SLCheckCapacity(con);
con->arr[con->size] = info;
con->size++;
}
//printf("%s %s\n", info.name, info.tel);
printf("历史数据导入通讯录成功!\n");
fclose(pf);
}
测试结果如下:
这样我们就不用担心数据丢失了!
4. 项目完整代码
SeqList.h:
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<string.h>
#include"Contact.h"
typedef Info SLDataType;
typedef struct SeqList
{
SLDataType* arr;
int capacity;
int size;
}SL;
//初始化和打印
void SLInit(SL* ps);
void SLPrint(SL* ps);
//扩容
void SLCheckCapacity(SL* ps);
//头插和尾插
void SLPushBack(SL* ps, SLDataType x);
void SLPushFront(SL* ps, SLDataType x);
//头删和尾删
void SLPopBack(SL* ps);
void SLPopFront(SL* ps);
//在指定位置插入数据
void SLInsert(SL* ps, int pos, SLDataType x);
//在指定位置删除
void SLErase(SL* ps, int pos);
//查找数据
//int SLFind(SL* ps, SLDataType x);
//销毁
void SLDestory(SL* ps);
SeqList.c:
#define _CRT_SECURE_NO_WARNINGS 1
#include "SeqList.h"
void SLInit(SL* ps)
{
ps->arr = NULL;
ps->size = ps->capacity = 0;
}
//void SLPrint(SL* ps)
//{
// for (int i = 0; i < ps->size; i++)
// {
// printf("%d ", ps->arr[i]);
// }
// printf("\n");
//}
//检查内存空间,扩容
void SLCheckCapacity(SL* ps)
{
int newcapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
SLDataType* tmp = (SLDataType*)realloc(ps->arr, newcapacity * sizeof(SLDataType));
if (tmp == NULL)
{
perror("realloc fall!");
exit(1);
}
ps->arr = tmp;
ps->capacity = newcapacity;
}
//尾插
void SLPushBack(SL* ps,SLDataType x)
{
assert(ps);
//空间不够,扩容
SLCheckCapacity(ps);
//空间足够,直接插入
ps->arr[ps->size++] = x;
}
//头插
void SLPushFront(SL* ps, SLDataType x)
{
assert(ps);
//判断是否扩容
SLCheckCapacity(ps);
//旧数据往后挪动一位
for (int i = ps->size; i > 0; i--)
{
ps->arr[i] = ps->arr[i - 1];
}
ps->arr[0] = x;
ps->size++;
}
//尾删
void SLPopBack(SL* ps) {
assert(ps);
//判断顺序表是否为空
assert(ps->size);
//不为空
ps->size--;
}
//头删
void SLPopFront(SL* ps)
{
assert(ps);
//判断顺序表是否为空
assert(ps->size);
for (int i = 0; i < ps->size-1; i++)
{
ps->arr[i] = ps->arr[i + 1];
}
ps->size--;
}
//在指定位置插入数据
void SLInsert(SL* ps, int pos, SLDataType x)
{
assert(ps && (pos>=0&&pos <= ps->size));
//判断是否扩容
SLCheckCapacity(ps);
for (int i = ps->size; i > pos; i--)
{
ps->arr[i ] = ps->arr[i - 1];
}
ps->arr[pos] = x;
ps->size++;
}
//在指定位置删除
void SLErase(SL* ps, int pos)
{
assert(ps && (pos >= 0 && pos <= ps->size));
//判断顺序表是否为空
assert(ps->size);
//不为空
for (int i = pos; i < ps->size-1; i++)
{
ps->arr[i] = ps->arr[i + 1];
}
ps->size--;
}
//查找数据
//int SLFind(SL* ps, SLDataType x)
//{
// assert(ps);
// for (int i = 0; i < ps->size; i++)
// {
// if (ps->arr[i] == x)
// {
// return i;
// }
// }
// return -1;
//}
void SLDestory(SL* ps)
{
assert(ps);
if (ps->arr)
{
free(ps->arr);
}
ps->arr = NULL;
ps->capacity = ps->size = 0;
}
Contact.h:
#pragma once
#include<stdio.h>
#define NAME_MAX 100
#define SEX_MAX 10
#define TEL_MAX 20
#define ADDR_MAX 100
//⽤户数据
typedef struct PersonInfo
{
char name[NAME_MAX];
char sex[SEX_MAX];
int age;
char tel[TEL_MAX];
char addr[ADDR_MAX];
}Info;
//前置声明 防止头文件嵌套调用
typedef struct SeqList contact;
//初始化通讯录
void InitContact(contact* con);//实际初始化的是顺序表
//销毁通讯录数据
void DestroyContact(contact* con);
//添加通讯录数据
void AddContact(contact* con);
//展⽰通讯录数据
void ShowContact(contact* con);
//删除通讯录数据
void DelContact(contact* con);
//查找通讯录数据
void FindContact(contact* con);
//修改通讯录数据
void ModifyContact(contact* con);
//保存数据
void SaveContact(contact* con);
//读取数据
void LoadContact(contact* con);
Contact.c:
#include"SeqList.h"
void InitContact(contact* con)
{
SLInit(con);
}
void DestroyContact(contact* con)
{
SLDestory(con);
}
//添加联系人
void AddContact(contact* con)
{
SLCheckCapacity(con);
printf("请输入联系人姓名:\n");
scanf("%s", con->arr[con->size].name);
printf("请输入联系人性别:\n");
scanf("%s", con->arr[con->size].sex);
printf("请输入联系人年龄:\n");
scanf("%d", &con->arr[con->size].age);
printf("请输入联系人电话:\n");
scanf("%s", con->arr[con->size].tel);
printf("请输入联系人住址:\n");
scanf("%s", con->arr[con->size].addr);
con->size++;
}
//展⽰通讯录数据
void ShowContact(contact* con) {
printf("%-20s\t%-5s\t%-4s\t%-12s\t%-20s\n", "姓名", "性别", "年龄", "电话", "住址");
for (int i = 0; i < con->size; i++)
{
printf("%-20s\t%-5s\t%-4d\t%-12s\t%-20s\n",
con->arr[i].name,
con->arr[i].sex,
con->arr[i].age,
con->arr[i].tel,
con->arr[i].addr
);
}
}
//查找通讯录数据
int FindByName(contact* con, char name[])//根据需求设计查找的方式
{
for (int i = 0; i < con->size; i++)
{
if (strcmp(con->arr[i].name, name) == 0)
{
return i;
}
}
return -1;
}
void FindContact(contact* con)
{
char name[NAME_MAX];
printf("请输入要查找人的名字:\n");
scanf("%s", name);
int FindIndex = FindByName(con, name);
if (FindIndex < 0)
{
printf("联系人不存在!\n");
return;
}
printf("%-20s\t%-5s\t%-4s\t%-12s\t%-20s\n", "姓名", "性别", "年龄", "电话", "住址");
printf("%-20s\t%-5s\t%-4d\t%-12s\t%-20s\n",
con->arr[FindIndex].name,
con->arr[FindIndex].sex,
con->arr[FindIndex].age,
con->arr[FindIndex].tel,
con->arr[FindIndex].addr
);
}
//删除通讯录数据
void DelContact(contact* con)
{
//删除之前一定要查找
printf("请输入要删除的联系人的姓名:\n");
char name[NAME_MAX];
scanf("%s", name);
int ret = FindByName(con, name);
//找不到,不能执行删除
if (ret < 0)
{
printf("要删除的联系人不存在!\n");
return;
}
//执行删除操作
SLErase(con, ret);
}
//修改通讯录数据
void ModifyContact(contact* con)
{
//修改之前进行查找
char name[NAME_MAX];
printf("请输入要修改联系人的姓名:\n");
scanf("%s",name);
int findIndex = FindByName(con, name);
//没有找到,不能执行修改操作
if (findIndex < 0)
{
printf("要修改的联系人不存在!\n");
return;
}
//找到了,执行修改操作
printf("请输入姓名:\n");
scanf("%s", con->arr[findIndex].name);
printf("请输入年龄:\n");
scanf("%d", &con->arr[findIndex].age);
printf("请输入性别:\n");
scanf("%s", con->arr[findIndex].sex);
printf("请输入电话:\n");
scanf("%s", con->arr[findIndex].tel);
printf("请输入地址:\n");
scanf("%s", con->arr[findIndex].addr);
printf("修改联系人成功!\n");
}
//保存数据
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(Info), 1, pf);
}
printf("通讯录数据保存成功!\n");
fclose(pf);
pf = NULL;
}
//读取数据
void LoadContact(contact* con) {
FILE* pf = fopen("contact.txt", "rb");
if (pf == NULL) {
perror("fopen error!\n");
return;
}
//循环读取⽂件数据
Info info = { 0 };
while (fread(&info, sizeof(Info), 1, pf))
{
SLCheckCapacity(con);
con->arr[con->size] = info;
con->size++;
}
//printf("%s %s\n", info.name, info.tel);
printf("历史数据导入通讯录成功!\n");
fclose(pf);
pf = NULL;
}
ConTest.c
#include"SeqList.h"
void menu()
{
printf("*******************************************\n");
printf("******* 1.添加联系人 2.查找联系人 ******\n");
printf("******* 3.修改联系人 4.删除联系人 ******\n");
printf("******* 5.查看通讯录 0.退出通讯录 ******\n");
printf("*******************************************\n");
}
int main()
{
int op = -1;
contact con;
//通讯录初始化
InitContact(&con);
LoadContact(&con);
do {
menu();
printf("请选择您的操作:\n");
scanf("%d", &op);
switch (op)
{
case 1:
//添加联系人
AddContact(&con);
break;
case 2:
//查找联系人
FindContact(&con);
break;
case 3:
//修改联系人
ModifyContact(&con);
break;
case 4:
//删除联系人
DelContact(&con);
printf("联系人删除成功!\n");
break;
case 5:
//查看通讯录
ShowContact(&con);
break;
break;
case 0:
//退出通讯录
printf("通讯录退出中.....\n");
break;
}
} while (op);
SaveContact(&con);
DestroyContact(&con);
return 0;
}
对于顺序表代码的实现在上一篇中有讲解,如果有的小伙伴有兴趣,可以去看一看。链接在下方:http://t.csdnimg.cn/wpM1t
本文为作者学习后的总结,如果有什么不恰当的地方,欢迎大佬指正!!!