C 语言写通讯录——

C 语言写通讯录——,第1张

——————————————我们先来看看通讯录大致结构————————————————


由此可知,我们实现通讯录得先保存个人信息,包括姓名、年龄、电话等,将其添加保存后可以进行增、删、查、改等功能——


目录

目录


一、实现个人信息添加:


二、信息的储存


三、通讯录的初始化

1.目录的初始化:

2.个人信息的初始化:


四、各项功能实现:

1.增加联系人:

2.删除 *** 作:

3.查找联系人:

4.打印联系人:

5.修改联系人:

6.联系人排序:

—————————————优化————————————————




一、实现个人信息添加:

我们可以用结构体进行个人信息的存储——

#define name_max 20
#define sex_max 6
#define number_max 11
#define addr_max 30

typedef struct PeoInfo
{
	char name[name_max];//名字
	char sex[sex_max];//性别
	int age;//年龄
	int number[number_max];//电话
	char addr[addr_max];//住址
}Peo;

这里结构体名称太长,我们可以用名字替换来缩短其命名,用define定义常量方便后期更改。



二、信息的储存

创建一个结构体,在结构体中创建数组进行数据存储——

#define Max 1000

typedef struct Contact
{
	Peo data[Max];
	int sum;//用来记录现存联系人大小及方便找到联系人位置
}Cont;

三、通讯录的初始化 1.目录的初始化:

enum Option
{
	Exit,
	Add,
	Delete,
	Search,
	Alter,
	Sort,
	Print
};

void menu()
{
	printf("************************************\n");
	printf("******  1.Add     2.Delete  ********\n");
	printf("******  3.Search  4.Alter   ********\n");
	printf("******  5.Sort    6.Print   ********\n");
	printf("******  0.Exit              ********\n");
	printf("************************************\n");

}

void test()
{
	int input = 0;

	Cont con;

	InitContact(&con);
	do
	{
		menu();
		printf("请选择:>");
		scanf("%d", &input);
		switch (input)
		{
		case Add:
			add_contact(&con);
			break;
		case Delete:
			DelContact(&con);
			break;
		case Search:
			SearchContact(&con);
			break;
		case Alter:
			AlterContact(&con); 
			break;
		case Sort:
			SortContact(&con);
			break;
		case Print:
			PrintContact(&con);
			break;
		case Exit:
			system("cls");
			printf("退出程序\n");
			break;
		default:
			printf("选择错误,请重新选择\n");
			break;
		}
	} while (input);
}

int main()
{
	test();
	return 0;
}

这里我们可以将目录分装成一个函数,运用枚举类型进行选择。


将主函数放置在一个测试文件中,再将通讯录分装成头文件(用来放置函数声明及头文件),再将实现的功能分装成一系列函数进行实现,方便后期调用及修改。


2.个人信息的初始化:

在创建了结构体后,内容需要进行初始化再进行赋值 *** 作——

void InitContact(struct Contact* pc)
{
	assert(pc);
	pc->sum = 0;
	memset(pc, 0, sizeof(pc->data));
}

在开启通讯录前先进行置为“0” *** 作。



四、各项功能实现: 1.增加联系人:

将结构体地址传入函数,通过地址找到其内容。


进行之前先用“assert”进行断言。


如果计数器——“sum”小于我们限制的最大存储值,则此结构体还可继续添加。


每次添加完成后可进行清屏保持屏幕整洁。


void add_contact(Cont* pc)
{
	assert(pc);
	if (pc->sum == Max)
	{
		printf("存储已满\n");
		return;
	}
	printf("请输入名字:>");
	scanf("%s", pc->data[pc->sum].name);
	printf("请输入性别:>");
	scanf("%s", pc->data[pc->sum].sex);
	printf("请输入年龄:>");
	scanf("%d", &(pc->data[pc->sum].age));
	printf("请输入电话:>");
	scanf("%s", pc->data[pc->sum].number);
	printf("请输入住处:>");
	scanf("%s", pc->data[pc->sum].addr);

	pc->sum++;
	system("cls");
	printf("添加完成.\n");
}
2.删除 *** 作:

