通讯录---结构体实践

一、通讯录功能

1、保存1000个人的信息

(1)一个人的信息包括:名字、性别、年龄、电话、住址

2、增加联系人

3、删除联系人

4、修改联系人

5、查找联系人

6、排序

7、打印通讯录已有成员的信息

二、通讯录实现要求

1、采用多模块方式实现:

(1)测试模块:专门测试通讯录的功能。

test.c

(2)通讯录模块:实现通讯录的功能。

contact.h --- 接口的声明
contact.c --- 接口的实现

(3)类型的声明、函数的声明一般都放在头文件中。使用的时候只需引头文件。

三、通讯录的实现

1、整体的框架

(1)在test.c源文件下有test()函数,用来实现功能的选择:

//一般写法
void test()
{
	int input = 0;
	do
	{
		menu();//选择功能
		printf("请选择所需的功能:>");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			add();
			break;
		case 2:
			del();
			break;
		case 3:
			search();
			break;
		case 4:
			modify();
			break;
		case 5:
			sort();
			break;
		case 0:
			printf("退出通讯录\n");
			break;
		default:
			printf("输入错误,请重新输入:>\n");
		}

	} while (input);

}

也可以:使用枚举列举出通讯录功能的可能取值,在switch…case…语句中,直接使用枚举常量,提高代码的可读性。(也可以不使用枚举,就采用1,2,3…如正上方代码)

enum option
{
	EXIT,//默认0
	ADD,//默认1
	DEL,
	SEARCH,
	MODIFY,
	SORT,
	PRINT
};
//使用枚举

void test()
{
	int input = 0;
	Contact con;//通讯录


	do
	{
		menu();//选择功能
		printf("请选择所需的功能:>");
		scanf("%d", &input);
		switch (input)
		{
		case ADD:
			AddContact();
			break;
		case DEL:
			del();
			break;
		case SEARCH:
			search();
			break;
		case MODIFY:
			modify();
			break;
		case SORT:
			sort();
			break;
		case PRINT:
			print();
			break;
		case EXIT:
			printf("退出通讯录\n");
			break;
		default:
			printf("输入错误,请重新输入:>\n");
		}


	} while (input);

}

(2)在test()函数里调用menu()函数,打印菜单。

void menu()
{
	printf("**************************\n");
	printf("****1.add     2.del ******\n");
	printf("****3.search  4.modify****\n");
	printf("****5.sort    6.print ****\n");
	printf("****0.exit            ****\n");
	printf("**************************\n");
}

(3)创建通讯录

  • 直接使用 PeoInfo 创建data[1000] 数组,存放1000个人的信息。但考虑到打印已有成员信息时要记录已有成员的个数,创建变量 sz,记录通讯录中已经保存的信息个数。为了传参方便,直接将data[1000] 与 sz 放在结构体Contact中,传参的时候只需传Contact。
typedef struct Contact
{
	PeoInfo data[1000];//创建通讯录,可以保存1000个人的信息
	int sz;//记录通讯录中已经保存的信息个数

}Contact;
  • 在test()函数中 创建通讯录
Contact con;

在这里插入图片描述

2、保存1000个人的信息

(1)一个人的信息包括:名字、性别、年龄、电话、住址

//声明通讯录人的信息
typedef struct PeoInfo
{
	char name[20];
	char sex[5];
	int age;
	char tele[12];//电话一般十一位
	char addr[30];
 }PeoInfo;

(2)保存1000个人的信息

//创建包含1000个元素的数组
PeoInfo data[1000];//存放1000个人的信息

(3)补充:为了方便后期修改常数,直接define声明常量

#define MAX 1000
#define NAME_MAX 20
#define SEX_MAX 5
#define TELE_MAX 12
#define ADDR_MAX 30
typedef struct PeoInfo
{
	char name[NAME_MAX];
	char sex[SEX_MAX];
	int age;
	char tele[TELE_MAX];//电话一般十一位
	char addr[ADDR_MAX];
 }PeoInfo;

