用c实现 通讯录 的6个功能(赋源码)

1. 前期准备

1.1. 创建三个文件

		  分别是"test.c", "contact.c","contact.h"
		test.c 是 用来测试,框架就存放在这
		contact.c 是 用来写实现功能的函数的
		contact.h 是 用来声明,结构体,以及“contact.c”写的函数,
		这样"test.c"就可以调用“contact.c”里的函数,实现跨文件调用。

1.2. 框架搭建

int main ()
{
	int input = 0;
	human contact [100] = { 0 };
	do
	{
		menu1();
		scanf("%d", &input);
		switch(input)
		{
			case 1:
				break;
			...
			case 6:
				break;
			default:
				printf("输入错误请认真输入!\n");
		}
	}while(input);
	return 0;
}
		  human 是 我自定义的类型,存放在"contact.h"如图

在这里插入图片描述

typedef struct human
{
	...
}human;
			  上面做的只是把自定义类型和创建结构体一起写了
			第一个human是结构体的,第二个human是自定义类型的名称
			顺变把两个.c文件用得上的系统的头文件也放在这这样只用声明一次就好啦
			
			  创建一个能存放100个结构体的数组
human contact[100] = { 0 };
			打印菜单menu1函数

在这里插入图片描述

	do
	{
		menu1();
		scanf("%d", &input);
		switch(input)
		{
			case 1:
				break;
			...
			case 6:
				break;
			default:
				printf("输入错误请认真输入!\n");
		}
	}while(input);
	return 0;
}
		   因为要实现6个不同的功能用switch刚刚好
		   input用来控制do...while循环和switch

2. 通讯录的6个功能

2.1.存储联系人的相关信息(姓名+年龄+性别+电话+地址)

			  test.c 的 传参部分
case 1:
	printf("请输入你要存放的联系人个数->");
	scanf("%d", &num);
	contact_save(contact, num);
	break;
			contact.c 的 函数部分
void contact_save(human* man, int num)
{
	for (int i = 0; i < num; i++)
	{
		printf("第%d位\n", i + 1);
		printf("请以名字 年龄 性别 电话 地址 以空格的方式作为分隔符:\n");
		scanf("%s %d %s %s %s", &man[i].name, &man[i].age,
			&man[i].sex, &man[i].number, &man[i].site);
	}
}
		num用来存放用户输入要存储联系人的个数
		human* man 接收 human类型的指针,而contact数组名为首元素的地址
		i + 1 是因为 i 是从0开始的 所以为了用户方便理解 + 1;

2.2. 增加联系人

		test.c 的 传参部分
case 2:
	printf("请输入你要增加的联系人个数->");
	scanf("%d", &add);
	contact_add(contact, num, add);
	break;
		contact.c 的 函数部分
void contact_add(human* man, int num, int add)
{
	for (int i = num; i < num + add; i++)
	{
		printf("第%d位\n", i + 1);
		printf("请以名字 年龄 性别 电话 地址 以空格的方式作为分隔符:\n");
		scanf("%s %d %s %s %s", &man[i].name, &man[i].age,
			&man[i].sex, &man[i].number, &man[i].site);
	}
}
		add用来存放用户输入要增加联系人的个数

2.3. 删除联系人

test.c传参部分
char find[20] = { 0 };
case 3:
	printf("请输入你要删除联系人的姓名->");
	scanf("%s", &find);
	if (f = contact_find(contact, find, num, add))
		contact_delete(&contact[f - 1]);
	else
		printf("不存在该联系人\n");
	break;
		  传参之前先判断有没有这个联系人调用查找函数
		contact_find 调用完以后会返回整形当前函数所在的下标
		存放到f用f来判断是否存在
		
		
		contact.c函数部分
int contact_find(human* man, char* p, int num, int add)
{
	for (int i = 0; i < num + add; i++)
	{
		for (int j = 0; man[i].name[j] != '\0'; j++)
		{
			if (man[i].name[j] != p[j])
				break;
			if (p[j + 1] == '\0')
				return i + 1;
		}
	}
	return 0;
}
		  char*p 接收 find数组的首元素的地址
		第一个for 循环 num + add 通讯录目前有几个或者曾经有过几个
		联系人
		  第二个for 循环 man[i] 结构体数组contact的第 i 个元素
		.name[i] 把这个结构体的name数组的所有元素和*p所
		指向的字符数组进行对比一致返回 i  + 1 
		返回 i 是返回该函数的下标 ,+1 是为了避免返回值赋给
		test.c 里的 变量f 在if做判断时不会把第一个元素的下标“0”
		误认为没有联系人,所以做 +1 处理