在我们添加联系人后如果此人之后不再联系,则可进入删除 *** 作——要进行删除 *** 作,则以人名为查找方式,先在所有结构体成员中查找到此人才可进行删除。


而查找此联系人的方式最简单暴力的方法无非就是遍历了(后期进行排序后也可以排序后的结构体进行遍历,效率会提高)——找到此人在总和的位置后,返回此人位置,即可对此人进行删除(将后一个结构体内容向前进行覆盖)。


int FindCont(Cont* pc, const char* s1)
{
	assert(pc);
	int i = 0;
	while (i <= pc->sum)
	{
		int ret = strcmp(pc->data[i].name, s1);
		if (ret == 0)
		{
			return i;
		}
		i++;
	}
	return -1;
}


void DelContact(Cont* pc)
{
	assert(pc);
	if (pc->sum == 0)
	{
		printf("无可修改联系人\n");
		return;
	}

	char arr[name_max] = { 0 };
	printf("请输入需要查找的联系人:>");
	gets(arr);
	int ret = FindCont(pc, arr);
	if (ret != -1)
	{
		int j = 0;
		for (j = ret; j < pc->sum - 1; j++)
		{
			pc->data[j] = pc->data[j + 1];
		}

		pc->sum--;
		printf("删除成功\n");
	}
	else
	{
		printf("无此联系人,请重新输入\n");
	}
}
3.查找联系人:

此时我们可以借用前面删除 *** 作中的"FindCont"函数进行查找,然后将查找到的联系人进行打印

void SearchContact(const Cont* pc)
{
	assert(pc);
	if (pc->sum == 0)
	{
		system("cls");
		printf("无可修改联系人\n");
		return;
	}

	char arr[name_max] = { 0 };
	printf("请输入需要查找的联系人:>");
	scanf("%s", arr);
	int ret = FindCont(pc, arr);
	if (ret == -1)
	{
		system("cls");
		printf("要查找的人不存在\n");
		return;
	}
	system("cls");
	printf("%-20s %-5s %-5s %-12s %-30s\n", "姓名", "年龄", "性别", "电话", "地址");
	printf("%-20s %-5d %-5s %-12s %-30s\n", pc->data[ret].name, pc->data[ret].age, pc->data[ret].sex,
		pc->data[ret].number, pc->data[ret].addr);
}
4.打印联系人:

该代码不用修改我们可在传参时加“const”进行修饰——

void PrintContact(const Cont* pc)
{
	assert(pc);
	int i = 0;
	printf("%-20s %-5s %-5s %-12s %-30s\n", "姓名", "年龄", "性别", "电话", "地址");

	for (i = 0; i < pc->sum; i++)
	{
		printf("%-20s %-5d %-5s %-12s %-30s\n", pc->data[i].name, pc->data[i].age, pc->data[i].sex,
			pc->data[i].number, pc->data[i].addr);
	}

}
5.修改联系人:

同删除类似,修改需先找到此联系人才可进行后续 *** 作——我们可以修改其联系人内容——