typedef struct Contact
{
	PeoInfo data[MAX];//创建通讯录,可以保存1000个人的信息
	int sz;//记录通讯录中已经保存的信息个数

}Contact;

3、初识化通讯录

(1)解释:在首次增加联系人前要将通讯录初始化,将sz初始化为0;将data[1000]中每个元素都初始化为0.

(2)初始化的实现

  • 函数参数Contact* pc ,是一个结构体指针,接收 con 的地址。
  • pc->data 此时data相当于数组的首元素,pc->data相当于data数组的起始地址。
  • memset( )函数—内存设置函数,记得添加头文件<string.h>
void* memset(void* dest,int c,size_t count);
void* dest 起始地址; 
int c 需要被改成的值;  
size_t  count 需要修改的范围(以字节为单位)。
memset 是以字节为单位来初始化内存单元的。
//初始化通讯录
void InitContact(Contact* pc)
{
	memset(pc->data,0,sizeof(pc->data));
	pc->sz = 0;
}

4、增加联系人

  • 记得判断通讯录是否已满
void AddContact(Contact* pc)
{
	if (pc->sz == MAX)
	{
		printf("通讯录已满,无法添加\n");
		return;
	}

	//录入信息
	printf("请输入名字:>");
	scanf("%s", pc->data[pc->sz].name);
	printf("请输入性别:>");
	scanf("%s", pc->data[pc->sz].sex);
	printf("请输入年龄:>");
	scanf("%d", &(pc->data[pc->sz].age));
	printf("请输入电话:>");
	scanf("%s", pc->data[pc->sz].tele);
	printf("请输入地址:>");
	scanf("%s", pc->data[pc->sz].addr);

	pc->sz++;
	printf("添加成功\n");
}

5、删除联系人

(1)首先判断通讯录是否为空,为空的话,就没必要删除。

(2)删除联系人包括两步:

  • 找到指定的联系人

    //1.先定义一个数组,存放指定人的信息
    //2.输入姓名(假设没有重名现象)
    //3.使用strcmp()来比较输入的名字与data数组中联系人的名字,当strcmp返回值为0时,表示两个字符串相等,此时返回下标。而查找指定联系人在其他功能处也要使用,所以写成函数,使用时直接调用。
    
    
    //查找指定联系人
    
    int FindByName(Contact* pc, char name[])
    {
    	assert(pc);
    	int i = 0;
    	for (i = 0; i < pc->sz; i++)
    	{
    		if (0 == strcmp(pc->data[i].name, name))//等于0表示两个字符串相等
    		{
    			return i;
    		}
    	}
    	return -1;
    }
    
    
  • 删除指定联系人

    //删除指定联系人的思想:
    //1.获取到指定联系人的下标(在找到指定联系人步骤中已经得到)
    //2.将它下标的下一位对应的元素赋值给它,此步骤相当于将其覆盖,然后依次覆盖。使用for循环实现。
    
//删除指定联系人
void DelContact(Contact* pc)
{
	assert(pc);
	if (pc->sz == 0)
	{
		printf("通讯录已空,无法删除\n");
	}
	
	//删除
	//1.找到指定联系人
	char name[NAME_MAX] = { 0 };
	printf("请输入要查找的联系人姓名:>");
	scanf("%s", name);
	int pos=FindByName(pc, name);
	if (pos == -1)
	{
		printf("要删除的人不存在\n");
		return;
	}
	//2.删除
	int j = 0;
	for (j = pos; j < pc->sz-1; j++) //假设j最大是999,那么j+1就是1000,越界,所以sz-1
	{
		pc->data[j] = pc->data[j + 1];
	}
	pc->sz--;
	printf("删除成功\n");

}

6、修改联系人

