c语言动态通讯录

首先我们得明确它的基本功能,信息:

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;
}

 最后的最后,我希望小伙伴们,能够在学习中收获满满,生活上也是顺顺利利,开开心心

事事如意,保持好那份初心!

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值