void AlterContact(Cont* pc)
{
	assert(pc);
	if (pc->sum == 0)
	{
		system("cls");
		printf("无可修改联系人\n");
		return;
	}

	char arr[name_max] = { 0 };
	printf("请输入需要查找的联系人:>");
	scanf("%s", arr);
	int ret = FindCont(pc, arr);
	if (ret == -1)
	{
		system("cls");
		printf("要查找的人不存在\n");
		return;
	}
	printf("%-20s %-5s %-5s %-12s %-30s\n", "姓名", "年龄", "性别", "电话", "地址");
	printf("%-20s %-5d %-5s %-12s %-30s\n", pc->data[ret].name, pc->data[ret].age, pc->data[ret].sex,
		pc->data[ret].number, pc->data[ret].addr);
	printf("请选择需要%s修改的内容:>",pc->data[ret].name);
	printf("1.名字\t 2.年龄\t 3.性别\t 4.电话\t 5.住址\n");
	int a = 0;
	scanf("%d", &a);
	switch (a)
	{
	case 1:
		memset(pc->data->name, 0, sizeof(pc->data[ret].name));
		printf("请输入修改后的名字:>");
		char new_name[name_max] = { 0 };
		scanf("%s", new_name);
		strcpy(pc->data->name, new_name);
		printf("修改成功\n");
		break;
	case 2:
		memset(pc->data->age, 0, sizeof(pc->data[ret].age));
		printf("请输入修改后的年龄:>");
		scanf("%d", &pc->data[ret].age);
		printf("修改成功\n");
		break;
	case 3:
		memset(pc->data->sex, 0, sizeof(pc->data[ret].sex));
		printf("请输入修改后的性别:>");
		scanf("%s", pc->data[ret].sex);
		printf("修改成功\n");
		break;
	case 4:
		memset(pc->data->number, 0, sizeof(pc->data[ret].number));
		printf("请输入修改后的号码:>");
		scanf("%s", pc->data[ret].number);
		printf("修改成功\n");
		break;
	case 5:
		memset(pc->data->addr, 0, sizeof(pc->data[ret].addr));
		printf("请输入修改后的号码:>");
		scanf("%s", pc->data[ret].addr);
		printf("修改成功\n");
		break;
	default:
		printf("选择错误\n");
		break;
	}
}
6.联系人排序:

在添加完联系人后整个结构体会显得杂乱无章,此时我们可以用到排序的函数将通讯录按照人名进行排序——
 

int cmp_name(const void* e1, const void* e2)
{
	return strcmp(((Peo*)e1)->name, ((Peo*)e2)->name);
}

void SortContact(Cont* pc)
{
	assert(pc);
	qsort(pc->data, pc->sum, sizeof(pc->data[0]), cmp_name);
	PrintContact(pc);
}

注:(qsort函数使用方法及模拟实现请看—— qsort - C++ Reference)


—————————————优化————————————————

这里可以将储存联系人数量的结构体进行修改——

同上用“sum”表示记录人数,用“capacity”来表示最大容量:

typedef struct Contact
{
	Peo* data;//可以存放1000个人的信息
	int sum;//记录通讯中已经保存的信息个数
	int capacity;//记录通讯录当前的最大容量
}Cont;

此时我们初始化结构体也需要一点改变——

初始化最大值定义为三个,每当达到这个预定值,则进行扩容,(注释:malloc函数详见:malloc - C++ Reference,realloc函数详见:realloc - C++ Reference)

#define DEFUALT_MAX 3 

void InitContact(struct Contact* pc)
{
	pc->sum = 0;
	pc->capacity = DEFUALT_MAX;
	pc->data = (Peo*)malloc(pc->capacity * sizeof(Peo));

	if (pc->data == NULL)
	{
		perror("InitContact::malloc");
		return;
	}
	memset(pc->data, 0, sizeof(pc->data));
}


void CheckCapacity(struct Contact* pc)
{
	if (pc->sum == pc->capacity)
	{
		if (pc->sum == pc->capacity)
		{
			Peo* tmp = (Peo*)realloc(pc->data, (pc->capacity + 2) * sizeof(Peo));
			if (tmp != NULL)
			{
				pc->data = tmp;
			}
			else
			{
				perror("CheckCapacity::realloc");
				return;
			}
			pc->capacity += 2;
			printf("增容成功\n");
		}
	}
}

这里我们引用了动态分配函数,则在程序退出时候,需要释放内存,否则会引起内存泄漏等问题,则我们在末尾可以封装一个销毁函数。


void DestroyContact(Cont* pc)
{
	free(pc->data);
	pc->data = NULL;
	pc->capacity = 0;
	pc->sum = 0;
	printf("销毁成功\n");
}

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/568788.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-09
下一篇 2022-04-09

发表评论

登录后才能评论

评论列表(0条)

保存