void  contact_delete_inside(char* p)
{
	for (int i = 0; p[i] != '\0'; i++)
	{
		p[i] = 0;
	}
}
void contact_delete(human* man)
{
	man->age = 0;
	contact_delete_inside(man->name);
	contact_delete_inside(man->number);
	contact_delete_inside(man->sex);
	contact_delete_inside(man->site);
}
		把man 所指向的结构体的所有变量全部归0
		contact_delete_inside 遍历字符数组在遇到
		‘\0’之前全部归0

2.4. 查找联系人

	test.c 传参部分
case 4:
	printf("请输入你要查找联系人的姓名->");
	scanf("%s", &find);
	if (f = contact_find(contact, find, num, add))
		contact_one_printf(&contact[f - 1]);
	else
		printf("不存在该联系人\n");
	break;
	跟删除的功能传参部分差不多,就不多赘述了
	
	contact.c 函数部分
int contact_find(human* man, char* p, int num, int add)
{
	for (int i = 0; i < num + add; i++)
	{
		for (int j = 0; man[i].name[j] != '\0'; j++)
		{
			if (man[i].name[j] != p[j])
				break;
			if (p[j + 1] == '\0')
				return i + 1;

		}
	}
	return 0;
}
void contact_one_printf(human* man)
{
	printf("-----------------------------------------------------------\n");
	printf("%s %d %s %s %s\n", man->name, man->age,
		man->sex, man->number, man->site);
	printf("-----------------------------------------------------------\n");
}
		contact_find在删除也说了,不多说了
		contact_one_printf函数是为了只输出一个结构体的信息

2.5. 修改联系人

		test.c 传参部分
	if (f = contact_find(contact, find, num, add))
	{
		contact_one_printf(&contact[f - 1]);
		do
		{
			menu2();
			printf("请问输入需要修改项的编号->");
			scanf("%d", &change);
			switch (change)
			{
			case 1:
				printf("请输入修改的姓名\n");
				contact_change(contact[f - 1].name);
				contact_one_printf(&contact[f - 1]);
				break;
			case 2:
				printf("请输入修改的年龄\n");
				scanf("%d", &contact[f - 1].age);
				contact_one_printf(&contact[f - 1]);
				break;
			...
			...
			case 5:
				printf("请输入修改的地址\n");
				contact_change(contact[f - 1].site);
				contact_one_printf(&contact[f - 1]);
				break;
			case 0:
				printf("已退出联系人修改\n");
				break;
			default:
				printf("输入错误请重新输入!\n");
			}
		} while (change);
	}
	else
		printf("不存在该联系人\n");
	break;
		  这边省略号代表case 3 ~ 4 都是大同小异,其实你看上面就看出来了
		很多相同的冗余代码,为什么不改完全是懒,如果大家看着难受就直接
		上手吧,我下面会附 Gitee 的链接源码
		
		菜单2
void menu2()
{
	printf("----------------------------------------------------------\n");
	printf("-----------1.姓名       2.年龄       3.性别----------------\n");
	printf("-----------4.电话       5.地址       0.exit----------------\n");
	printf("----------------------------------------------------------\n");
}
		contact.c 函数部分 
void contact_change(char* p)
{
	char arr[20] = { 0 };
	scanf("%s", &arr);
	for (int i = 0; p[i] != '\0'; i++)
	{
		p[i] = arr[i];
		if (arr[i] == '\0')
			break;
	}
}
		把要修改的内容赋给 arr 再用arr 对 p 所指向的数组 进行覆盖·

2.6. 排序

		test.c  传参部分
