前言
昨天我们踏入了数据结构的深山,并且和顺序表battle了一番,虽说最后赢了,但同时也留下了一个问题:如何从顺序表的增删查改加强到通讯录的的增删查改,别急,今天就带你一探究竟。
一.回顾与思考
我们昨天实现了顺序表的头删,头插,尾删尾插,选择插入,选择删除,以及初始化和销毁等功能,我们也知道通讯录其实就是之前的顺序表的plus版本,二者有很强的关联性,于是乎我们今天不打算从头开始写代码,而是在昨天的基础上进行修改和完善。
没看过的宝子建议先去了解一下哦
【数据结构之顺序表的增删查改 - CSDN App】http://t.csdnimg.cn/VK5iU
二.目标展示
🌟 🌟 🌟在开始前,先来看看我们都要干什么吧 🌟 🌟 🌟
功能要求 1)⾄少能够存储100个⼈的通讯信息 2)能够保存⽤⼾信息:名字、性别、年龄、电话、地址等 3)增加联系⼈信息 4)删除指定联系⼈ 5)查找制定联系⼈ 6)修改指定联系⼈ 7)显⽰联系⼈信息 8)程序结束后,历史通讯录信息不会丢失
三通讯录启动
老规矩,我先把头文件展示一下,然后挨个给王子公主们讲解🌞SL.h
#pragma once#include"contact.h"
#include
#define _CRT_SECURE_NO_WARNINGS 1
typedef struct PersonInfo
{
char name[NAME_MAX];
char sex[SEX_MAX];
int age;
char tele[TEL_MAX];
char address[ADDR_MAX];
}SLDataType;
typedef struct SL
{
SLDataType* a;
int size;
int capacity;
}SL;
//typedef contact SL;
//初始化
void SLInit(SL* ps);
//销毁
void SLDestroy(SL* ps);
//打印
void SLPrint(SL* ps);
//扩容
void SLCheckCapacity(SL* ps);
//头部插⼊删除 / 尾部插⼊删除
void SLPushBack(SL* ps, SLDataType x);
void SLPopBack(SL* ps);
void SLPushFront(SL* ps, SLDataType x);
void SLPopFront(SL* ps);
//指定位置之前插⼊/删除数据
void SLInsert(SL* ps, int pos, SLDataType x);
void SLDelete(SL* ps, int pos);
🌞contact.h
与上次不同,这次我们写了两个头文件,一个是在原来顺序表的基础上修改的,一个是通讯录的头文件,别晕,咱们慢慢说。#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#define NAME_MAX 100
#define SEX_MAX 10
#define TEL_MAX 11
#define ADDR_MAX 100
#include
#include
//前置声明
struct SL;
typedef struct SL contact;
//用户数据
//初始化通讯录
void InitContact(contact* con);
//删除通讯录数据
void DelContact(contact* con);
//添加通讯录数据
void AddContact(contact* con);
//展示通讯录数据
void ShowContact(contact* con);
//查找通讯录数据
void FindContact(contact* con);
//修改通讯录数据
void ModifyContact(contact* con);
//销毁通讯录数据
void DestroyContact(contact* con);
🌞SL.h头文件讲解
🐻1.防止头文件被多次包含。
#pragma once
🐻2.把我们需要的头文件包含一下,contact.h中有我们需要的宏,至于windows.h,到后面你就知道了。
#include"contact.h"#include
🐻3.vs用户应该都知道这个,为了防止IDE报scanf等函数的错。
#define _CRT_SECURE_NO_WARNINGS 1
🐻4.联系人结构体定义
typedef struct PersonInfo注意注意,重点来了,我们定义了一个结构体,它包含了通讯录联系人的种种信息例如姓名,性别,年龄,电话和住址,接着我们又给结构体换了个名字——SLDataType 它是个英文缩写,即Sequence List Data Type,顺序表数据类型,ok回想一下上一篇文章,我们所用的顺序表数据类型是int,当时也是给他换成了这个名字,如此一来,之前我写的函数就不会因为类型改变而要再全部改一遍了。{
char name[NAME_MAX];
char sex[SEX_MAX];
int age;
char tele[TEL_MAX];
char address[ADDR_MAX];
}SLDataType;
🐻5.通讯录结构体定义
typedef struct SL好的,紧跟着的又是一个结构体,它就是我们的通讯录类型,他有三个成员 第一个是存放联系人的个人信息的 第二个是通讯录当前的数据数量, 第三个是通讯录容量 与昨天相比,他只有SLDataType改变了 后面的就是咱们昨天写的函数了,我就不再赘述了{
SLDataType* a;
int size;
int capacity;
}SL;
ok'接下来看contact.h
🌞contact.h头文件讲解
🦊1.宏定义
#define NAME_MAX 100//
#define SEX_MAX 10//
#define TEL_MAX 11//
#define ADDR_MAX 100//
- 1.姓名的最大长度
- 2.性别单词的最大长度(female和male)
- 3.电话号码最大长度
- 4.地址的最大长度
🦊2.前置声明
struct SL;
前置声明,等会我们要用到这个结构体,但这个结构提示定义在另一个头文件的,所以先声明一下 再给他换个名字(当然你也可以不换),主要是为了方便记忆,既然他是这个通讯录的类型,那干脆给他起名叫通讯录得了——contact。 注意注意,下面就要写函数了,重点来了 首先在强调一下,我们之前是写过了的,所以今天不用从头再来,我们要做事是 修改typedef struct SL contact;
//用户数据
🦊3.初始化通讯录
void InitContact(contact* con);
void InitContact(contact* con)
这个就是正常开辟堆区空间就好。 现在我们先不急着往下写,我们想想我们等下要写修改数据,删除数据,展示数据的函数,他们的共同点是都要先找到那个联系人才行,于是乎我们可以直接写出实现这个功能的函数,之后直接调用它就好了{
SLInit(con);
}
🦊4.查找函数
int checkbyname(contact* con, char* p);
//查找函数
int checkbyname(contact* con, char* p)
{
for (int i = 0; i < con->size; i++)
{
if (strcmp(p, con->a[i].name)==0)
return i;
}
return -1;
}
🦊5.删除通讯录数据
void DelContact(contact* con);
- 1.检查通讯录内容是否为空(都空了你还删个啥)
- 2.通过scanf接受名字,记得把回车移除缓冲区
- 3.调用查找函数找找这个人在哪里
- 4.调用之前的指定删除函数
//删除通讯录数据
void DelContact(contact* con)
{
if (con->size - 1 < 0)
{
printf("通讯录空了\n");
//perror("SLPopFront Fail");
return;
}
printf("输入你要删除的联系人姓名\n");
char p[101];
scanf("%s",p);
getchar();
int pos = checkbyname(con, p);
if (pos == -1)
printf("此人不存在\n");
else
{
SLDelete(con, pos);
printf("删除成功\n");
}
}
void SLDelete(SL* ps, int pos)
{
for (int i = pos; i < ps->size - 1; i++)
ps->a[i] = ps->a[i + 1];
ps->size--;
}
🦊6.添加通讯录数据
void AddContact(contact* con);
把你要添加的联系人信息输进去,存到一个SLDataType变量中 通过之前写的尾插把联系人添加进去void AddContact(contact* con)
{
SLDataType a;
printf("请输入姓名\n");
scanf("%s", a.name);
getchar();
printf("请输入性别\n");
scanf("%s", a.sex);
getchar();
printf("请输入年龄\n");
scanf("%d", &a.age);
getchar();
printf("请输入电话号码\n");
scanf("%s", a.tele);
getchar();
printf("请输入地址\n");
scanf("%s", a.address);
getchar();
SLPushBack(con,a);
}
void SLPushBack(SL* ps, SLDataType x)
{
if (ps->size + 1 > ps->capacity)
SLCheckCapacity(ps);
ps->a[ps->size] = x;
(ps->size)++;
}
🦊7.展示通讯录数据
void ShowContact(contact* con);
通过for循环把信息全部打印出来void ShowContact(contact* con)
{
printf("姓名\t性别\t年龄\t号码\t地址\n");
for (int i = 0; i < con->size; i++)
{
printf("%s\t%s\t%d\t%s\t%s\n", con->a[i].name, con->a[i].sex, con->a[i].age, con->a[i].tele, con->a[i].address);
}
}
🦊8.查找通讯录数据
void FindContact(contact* con);
- 1.输入要找的人名
- 2.调用查找函数
- 3.打印出来你要找的人的名字
void FindContact(contact* con)
{
char name[100] = { 0 };
printf("输入你要找的名字\n");
scanf("%s",name);
getchar();
int i=checkbyname(con, name);
if (i == -1)
printf("没有你要找的人\n");
else
printf("%s\t%s\t%d\t%s\t%s\n", con->a[i].name, con->a[i].sex, con->a[i].age, con->a[i].tele, con->a[i].address);
}
🦊9.修改通讯录数据
void ModifyContact(contact* con);
- 1.输入名字
- 2.调用查找函数
- 3.输入你要修改为什么信息
- 4.通过之前的选择插入函数修改数据
//修改通讯录数据
void ModifyContact(contact* con)
{
char name[100] = { 0 };
printf("输入你要修改的人的名字\n");
scanf("%s",name);
getchar();
int i = checkbyname(con, name);
if (i == -1)
printf("没有你要找的人\n");
else
{
SLDataType a;
printf("请输入姓名\n");
scanf("%s", a.name);
getchar();
printf("请输入性别\n");
scanf("%s", a.sex);
getchar();
printf("请输入年龄\n");
scanf("%d", &a.age);
getchar();
printf("请输入电话号码\n");
scanf("%s", a.tele);
getchar();
printf("请输入地址\n");
scanf("%s", a.address);
getchar();
SLInsert(con, i, a);
}
}
🦊10.销毁通讯录数据
void DestroyContact(contact* con);
void DestroyContact(contact* con)
诶喝,你想想,咱们退出而时候加上这句话“退出中,请稍等”,再用sleep函数暂停个1秒2秒,是不是更有那种感觉。 but,我们还没有结束,别忘了最后一条要求 🪐🪐🪐🪐 那看来文件操作是必不可少了🪐🪐🪐🪐🪐 其实也好想,退出的时候把数据保存在一个文件中,开始运行程序时把这文件的数据读取出来。 那我们就要修改初始化函数和销毁函数了 我们使用fread和fwrite{
SLDestroy(con);
printf("退出中,请稍等\n");
Sleep(1000);
}
- 方法一:我的思路是先把当前数据数量读进文件中,这样之后把这个数据再读出来就可以循环读取联系人信息了
- 方法二是:利用fread的返回值,他的返回值使实际读取的数据数量,我们每次读一个,当返回值为0,就说明读完了,于是停止读取。
void SLInit(SL* ps)
{
FILE* p = fopen("contact.x", "rb");
if (p != NULL)
{
{
fread(&ps->size, sizeof(int), 1, p);
fread(&ps->capacity, sizeof(int),1, p);
ps->a = (SLDataType*)malloc(ps->capacity * sizeof(SLDataType));
for (int i = 0; i < ps->size; i++)
{
fread(&ps->a[i], sizeof(SLDataType), 1, p);
}
}
fclose(p);
}
else
{
ps->a = (SLDataType*)malloc(CAPACITY * sizeof(SLDataType));
ps->size = 0;
ps->capacity = 4;
}
}
void SLDestroy(SL* ps)
{
FILE* p = fopen("contact.x","wb");
if (p == NULL)
printf("保存数据失败\n");
else
{
fwrite (&ps->size,sizeof(int),1,p);
fwrite(&ps->capacity, sizeof(int),1, p);
for (int i = 0; i < ps->size; i++)
{
fwrite(ps->a+i, sizeof(SLDataType),1, p);
}
fclose(p);
}
free(ps->a);
ps->a = NULL;
ps->size = 0;
ps->capacity = 0;
}
最后的最后,把主函数奉上
#include"contact.h"
#include"SL.h"
void menu()
{
printf("********* 通讯录 ***********\n");
printf("***1.添加 ***** 2.删除*********\n");
printf("***3.展示 ***** 4.查找********\n");
printf("***5.修改 ***** 0.退出并保存*****\n");
}
int main()
{
int b = -1;
contact a;
InitContact(&a);
do
{
menu();
scanf("%d", &b);
switch (b)
{
case 1:
AddContact(&a);
break;
case 2:
DelContact(&a);
break;
case 3:
ShowContact(&a);
break;
case 4:
FindContact(&a);
break;
case 5:
ModifyContact(&a);
break;
case 0:
DestroyContact(&a);
break;
default:
printf("输入错误,请重新输入\n");
break;
}
} while (b);
}
总结:
经过顺序表和通讯录的洗礼,我们算是熬过这数据结构第一关了,我的建议是趁热打铁去刷点顺序表的oj题来巩固一下。
那么下一站,单链表,我们再会!
猜你喜欢
- 3小时前如何快速打开github
- 3小时前基于微信小程序的网上购物平台小程序的设计与实现 服务器端口php+mysql(附源码 调试 文档)
- 3小时前uniapp中video层级太高解决方案,适用安卓IOSH5
- 3小时前【前后端分离与不分离的区别】
- 3小时前ffmpeg 常用命令行详解
- 3小时前第6章-路由器、交换机及其操作系统介绍
- 3小时前数据结构初探:揭开数据结构奥秘
- 3小时前基于 Spring Boot+MySQL实现的在线考试系统源码+数据库,基于不同类型的客观题,进行自动组卷、批卷等功能的考试系统
- 3小时前支付宝怎样开通商家服务(支付宝怎样开通商家服务收款码)
- 3小时前楼王位置什么位置(何为楼王位置)
网友评论
- 搜索
- 最新文章
- 热门文章