//修改指定联系人
void ModifyContact(Contact* pc)
{
	char name[NAME_MAX] = { 0 };
	printf("请输入要查找的联系人姓名:>");
	scanf("%s", name);
	int pos = FindByName(pc, name);
	if (pos == -1)
	{
		printf("要查找的人不存在\n");
		return;
	}
	printf("请输入修改后的姓名:>");
	scanf("%s", pc->data[pos].name);
	printf("请输入修改后性别:>");
	scanf("%s", pc->data[pos].sex);
	printf("请输入修改后年龄:>");
	scanf("%d", &(pc->data[pos].age));
	printf("请输入修改后电话:>");
	scanf("%s", pc->data[pos].tele);
	printf("请输入修改后地址:>");
	scanf("%s", pc->data[pos].addr);
	printf("修改成功\n");
	printf("%-20s  %-5s  %-5s  %-12s  %-30s\n", "姓名", "性别", "年龄", "电话号码", "地址");
	printf("%-20s  %-5s  %-5d  %-12s  %-30s\n", pc->data[pos].name,
		pc->data[pos].sex, pc->data[pos].age, pc->data[pos].tele,
		pc->data[pos].addr);//左对齐的效果
}

7、查找联系人

(1)通过姓名查找指定联系人,找到后返回下标。

(2)打印找到的联系人。

//查找联系人
void SearchContact(const Contact* pc)
{
	char name[NAME_MAX] = { 0 };
	printf("请输入要查找的联系人姓名:>");
	scanf("%s", name);
	int pos = FindByName(pc, name);
	if (pos == -1)
	{
		printf("要查找的人不存在\n");
		return;
	}
	printf("%-20s  %-5s  %-5s  %-12s  %-30s\n", "姓名", "性别", "年龄", "电话号码", "地址");
	printf("%-20s  %-5s  %-5d  %-12s  %-30s\n", pc->data[pos].name,
			pc->data[pos].sex, pc->data[pos].age, pc->data[pos].tele,
			pc->data[pos].addr);//左对齐的效果
	

}

8、排序

(1)思路:按照姓名排序,使用strcmp()函数,比较姓名;使用qsort()函数进行排序,但要自定义比较函数。
(2)qsort的使用:

void qsort( void *base, size_t num, size_t width, int (__cdecl *compare )(const void *elem1, const void *elem2 )   需要自定义比较函数,函数的参数是void*类型,即为需要排序的两个元素的地址。函数的返回类型是int );
//void *base 起始元素地址
//size_t num  元素个数
//size_t width  元素大小
//int (__cdecl *compare )(const void *elem1, const void *elem2 )  指针函数
//需要自定义比较函数,函数的参数是void*类型,即为需要排序的两个元素的地址。函数的返回类型是int

//只需要给qsort提供以上四种参数,qsort就会自动排序,只不过其中的第四个参数要自定义。
int cmp_by_name(const void* e1, const void* e2)
{
	return strcmp(((PeoInfo*)e1)->name, ((PeoInfo*)e2)->name);
}

void SortContact(Contact* pc)
{
	qsort(pc->data, pc->sz, sizeof(PeoInfo), cmp_by_name);
	printf("排序成功\n");
}

9、打印

  • 直接for循环,挨个输出data数组中的元素。
//打印已有信息
void PrintContact(const Contact* pc)
{
	assert(pc);
	int i = 0;
	printf("%-20s  %-5s  %-5s  %-12s  %-30s\n", "姓名", "性别", "年龄", "电话号码", "地址");
	for (i = 0; i < pc->sz; i++)
	{
		//printf("%20s  %5s  %5d  %12s  %30s\n", pc->date[i].name,
		//	pc->date[i].sex, pc->date[i].age, pc->date[i].tele,
		//	pc->date[i].addr);//右对齐的效果
		printf("%-20s  %-5s  %-5d  %-12s  %-30s\n", pc->data[i].name,
			pc->data[i].sex, pc->data[i].age, pc->data[i].tele,
			pc->data[i].addr);//左对齐的效果
	}
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值