case 6:
	do
	{
		menu2();
		printf("请问输入需要排序项的编号->");
		scanf("%d", &change);
		
		if (change > 0 && change < 6)
		{
			printf("你需要升序还是降序?升序请输入非0数,降序请输入0->");
			scanf("%d", &sort);
			contact_sort(contact, change, sort, num, add);
			contact_all_printf(contact, num, add);
		}
		else if (change == 0)
			break;
		else
			printf("输入错误请重新输入!\n");
	} while (change);
	break;
		if (change > 0 && change < 6)
		不管是用结构体的那个变量进行排序都用contact_sort函数
void contact_sort(human* man, int change, int sort, int num, int add)
{
	switch (change)
	{
	case 1:
		contact_sort_str(man, man->name, num, add, sort);
		break;
	case 2:
		contact_sort_str(man, &man->age, num, add, sort);
	case 3:
		contact_sort_str(man, man->sex, num, add, sort);
		break;
	case 4:
		contact_sort_str(man, man->number, num, add, sort);
		break;
	case 5:
		contact_sort_str(man, man->site, num, add, sort);
		break;
	}
}
		change存储用户的选择 根据选择传相应的参数
		
		contact.c 函数部分
		
		这边就把讲解写在代码块里面了,这一块太长了
		至于我们不用双斜杠作注解主要是代码块里注解
		的字颜色太淡了就只能这样了
void contact_sort_str(human* man,char* p, int num, int add, int sort)
{
	----------------------------
	用save作为交换的中转站
	---------------------------
	
	human save = { 0 };
	
	----------------------------------------------------------
	第一个循环主要是为了提高效率,其中z是代表下面的排序进行了几次
	进行一次就代表有一个结构体元素排序好了,那么用z去减下面的遍历
	次数从而减少不必要的遍历提高效率
	----------------------------------------------------------
	for (int z = 0; z < num + add; z++)
	{
		int j = 0;
	----------------------------------------------------------
	num + add 是 联系人的总数 
	-1 为了防止数组越界 因为下面的交换方式是用 man[j+1]来和man[j]
	的值来进行互换的 假如循环到第100个联系人,即就j = 100 那么
	j + 1101101个联系人并不存在,去进行赋值会导致把原来有效
	的值变成其他无效的随机值或者其他的什么值(摊手)
	至于,为什么(num + add)* 5353怎么来的?
	这边使用sizeof(contact)对存放结构体类型的数组查看他所占的字节
	即5300,再/100 就得出来53
	一个结构体占53字节,再加上char*只有访问1字节的权限,还有为了
	函数的通用性,那么不管此时传来的是结构体的那个成员变量那么只
	要给p + 53 就直接指向了下一个结构体的相同的成员变量的地址,
	至于j 控制要交换的结构体
	----------------------------------------------------------
		for (int i = 0; i < ((num + add - 1 - z) * 53); i+=53)
		{
			if (p[i] != '\0')
			{
				if (sort == 1)
				{
					if (p[i] < p[i + 53])
					{
						save = man[j];
						man[j] = man[j + 1];
						man[j + 1] = save;
					}
					j++;
				}
				else
				{
					if (p[i] > p[i + 53])
					{
						save = man[j];
						man[j] = man[j + 1];
						man[j + 1] = save;
					}
					j++;
				}
			}
		}
	}
}

一些补充

scanf("%d", &contact[f - 1].age);
		这个位置会报一个警告如图

在这里插入图片描述
这个是关结构体成员变量age的以下分两种情况

typedef struct human
{
	char age;
	char sex[10];
	char name[20];
	char number[12];
	char site[10];
}human;
typedef struct human
{
	char sex[10];
	char name[20];
	char number[12];
	char site[10];
	char age;
}human;
		  我想你应该在想就是把,char age 放在前后有什么区别么?
		区别在如age在前面时,你用%d 去给age赋值,在编译器给你的
		结构体分配内存时各个变量的内存其实基本是连续的(为什么说
		是基本呢?还有一个概念就是”结构体内存对齐”的概念,这里我
		就不详细说了有想了解的可以去看看其他的博客),
		所以在scanf("%d",&&contact[f - 1].age),%d默认对4个字符进行
		赋值,刚好我上面提到结构体的内存的连续,那么跟在age后面
		的sex就是在内存中age后面的,这就会导致sex的值被篡改。
		
		  至于,为什么放在后面没事可能是因为结构体的访问内存权限只有
		53字节的原因?导致放在后面就越界不了?具体的我也不太清楚,
		有知道的可以在评论区说说,我也当学习学习。

