首先我们得明确它的基本功能,信息:
1.人的信息:姓名+年龄+性别+地址+电话
2.通讯录的可以存放100个人的信息
3.功能:
1>增加联系人
2>删除指定联系人
3>查找指定联系人的信息
4>修改指定联系人的信息
5>显示所有联系人的信息
6>排序(姓名,年龄)
test.c 测试通讯录
contact.c 通讯录的实现
contact.h 函数的声明
为了一步一步的引进?我们先写静态版本的吧!
第一步,我们是先写个框架(怎么进去,怎么选择的)
其实这个是非常简单的,也是相当固定的,跟之前写过的扫雷,三子棋,等游戏写法差不多
创建了test.c文件后开始
void menu()
{
printf("###########################\n");
printf("######1.Add 2.del ####\n");
printf("######3.search 4.modify####\n");
printf("######5.show 6.sort ####\n");
printf("######0.exit ####\n");
printf("###########################\n");
}
//枚举方式
enum Option
{
EXIT,
ADD,
DEL,
SEARCH,
MODIFY,
SHOW,
SORT
};
int main()
{
int input = 0;
do
{
menu();
printf("请输入你想实现的业务数字:");
scanf("%d", &input);
switch (input)
{
case ADD:
break;
case DEL:
break;
case SEARCH:
break;
case MODIFY:
break;
case SHOW:
break;
case SORT:
break;
case EXIT:
printf("退出游戏");
break;
default:
printf("输入错误,请重新选择");
break;
}
} while (input);
return 0;
}
出来的效果是这样的:
其中上面用了枚举的便利方法:为什么?
因为如果了解过枚举的原理,我们知道,枚举的成员正常情况下第一个默认为0,接着下去
enum Option
{
EXIT, --0 退出
ADD, --1 增加
DEL, --2 删除
SEARCH, --3 查找
MODIFY, --4 修改
SHOW, --5 展示
SORT --6 排序
};
这就很好的对应了我们的菜单数字,且在case那里可以更直观明了的看清楚我们想实现的代码,更方便我们后续写代码。
接着,我们先进行写人的信息的代码,想想,这是不是得用我们所学的结构体的知识
这个代码我们在Contact.h文件中写,可以方便我们在.c文件中任意调用。
//人的信息
typedef struct PeoInfo
{
char name[20];
int age;
char sex[4];
char addr[40];
char tele[4];
}PeoInfo;
这样子就写好了人的信息了,可我们试想一下,这给定一个数字的,是不是就固定死了。
想要更加灵活的话,我们可以自定义一下,如下:
#define NameMax 20
#define SexMax 4
#define AddrMax 40
#define TeleMax 12
//人的信息
typedef struct PeoInfo
{
char name[NameMax];
int age;
char sex[SexMax];
char addr[AddrMax];
char tele[TeleMax];
}PeoInfo;
这样是不是就更加灵活了,后续想要改的话,就直接在上面改个数字就行,不用在具体代码中一个一个的改。
初始化部分
接着,到我们的初始化部分了。想想,我们在什么时候应该初始化呢?是不是在每次进入菜单选择之前,就把初始化搞好?
所以把初始化在菜单的前面声明了先,又因为它属于通讯录部分,为了更加清晰它的分工,我们把它放在Contact.c文件那里
静态的
typedef struct Contact
{
PeoInfo data[Max]; //存放人的信息的
int sz; //当前已经存放的信息个数
两者必然是一起的?
因为data无论增加还是减少,sz都会随着改变的!
}Contact;
test.c文件中
Contact con;
InitContact(&con);
在Contact.h头文件中声明
#define MAX 100
void InitContact(Contact* pc);
void InitContact(Contact* pc)
{
assert(pc);
pc->sz = 0;
memset(pc->data, 0, sizeof(pc->data));
memset这个函数我们之前讲过了,作用就把它全初始化为0。
}
写完初始化之后,我们就可以走向功能区的部分了
先Add增加部分吧!
void AddContact(Contact* pc)
{
assert(pc); 这里断言是一个好习惯,遇到指针就应该加上断言,防止空指针
if (pc->sz == Max) 判断是否已经满了通讯录
{
printf("通讯录已满,无法添加\n");
return;
}
//增加一个人的信息 这里由于是数组,scanf不用加&
但是age不是数组,必须&!!!!!
printf("请输入一个人的姓名:");
scanf("%s", pc->data[pc->sz].name);
printf("请输入一个人的年龄:");
scanf("%d", &(pc->data.age));
printf("请输入一个人的性别:");
scanf("%s", pc->data[pc->sz].sex);
printf("请输入一个人的地址:");
scanf("%s", pc->data[pc->sz].addr);
printf("请输入一个人的电话:");
scanf("%s", pc->data[pc->sz].tele);
pc->sz++; 一个人增加完后,开始下一个空间大小
}
显示部分:
void ShowContact(const Contact* pc)
{
assert(pc);
int i = 0;
printf("%-20s\t %-4s\t %-4s\t %-40s\t %-12s\n ", "名字", "年龄", "性别", "地址", "电话");
for (i = 0; i < pc->sz; i++)
{
printf("%-20s\t %-4d\t %-4s\t %-40s\t %-12s\n", pc->data[i].name,
pc->data[i].age,
pc->data[i].sex,
pc->data[i].addr,
pc->data[i].tele);
}
}
删除部分:
我们要删除之前,是不是得找到你要删的那个名字?
所以得创建一个函数,找出来,删除它
int Find(const Contact* pc, char name[])
{
assert(pc);
int i = 0;
for (i = 0; i < pc->sz; i++)
{
if (strcmp(pc->data[i].name, name) == 0)
{
return i;
}
}
return -1;
}
void DelContact(Contact* pc)
{
assert(pc);
char name[NameMax] = { 0 };
if (pc->sz == 0)
{
printf("不好意思,没有可以删除的人");
return;
}
printf("请选择你要删除的人:");
scanf("%s", name);
int ret = Find(pc, name);
if (-1 == ret)
{
printf("没有这个人,请再次查看是否输入正确?\n");
return;
}
int i = 0;
for (i = ret; i < pc->sz - 1; i++)
{
pc->data[i] = pc->data[i + 1];
}
pc->sz--;
printf("删除成功\n");
}
查找部分:
void SearchContact(const Contact* pc)
{
assert(pc);
char name[NameMax] = { 0 };
printf("请输入你要查找的名字");
scanf("%s", name);
int pos = Find(pc, name); 这里也使用到了找的函数,说明我们单独去创建是明智的
if (-1 == pos)
{
printf("不好意思,没有这个人的信息");
return;
}
//打印信息
printf("%-20s\t %-4s\t %-4s\t %-40s\t %-12s\n ",
"名字", "年龄", "性别", "地址", "电话");
printf("%-20s\t %-4d\t %-4s\t %-40s\t %-12s\n",
pc->data[pos].name,
pc->data[pos].age,
pc->data[pos].sex,
pc->data[pos].addr,
pc->data[pos].tele);
}
修改部分:
void ModifyContact(Contact* pc)
{
assert(pc);
char name[NameMax] = { 0 };
printf("请输入你要修改的人的名字");
scanf("%s", name);
int ret = Find(pc, name);
if (-1 == ret)
{
printf("对不起,没有这个人的信息");
return;
}
//修改就是重新录一遍进去
printf("请输入一个人的姓名:");
scanf("%s", pc->data[pc->sz].name);
printf("请输入一个人的年龄:");
scanf("%d", &pc->data[pc->sz].age);
printf("请输入一个人的性别:");
scanf("%s", pc->data[pc->sz].sex);
printf("请输入一个人的地址:");
scanf("%s", pc->data[pc->sz].addr);
printf("请输入一个人的电话:");
scanf("%s", pc->data[pc->sz].tele);
printf("修改完成");
可能有人会问?
我写这个时的疑问?这里有点想不通,为啥直接录进去就可以修改了呢?
原来的数又怎么处理呢?
解答:我这样跟你说一下吧,它这块儿是一个结构体,是数组嘛,对吗?
每个数组,每个下边里面存的是一个一个的结构体,这个你能理解吧。
如果我在就是VS里面,我定义一个结构体
然后我给这个结构体里面就是先进行一个一个初始化,初始了一个值,对吧?
然后我在后面再给它这里面的每一个成员变量再重新输入了一遍值,
你说它里面的值是不是会修改?那原来的值就被覆盖了嘛,对吧
你初始化的这肯定算你的初始化呀,对吧?我我为什么要初始化这个东西?
因为我害怕。我如果没有就是在后面修改的话,我用我这个初始化的东西,
它是不是就是一个随机的东西了?我就不可控制了对吧?
那我是不是得初始化一下?这块儿和你这个初始化没有啥关系。
就相当于你用一个int a=1,再然后让这个 a=2,
你说你这个a=in a=1,这个A=1,
还算不算初始化?它当然算初始化呀。
排序部分:
这里用到了qsort函数。看不懂的话,可以去前面几篇有讲到过哦~
cmp_by_name(void* e1, void* e2)
{
return strcmp(((struct PeoInfo*)e1)->name, ((struct PeoInfo*)e2)->name);
}
void SortContact(Contact* pc)
{
qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp_by_name);
}
好了,写完了静态部分的通讯录。我们是不是觉得这种有些小缺陷呢?就是它目前是设定了100个人的,但是当我们填完100人之后,我们就不可以再填了,这样,我们又不知道我们以后有多少个人要记录,满了之后再改,就显得十分麻烦。又我们在上一篇文章中写到了动态内存的开辟的文章了,我们是不是就可以使用一下,又节省空间。
现在我们先说明一下动态通讯录要改静态的什么内容?
首先是不是得改变一下初始化内容,增加部分,
//静态的
//typedef struct Contact
//{
// PeoInfo data[Max]; //存放人的信息的
// int sz; //当前已经存放的信息个数
//
//}Contact;
//动态的
typedef struct Contact
{
PeoInfo* data; 存放人的信息的 ,这里就不能使用数组了,直接用指针传地址过去
int sz; 当前已经存放的信息个数
int capacity; 当前通讯录的最大容量
}Contact;
利用扩容方式初始化通讯录
void InitContact(Contact* pc)
{
assert(pc);
pc->sz = 0;
PeoInfo* str = (PeoInfo*)calloc(DEFFAULT_SZ, sizeof(PeoInfo));
if (str == NULL)
{
perror("calloc");
return;
}
pc->data = str;
pc->capacity = DEFFAULT_SZ;
//加载文件信息到通讯录
LoadContact(pc);
}
检查是否扩容成功?
void CheckContact(Contact* pc)
{
//判断是否满
if (pc->sz == pc->capacity)
{
//增容
PeoInfo* str = (PeoInfo*)realloc(pc->data, (pc->capacity + INC_SZ) * sizeof(PeoInfo));
if (NULL==STR)
{
perror("calloc");
return;
}
pc->data = str;
pc->capacity += INC_SZ;
printf("增容成功\n");
}
}
增加部分:
void AddContact(Contact* pc)
{
assert(pc);
//判断增容是否需要
CheckContact(pc);
//增加一个人的信息
printf("请输入一个人的姓名:");
scanf("%s", pc->data[pc->sz].name);
printf("请输入一个人的年龄:");
scanf("%d", &pc->data[pc->sz].age);
printf("请输入一个人的性别:");
scanf("%s", pc->data[pc->sz].sex);
printf("请输入一个人的地址:");
scanf("%s", pc->data[pc->sz].addr);
printf("请输入一个人的电话:");
scanf("%s", pc->data[pc->sz].tele);
pc->sz++;
}
排序部分:
void SortContact(Contact* pc)
{
int i = 0;
for (i = 0; i < pc->sz - 1; i++)
{
int j = 0;
for (j = 0; j < pc->sz - 1 - i; j++)
{
int temp = { 0 };
if (strcmp(pc->data[j].name, pc->data[j + 1].name) > 0)
{
memcpy(&temp, &(pc->data[j].name), sizeof(struct PeoInfo*));
memcpy(&(pc->data[j].name), &(pc->data[j + 1].name), sizeof(struct PeoInfo*));
memcpy(&(pc->data[j + 1].name), &temp, sizeof(struct PeoInfo*));
}
}
}
printf("排序成功!");
}
解释:
解释下面代码:
memcpy(&temp, &(pc->data[j].name), sizeof(struct PeoInfo*))
memcpy(&(pc->data[j].name), &(pc->data[j + 1].name), sizeof(struct PeoInfo*));
memcpy(&(pc->data[j + 1].name), &temp, sizeof(struct PeoInfo*));
这里相当于加一个临时变量转换
eg:原理相当于
int temp=arr[i];
arr[i]=arr[i+1];
arr[i+1]=temp;
结束后要释放函数:
//退出后需要释放
void DestoryContact(Contact* pc)
{
assert(pc);
free(pc->data);
pc->data = NULL;
}
好了,结束了,下面我们各部分完整代码放下面:
Contact.h:
#pragma once
#include<assert.h>
#include<string.h>
#include<stdlib.h>
#include<stdio.h>
//#define Max 100
#define NameMax 20
//#define AgeMax 4
#define SexMax 4
#define AddrMax 40
#define TeleMax 12
#define DEFFAULT_SZ 3 //默认
#define INC_SZ 2 //加
//人的信息
typedef struct PeoInfo
{
char name[NameMax];
int age;
char sex[SexMax];
char addr[AddrMax];
char tele[TeleMax];
}PeoInfo;
//静态的
//typedef struct Contact
//{
// PeoInfo data[Max]; //存放人的信息的
// int sz; //当前已经存放的信息个数
//
//}Contact;
//动态的
typedef struct Contact
{
PeoInfo* data; //存放人的信息的
int sz; //当前已经存放的信息个数
int capacity; //当前通讯录的最大容量
}Contact;
void InitContact(Contact* pc);
void AddContact(Contact* pc);
void ShowContact(Contact* pc);
void DelContact(Contact* pc);
void SearchContact(Contact* pc);
void ModifyContact(Contact* pc);
void SortContact(Contact* pc);
void DestoryContact(Contact* pc);
void SaveContact(Contact *pc);
void LoadContact(Contact* pc);
Contact.c:
#define _CRT_SECURE_NO_WARNINGS 1
#include "Contact.h"
//void InitContact(Contact* pc)
//{
// assert(pc);
// pc->sz = 0;
// memset(pc->data, 0, sizeof(pc->data));
//}
void InitContact(Contact* pc)
{
assert(pc);
pc->sz = 0;
PeoInfo* str = (PeoInfo*)calloc(DEFFAULT_SZ, sizeof(PeoInfo));
if (str == NULL)
{
perror("calloc");
return;
}
pc->data = str;
pc->capacity = DEFFAULT_SZ;
}
//void AddContact(Contact* pc)
//{
// assert(pc);
// if (pc->sz == Max)
// {
// printf("通讯录已满,无法添加\n");
// return;
// }
// //增加一个人的信息
// printf("请输入一个人的姓名:");
// scanf("%s", pc->data[pc->sz].name);
// printf("请输入一个人的年龄:");
// scanf("%s", pc->data[pc->sz].age);
// printf("请输入一个人的性别:");
// scanf("%s", pc->data[pc->sz].sex);
// printf("请输入一个人的地址:");
// scanf("%s", pc->data[pc->sz].addr);
// printf("请输入一个人的电话:");
// scanf("%s", pc->data[pc->sz].tele);
//
// pc->sz++;
//}
void CheckContact(Contact* pc)
{
//判断是否满
if (pc->sz == pc->capacity)
{
//增容
PeoInfo* str = (PeoInfo*)realloc(pc->data, (pc->capacity + INC_SZ) * sizeof(PeoInfo));
if (str == NULL)
{
perror("calloc");
return;
}
pc->data = str;
pc->capacity += INC_SZ;
printf("增容成功\n");
}
}
void AddContact(Contact* pc)
{
assert(pc);
//判断增容是否需要
CheckContact(pc);
//增加一个人的信息
printf("请输入一个人的姓名:");
scanf("%s", pc->data[pc->sz].name);
printf("请输入一个人的年龄:");
scanf("%d", &pc->data[pc->sz].age);
printf("请输入一个人的性别:");
scanf("%s", pc->data[pc->sz].sex);
printf("请输入一个人的地址:");
scanf("%s", pc->data[pc->sz].addr);
printf("请输入一个人的电话:");
scanf("%s", pc->data[pc->sz].tele);
pc->sz++;
}
void ShowContact(const Contact* pc)
{
assert(pc);
int i = 0;
printf("%-20s\t %-4s\t %-4s\t %-40s\t %-12s\n ", "名字", "年龄", "性别", "地址", "电话");
for (i = 0; i < pc->sz; i++)
{
printf("%-20s\t %-4d\t %-4s\t %-40s\t %-12s\n", pc->data[i].name,
pc->data[i].age,
pc->data[i].sex,
pc->data[i].addr,
pc->data[i].tele);
}
}
int Find(const Contact* pc, char name[])
{
assert(pc);
int i = 0;
for (i = 0; i < pc->sz; i++)
{
if (strcmp(pc->data[i].name, name) == 0)
{
return i;
}
}
return -1;
}
void DelContact(Contact* pc)
{
assert(pc);
char name[NameMax] = { 0 };
if (pc->sz == 0)
{
printf("不好意思,没有可以删除的人");
return;
}
printf("请选择你要删除的人:");
scanf("%s", name);
int ret = Find(pc, name);
if (-1 == ret)
{
printf("没有这个人,请再次查看是否输入正确?\n");
return;
}
int i = 0;
for (i = ret; i < pc->sz - 1; i++)
{
pc->data[i] = pc->data[i + 1];
}
pc->sz--;
printf("删除成功\n");
}
void SearchContact(const Contact* pc)
{
assert(pc);
char name[NameMax] = { 0 };
printf("请输入你要查找的名字");
scanf("%s", name);
int pos = Find(pc, name);
if (-1 == pos)
{
printf("不好意思,没有这个人的信息");
return;
}
//打印信息
printf("%-20s\t %-4s\t %-4s\t %-40s\t %-12s\n ",
"名字", "年龄", "性别", "地址", "电话");
printf("%-20s\t %-4d\t %-4s\t %-40s\t %-12s\n",
pc->data[pos].name,
pc->data[pos].age,
pc->data[pos].sex,
pc->data[pos].addr,
pc->data[pos].tele);
}
void ModifyContact(Contact* pc)
{
assert(pc);
char name[NameMax] = { 0 };
printf("请输入你要修改的人的名字");
scanf("%s", name);
int ret = Find(pc, name);
if (-1 == ret)
{
printf("对不起,没有这个人的信息");
return;
}
//修改就是重新录一遍进去
printf("请输入一个人的姓名:");
scanf("%s", pc->data[pc->sz].name);
printf("请输入一个人的年龄:");
scanf("%d", &pc->data[pc->sz].age);
printf("请输入一个人的性别:");
scanf("%s", pc->data[pc->sz].sex);
printf("请输入一个人的地址:");
scanf("%s", pc->data[pc->sz].addr);
printf("请输入一个人的电话:");
scanf("%s", pc->data[pc->sz].tele);
printf("修改完成");
}
//cmp_by_name(void* e1, void* e2)
//{
// return strcmp(((struct PeoInfo*)e1)->name, ((struct PeoInfo*)e2)->name);
//}
//void SortContact(Contact* pc)
//{
// qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp_by_name);
//}
void SortContact(Contact* pc)
{
int i = 0;
for (i = 0; i < pc->sz - 1; i++)
{
int j = 0;
for (j = 0; j < pc->sz - 1 - i; j++)
{
int temp = { 0 };
if (strcmp(pc->data[j].name, pc->data[j + 1].name) > 0)
{
memcpy(&temp, &(pc->data[j].name), sizeof(struct PeoInfo*));
memcpy(&(pc->data[j].name), &(pc->data[j + 1].name), sizeof(struct PeoInfo*));
memcpy(&(pc->data[j + 1].name), &temp, sizeof(struct PeoInfo*));
}
}
}
printf("排序成功!");
}
//退出后需要释放
void DestoryContact(Contact* pc)
{
assert(pc);
free(pc->data);
pc->data = NULL;
}
test.c:
#define _CRT_SECURE_NO_WARNINGS 1
#include "Contact.h"
void menu()
{
printf("###########################\n");
printf("######1.Add 2.del ####\n");
printf("######3.search 4.modify####\n");
printf("######5.show 6.sort ####\n");
printf("######0.exit ####\n");
printf("###########################\n");
}
//枚举方式
enum Option
{
EXIT,
ADD,
DEL,
SEARCH,
MODIFY,
SHOW,
SORT
};
int main()
{
Contact con;
InitContact(&con);
int input = 0;
do
{
menu();
printf("请输入你想实现的业务数字:");
scanf("%d", &input);
switch (input)
{
case ADD:
AddContact(&con);
break;
case DEL:
DelContact(&con);
break;
case SEARCH:
SearchContact(&con);
break;
case MODIFY:
ModifyContact(&con);
break;
case SHOW:
ShowContact(&con);
break;
case SORT:
SortContact(&con);
break;
case EXIT:
DestoryContact(&con);
printf("退出游戏");
break;
default:
printf("输入错误,请重新选择");
break;
}
} while (input);
return 0;
}
最后的最后,我希望小伙伴们,能够在学习中收获满满,生活上也是顺顺利利,开开心心
事事如意,保持好那份初心!
标签:sz,语言,pc,Contact,通讯录,printf,动态,data,name From: https://blog.csdn.net/go_bai/article/details/144129103