引言:通过顺序表的逻辑实现通讯录。这里就不讲关于顺序表的函数了。如果有不明白的可以看我写的顺序表的博客。
目录
顺序表与通讯录的比较
各源文件文件大榄
Contact.c中通讯录相关函数的定义
初始化和销毁通讯录
添加联系人:
删除联系人:
打印通讯录中存储的所有的联系人的信息
查找联系人(通过名字)
修改联系人的信息
保存顺序表的内容
将文件的内容读入顺序表
将通讯录中的联系人的信息写入文件
优化后的的通讯录初始化和销毁函数
test.c
SeqList.h
SeqList.c
Contact.h
Contact.c
结语:
顺序表与通讯录的比较
通讯录的底层逻辑就是顺序表,与存储int数据的顺序表相比,通讯录这个结构体存储的每个元素的类型为结构体,并且这个结构体定义的是每个联系人的基本信息。
图解:
各源文件文件大榄
SeqList.h | 顺序表的结构的声明,顺序表相关函数的声明,#define定义的符号 |
SeqList.c | 顺序表函数的定义 |
Contact.h | 通讯录中每个联系人的结构的定义,通讯录相关函数的声明 |
Contact.c | 通讯录相关函数的定义 |
test.c | 可以测试,通讯录的流程实现 |
Contact.h
#pragma once
#define NAME_MAX 20
#define GENDER_MAX 20
#define TEL_MAX 20
#define ADRR_MAX 20
//联系人的信息的结构
typedef struct personInfo
{
char name[NAME_MAX];//姓名
char gender[GENDER_MAX];//性别
int age;//年龄
char tel[TEL_MAX];//电话
char addr[ADRR_MAX];//家庭地址
}peoInfo;
typedef struct SeqList Contact;//前置声明,将顺组表中的struct SeqList 改为 Contact 增加代码的可读性
//初始化和销毁
void ContactInit(Contact* ps);
void ContactDestory(Contact* ps);
//添加和删除
void ContactAdd(Contact* ps);
void ContactDel(Contact* ps);
//打印通讯录中的联系人
void ContactPrint(Contact* ps);
//修改联系人的信息
void ContactModify(Contact* ps);
//查找想要查找的联系人
void ContactFind(Contact* ps);
//将文件的信息加载进通讯录
void ContactLoad(Contact* ps);
//销毁通讯录前将通讯录中的信息写入文件
void ContactSave(Contact* ps);
SeqList.h
#pragma once
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include "Contact.h"
//顺序表中存储的元素的类型为定义的联系人的结构体
#define SLDataType peoInfo
typedef struct SeqList
{
SLDataType* arr;
int size;
int capacity;
}SL;
//初始化
void SLInit(SL* ps);
void SLDestory(SL* ps);
//打印
//void SLPrint(SL ps);
//尾插,尾删
void SLPushBack(SL* ps, SLDataType x);
void SLPushFront(SL* ps, SLDataType x);
//尾删,头删
void SLPopFront(SL* ps);
void SLPopBack(SL* ps);
//任意插,任意删
void SLInsert(SL* ps, int pos, SLDataType x);
void SLErase(SL* ps, int pos);
Contact.c中通讯录相关函数的定义
初始化和销毁通讯录
//初始化
void ContactInit(Contact* ps)
{
SLInit(ps);
}
//销毁
void ContactDestory(Contact* ps)
{
SLDestory(ps);
}
直接通过顺序表的初始化和销毁实现就可以了。
添加联系人:
void ContactAdd(Contact* ps)
{
peoInfo s;//先定义一个联系人的变量存储要添加的联系人的信息
printf("请输入要添加的联系人姓名:\n");
scanf("%s", s.name);
printf("请输入要添加联系人的性别:\n");
scanf("%s", s.gender);
printf("请输入要添加联系人的年龄:\n");
scanf("%d", &s.age);
printf("请输入要添加联系人的电话:\n");
scanf("%s", s.tel);
printf("请输入要添加联系人的地址:\n");
scanf("%s", s.addr);
SLPushFront(ps, s);//顺序表的头插,这里用尾插也可以
}
注意:用顺序表的头插或尾插将联系人的信息插入进通讯录.
删除联系人:
//通过名字在通讯录中找到要删除的人
int FindByName(Contact* ps, char* name)
{
for (int i = 0; i < ps->size; i++)
{
if (strcmp(ps->arr[i].name, name) == 0)
return i;
}
return -1;
}
//删除一个联系人
void ContactDel(Contact* ps)
{
char name[NAME_MAX];
printf("请输入你要删除的联系人的姓名:\n");
scanf("%s",name);
//如果通过名字找到联系人则返回存储该联系人的下标
int find = FindByName(ps, name);
if (find < 0)
{
printf("你的通讯录中没有您要删除的人\n");
return;
}
//通过顺序表的任意删除函数删除
SLErase(ps, find);
}
问题:如何删除一个联系人呢?
首先,你需要给出这个联系人的名字或手机号,或家庭地址,通过这些信息找到这个联系人在顺序表中存储的位置;然后,在通过下标,利用顺序表的任意删除顺序表中的数据,删除该联系人。
这里再讲一下FindByName 函数,如果顺序表中存储的联系人的结构体的名字中有这个名字,则返回在顺序表中存储该联系人的下标;若没找到,则返回一个比0小的数。
打印通讯录中存储的所有的联系人的信息
预期结果:
实现代码:
void ContactPrint(Contact* ps)
{
printf("%-5s%-5s%-5s%-5s%-5s\n",
"姓名", "性别", "年龄", "电话", "家庭地址");
for (int i = 0; i < ps->size; i++)
{
printf("%-5s%-5s%-5d%-5s%-5s\n",
ps->arr[i].name,
ps->arr[i].gender,
ps->arr[i].age,
ps->arr[i].tel,
ps->arr[i].addr);
}
}
这里代码比较简单,就不多说了。
查找联系人(通过名字)
//通过名字在顺序表中查询
int FindByName(Contact* ps, char* name)
{
for (int i = 0; i < ps->size; i++)
{
if (strcmp(ps->arr[i].name, name) == 0)
return i;
}
return -1;
}
//查找联系人
void ContactFind(Contact* ps)
{
char name[NAME_MAX];
printf("请输入想要查找的联系人的姓名:\n");
scanf("%s", name);
int find = FindByName(ps, name);//通过名字查找
if (find < 0)
{
printf("你想要查找的联系人的姓名不在通讯录中\n");
return;
}
//找到了该联系人则打印一下这个联系人的信息
printf("%-5s%-5s%-5s%-5s%-5s\n",
"姓名", "性别", "年龄", "电话", "家庭地址");
printf("%-5s%-5s%-5d%-5s%-5s\n",
ps->arr[find].name,
ps->arr[find].gender,
ps->arr[find].age,
ps->arr[find].tel,
ps->arr[find].addr);
}
这里的查找只是通过名字查找,你也可以通过电话,或家庭地址查找。
修改联系人的信息
void ContactModify(Contact* ps)
{
char name[NAME_MAX];
printf("请输入想要修改的联系人的姓名:\n");
scanf("%s", name);
int find = FindByName(ps, name);
if (find < 0)
{
printf("你想要修改的联系人的姓名不在通讯录中\n");
return;
}
printf("请输入要添加的联系人姓名:\n");
scanf("%s", ps->arr[find].name);
printf("请输入要添加联系人的性别:\n");
scanf("%s", ps->arr[find].gender);
printf("请输入要添加联系人的年龄:\n");
scanf("%d", &ps->arr[find].age);
printf("请输入要添加联系人的电话:\n");
scanf("%s", ps->arr[find].tel);
printf("请输入要添加联系人的地址:\n");
scanf("%s", ps->arr[find].addr);
}
实现思路:通过名字找到你想要修改的联系人在顺序表中存储的下标,有了下标就可以直接对这个位置的数据进行修改。
保存顺序表的内容
每次程序运行完,通讯录中的数据就会丢失,如何在下次运行程序时,继续使用上次的程序呢?
在每次销毁顺序表之前将通讯录中联系人的信息写入一个文件,每次初始化通讯录后将文件的内容读入通讯录就可以了。
将文件的内容读入顺序表
void ContactLoad(Contact* ps)
{
FILE* pf = fopen("test.txt", "rb");
if (pf == NULL)
{
perror("fopen");
return;
}
peoInfo s;//定义一个联系人的变量存储每次从文件中读出的联系人的信息
while (fread(&s, sizeof(peoInfo), 1, pf))//每次读一个联系人的信息直至没有联系人的信息可以读
{
SLPushFront(ps, s);//将联系人的信息写入通讯录
}
fclose(pf);
pf = NULL;
}
将通讯录中的联系人的信息写入文件
void ContactSave(Contact* ps)
{
assert(ps);
FILE* pf = fopen("test.txt", "wb");
if (pf == NULL)
{
perror("fopen");
return;
}
fwrite(ps->arr, sizeof(peoInfo), ps->size, pf);//将通讯录中size个联系人的数据,也就是所有联系人的数据写入文件
fclose(pf);
pf = NULL;
}
优化后的的通讯录初始化和销毁函数
void ContactInit(Contact* ps)
{
SLInit(ps);
ContactLoad(ps);
}
void ContactDestory(Contact* ps)
{
ContactSave(ps);
SLDestory(ps);
}
test.c
void menu()
{
printf("************************************\n");
printf("****1.添加联系人****2.删除联系人****\n");
printf("****3.修改联系人****4.查找联系人****\n");
printf("****5.展示联系人****0. 退出 ****\n");
}
int main()
{
//ContactTest1();
Contact s;
ContactInit(&s);//初始化并载入文件中的联系人数据
int op;
do
{
menu();
printf("请输入你的操作:\n");
scanf("%d", &op);
switch (op)
{
case 1:
ContactAdd(&s);
break;
case 2:
ContactDel(&s);
break;
case 3:
ContactModify(&s);
break;
case 4:
ContactFind(&s);
break;
case 5:
ContactPrint(&s);
break;
case 0:
printf("退出.....emo\n");
break;
default:
printf("你在干什么?请输入正确的操作数:\n");
break;
}
} while (op);
//销毁并肩现在通讯录中联系人的信息写入文件
ContactDestory(&s);
return 0;
}
SeqList.h
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include "Contact.h"
#define SLDataType peoInfo
typedef struct SeqList
{
SLDataType* arr;
int size;
int capacity;
}SL;
//初始化
void SLInit(SL* ps);
void SLDestory(SL* ps);
//打印
//void SLPrint(SL ps);
//尾插,尾删
void SLPushBack(SL* ps, SLDataType x);
void SLPushFront(SL* ps, SLDataType x);
//尾删,头删
void SLPopFront(SL* ps);
void SLPopBack(SL* ps);
//任意插,任意删
void SLInsert(SL* ps, int pos, SLDataType x);
void SLErase(SL* ps, int pos);
SeqList.c
#include "SeqList.h"
void CheckSLCapacity(SL* ps)
{
if (ps->capacity == ps->size)
{
int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
SLDataType* tmp = (SLDataType*)realloc(ps->arr, newcapacity * sizeof(SLDataType));
if (tmp == NULL)
{
perror("realloc");
exit(-1);
}
//开辟成功
ps->arr = tmp;
ps->capacity = newcapacity;
}
}
void SLInit(SL* ps)
{
assert(ps);
ps->arr = NULL;
ps->size = 0;
ps->capacity = 0;
}
void SLDestory(SL* ps)
{
assert(ps);
free(ps->arr);
ps->arr = NULL;
ps->size = 0;
ps->capacity = 0;
}
//void SLPrint(SL s)
//{
// for (int i = 0; i < s.size; i++)
// printf("%d ", s.arr[i]);
// printf("\n");
//}
void SLPushBack(SL* ps, SLDataType x)
{
assert(ps != NULL);
CheckSLCapacity(ps);
ps->arr[ps->size] = x;
ps->size++;
}
void SLPushFront(SL* ps, SLDataType x)
{
assert(ps != NULL);
CheckSLCapacity(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 != NULL);
assert(ps->size > 0);
ps->size--;
}
void SLPopFront(SL* ps)
{
assert(ps != NULL);
assert(ps->size > 0);
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);
assert(pos >= 0 && pos <= ps->size);
CheckSLCapacity(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);
assert(pos >= 0 && pos < ps->size);
for (int i = pos; i < ps->size-1; i++)
{
ps->arr[i] = ps->arr[i + 1];
}
ps->size--;
}
Contact.h
#pragma once
#define NAME_MAX 20
#define GENDER_MAX 20
#define TEL_MAX 20
#define ADRR_MAX 20
typedef struct personInfo
{
char name[NAME_MAX];
char gender[GENDER_MAX];
int age;
char tel[TEL_MAX];
char addr[ADRR_MAX];
}peoInfo;
typedef struct SeqList Contact;
//初始化和销毁
void ContactInit(Contact* ps);
void ContactDestory(Contact* ps);
//添加和删除
void ContactAdd(Contact* ps);
void ContactDel(Contact* ps);
//打印通讯录中的联系人
void ContactPrint(Contact* ps);
//修改联系人的信息
void ContactModify(Contact* ps);
//查找想要查找的联系人
void ContactFind(Contact* ps);
//将文件的信息加载进通讯录
void ContactLoad(Contact* ps);
//销毁通讯录前将通讯录中的信息写入文件
void ContactSave(Contact* ps);
Contact.c
#include "SeqList.h"//这个文件中有Contact的定义
void ContactInit(Contact* ps)
{
SLInit(ps);
ContactLoad(ps);
}
void ContactDestory(Contact* ps)
{
ContactSave(ps);
SLDestory(ps);
}
void ContactAdd(Contact* ps)
{
peoInfo s;
printf("请输入要添加的联系人姓名:\n");
scanf("%s", s.name);
printf("请输入要添加联系人的性别:\n");
scanf("%s", s.gender);
printf("请输入要添加联系人的年龄:\n");
scanf("%d", &s.age);
printf("请输入要添加联系人的电话:\n");
scanf("%s", s.tel);
printf("请输入要添加联系人的地址:\n");
scanf("%s", s.addr);
SLPushFront(ps, s);
}
int FindByName(Contact* ps, char* name)
{
for (int i = 0; i < ps->size; i++)
{
if (strcmp(ps->arr[i].name, name) == 0)
return i;
}
return -1;
}
void ContactDel(Contact* ps)
{
char name[NAME_MAX];
printf("请输入你要删除的联系人的姓名:\n");
scanf("%s",name);
int find = FindByName(ps, name);
if (find < 0)
{
printf("你的通讯录中没有您要删除的人\n");
return;
}
SLErase(ps, find);
}
void ContactPrint(Contact* ps)
{
printf("%-5s%-5s%-5s%-5s%-5s\n",
"姓名", "性别", "年龄", "电话", "家庭地址");
for (int i = 0; i < ps->size; i++)
{
printf("%-5s%-5s%-5d%-5s%-5s\n",
ps->arr[i].name,
ps->arr[i].gender,
ps->arr[i].age,
ps->arr[i].tel,
ps->arr[i].addr);
}
}
void ContactModify(Contact* ps)
{
char name[NAME_MAX];
printf("请输入想要修改的联系人的姓名:\n");
scanf("%s", name);
int find = FindByName(ps, name);
if (find < 0)
{
printf("你想要修改的联系人的姓名不在通讯录中\n");
return;
}
printf("请输入要添加的联系人姓名:\n");
scanf("%s", ps->arr[find].name);
printf("请输入要添加联系人的性别:\n");
scanf("%s", ps->arr[find].gender);
printf("请输入要添加联系人的年龄:\n");
scanf("%d", &ps->arr[find].age);
printf("请输入要添加联系人的电话:\n");
scanf("%s", ps->arr[find].tel);
printf("请输入要添加联系人的地址:\n");
scanf("%s", ps->arr[find].addr);
}
void ContactFind(Contact* ps)
{
char name[NAME_MAX];
printf("请输入想要查找的联系人的姓名:\n");
scanf("%s", name);
int find = FindByName(ps, name);
if (find < 0)
{
printf("你想要查找的联系人的姓名不在通讯录中\n");
return;
}
printf("%-5s%-5s%-5s%-5s%-5s\n",
"姓名", "性别", "年龄", "电话", "家庭地址");
printf("%-5s%-5s%-5d%-5s%-5s\n",
ps->arr[find].name,
ps->arr[find].gender,
ps->arr[find].age,
ps->arr[find].tel,
ps->arr[find].addr);
}
void ContactLoad(Contact* ps)
{
FILE* pf = fopen("test.txt", "rb");
if (pf == NULL)
{
perror("fopen");
return;
}
peoInfo s;
while (fread(&s, sizeof(peoInfo), 1, pf))
{
SLPushFront(ps, s);
}
fclose(pf);
pf = NULL;
}
void ContactSave(Contact* ps)
{
assert(ps);
FILE* pf = fopen("test.txt", "wb");
if (pf == NULL)
{
perror("fopen");
return;
}
fwrite(ps->arr, sizeof(peoInfo), ps->size, pf);
fclose(pf);
pf = NULL;
}
最终结果展示:
第一次写:
写完之后文件中有一个联系人: 22 22 22 22 22 22
文件的内容:
第二次使用程序:
结语:
总算写完了,现在脑袋还是昏昏的,哈哈哈哈.
下次的项目就是贪吃蛇了。