源码

contact.h

# include<stdio.h>
typedef struct human
{
	char sex[10];
	char name[20];
	char number[12];
	char site[10];
	char age;
}human;
void contact_save(human* man, int num);
void contact_add(human* man, int num, int add);
void contact_delete(human* man);
int contact_find(human* man, char* p, int num, int add);
void contact_change(char* p);
void contact_sort_str(human* man, char* p, int num, int add, int sort);
void contact_one_printf(human* man);
void contact_all_printf(human* man, int num, int add);

test.c

# define _CRT_SECURE_NO_WARNINGS 1
# include"contact.h"
void menu1()
{
	printf("-----------------------------------------------------------\n");
	printf("-----------1.存放联系人 2.增加联系人 3.删除联系人----------\n");
	printf("-----------4.查找联系人 5.修改联系人 6.排序      ----------\n");
	printf("-----------             0.exit                   ----------\n");
	printf("-----------------------------------------------------------\n");
}
void menu2()
{
	printf("-----------------------------------------------------------\n");
	printf("-----------1.姓名       2.年龄       3.性别----------------\n");
	printf("-----------4.电话       5.地址       0.exit      ----------\n");
	printf("-----------------------------------------------------------\n");
}
void contact_sort(human* man, int change, int sort, int num, int add)
{
	switch (change)
	{
	case 1:
		contact_sort_str(man, man->name, num, add, sort);
		break;
	case 2:
		contact_sort_str(man, &man->age, num, add, sort);
	case 3:
		contact_sort_str(man, man->sex, num, add, sort);
		break;
	case 4:
		contact_sort_str(man, man->number, num, add, sort);
		break;
	case 5:
		contact_sort_str(man, man->site, num, add, sort);
		break;
	}
}
int main()
{
	int input = 0;
	int num = 0;
	int add = 0;
	int del = 0;
	int f = 0;
	int change = 0;
	int sort = 0;
	char find[20] = { 0 };
	human contact [100] = { 0 };
	//printf("%d", sizeof(contact)); 
	do
	{
		menu1();
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			printf("请输入你要存放的联系人个数->");
			scanf("%d", &num);
			contact_save(contact, num);
			break;
		case 2:
			printf("请输入你要增加的联系人个数->");
			scanf("%d", &add);
			contact_add(contact, num, add);
			break;
		case 3:
			printf("请输入你要删除联系人的姓名->");
			scanf("%s", &find);
			if (f = contact_find(contact, find, num, add))
				contact_delete(&contact[f - 1]);
			else
				printf("不存在该联系人\n");
			break;
		case 4:
			printf("请输入你要查找联系人的姓名->");
			scanf("%s", &find);
			if (f = contact_find(contact, find, num, add))
				contact_one_printf(&contact[f - 1]);
			else
				printf("不存在该联系人\n");
			break;
		case 5:
			printf("请输入你要修改联系人的姓名->");
			scanf("%s", &find);
			if (f = contact_find(contact, find, num, add))
			{
				contact_one_printf(&contact[f - 1]);
				do
				{
					menu2();
					printf("请问输入需要修改项的编号->");
					scanf("%d", &change);
					switch (change)
					{
					case 1:
						printf("请输入修改的姓名\n");
						contact_change(contact[f - 1].name);
						contact_one_printf(&contact[f - 1]);
						break;
					case 2:
						printf("请输入修改的年龄\n");
						scanf("%d", &contact[f - 1].age);
						contact_one_printf(&contact[f - 1]);
						break;
					case 3:
						printf("请输入修改的性别\n");
						contact_change(contact[f - 1].sex);
						contact_one_printf(&contact[f - 1]);

						break;
					case 4:
						printf("请输入修改的电话\n");
						contact_change(contact[f - 1].number);
						contact_one_printf(&contact[f - 1]);
						break;
					case 5:
						printf("请输入修改的地址\n");
						contact_change(contact[f - 1].site);
						contact_one_printf(&contact[f - 1]);
						break;
					case 0:
						printf("已退出联系人修改\n");
						break;
					default:
						printf("输入错误请重新输入!\n");
					}
				} while (change);
			}
			else
				printf("不存在该联系人\n");
			break;
		case 6:
			do
			{
				menu2();
				printf("请问输入需要排序项的编号->");
				scanf("%d", &change);
				
				if (change > 0 && change < 6)
				{
					printf("你需要升序还是降序?升序请输入非0数,降序请输入0->");
					scanf("%d", &sort);
					contact_sort(contact, change, sort, num, add);
					contact_all_printf(contact, num, add);
				}
				else if (change == 0)
					break;
				else
					printf("输入错误请重新输入!\n");
			} while (change);
			break;
		case 0:
			printf("已退出!\n");
			break;
		default:
			printf("输入错误请认真输入!\n");
		}
	} while (input);
	contact_all_printf(contact, num, add);
	return 0;
}

contact.c

# define _CRT_SECURE_NO_WARNINGS 1
# include"contact.h"
void contact_save(human* man, int num)
{
	for (int i = 0; i < num; i++)
	{
		printf("第%d位\n", i + 1);
		printf("请以名字 年龄 性别 电话 地址 以空格的方式作为分隔符:\n");
		scanf("%s %d %s %s %s", &man[i].name, &man[i].age,
			&man[i].sex, &man[i].number, &man[i].site);
	}
}
void contact_add(human* man, int num, int add)
{
	for (int i = num; i < num + add; i++)
	{
		printf("第%d位\n", i + 1);
		printf("请以名字 年龄 性别 电话 地址 以空格的方式作为分隔符:\n");
		scanf("%s %d %s %s %s", &man[i].name, &man[i].age,
			&man[i].sex, &man[i].number, &man[i].site);
	}
}

void  contact_delete_inside(char* p)
{
	for (int i = 0; p[i] != '\0'; i++)
	{
		p[i] = 0;
	}
}
void contact_delete(human* man)
{
	man->age = 0;
	contact_delete_inside(man->name);
	contact_delete_inside(man->number);
	contact_delete_inside(man->sex);
	contact_delete_inside(man->site);
}

int contact_find(human* man, char* p, int num, int add)
{
	for (int i = 0; i < num + add; i++)
	{
		for (int j = 0; man[i].name[j] != '\0'; j++)
		{
			if (man[i].name[j] != p[j])
				break;
			if (p[j + 1] == '\0')
				return i + 1;

		}
	}
	return 0;
}
void contact_change(char* p)
{
	char arr[20] = { 0 };
	scanf("%s", &arr);
	for (int i = 0; p[i] != '\0'; i++)
	{
		p[i] = arr[i];
		if (arr[i] == '\0')
			break;
	}
}
void contact_sort_str(human* man,char* p, int num, int add, int sort)
{
	human save = { 0 };
	for (int z = 0; z < num + add; z++)
	{
		int j = 0;
		for (int i = 0; i < ((num + add - 1 - z) * 53); i+=53)
		{
			if (p[i] != '\0')
			{
				if (sort == 1)
				{
					if (p[i] < p[i + 53])
					{
						save = man[j];
						man[j] = man[j + 1];
						man[j + 1] = save;
					}
					j++;
				}
				else
				{
					if (p[i] > p[i + 53])
					{
						save = man[j];
						man[j] = man[j + 1];
						man[j + 1] = save;
					}
					j++;
				}
			}
		}

	}
}

void contact_one_printf(human* man)
{
	printf("-----------------------------------------------------------\n");
	printf("%s %d %s %s %s\n", man->name, man->age,
		man->sex, man->number, man->site);
	printf("-----------------------------------------------------------\n");
}
void contact_all_printf(human* man, int num,int add)
{
	int a = 0;
	for (int i = 0; i < num + add; i++)
	{
		if (man[i].name[0] != '\0')
		{
			printf("-----------------------------------------------------------\n");
			printf("第%d位\n", i + 1 - a);
			printf("%s %d %s %s %s\n", man[i].name, man[i].age,
				man[i].sex, man[i].number, man[i].site);
			printf("-----------------------------------------------------------\n");
		}
		else
			a++;	

	}
}
  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值