C语言结构体练习:【通讯录(静态数组简易版)的实现】

全文目录

  • 前言
  • 模块和功能划分
  • 数据类型的选择
    • 功能序号类型 `enum`
    • 个人信息类型 `PeoInfo`
    • 通讯录类型 `Contact`
  • ‍ 功能的实现
    • 初始化通讯录 `InitContact`
    • 添加功能 `AddContact`
    • 打印功能 `PrintContact`
    • 删除联系人 `DeleteContact`
      • 通过名字查找对应下标 `FindByName`
    • 查找联系人 `SearchContact`
    • 修改联系人信息 `ModifyContact`
    • 清空通讯录 `EmptyContact`
    • 排序功能 `SortContact`
  • 总结

前言

前面我们学习了C语言的结构体等自定义类型的知识,乌泱泱的一大堆知识,没有练习肯定是学不扎实的,所以今天我们将前面学到的所有C语言知识整合起来进行实现一个小项目:通讯录(静态数组简易版),达到一个复习的目的。

模块和功能划分

我们实现的通讯录主要有以下几个功能:

  1. 退出(exit)
  2. 添加(add)
  3. 删除(delete)
  4. 查找(search)
  5. 修改(modify)
  6. 打印(print)
  7. 清空(empty)
  8. 排序(sort)

同时为了方便调试和代码的美观,我们将代码分为三个源文件:test.c, contact.h, contact.c
C语言结构体练习:【通讯录(静态数组简易版)的实现】_第1张图片

数据类型的选择

功能序号类型 enum

对于各种功能,在实现的时候是通过switch case 语句来实现各种功能的:

do {
	menu();
	printf("请选择->");
	scanf("%d", &input);
	switch (input) {
	case 1: 	// 添加
		...
		break;
	case 2: 	// 删除
		...
		break;
	case 3: 	// 查找
		...
		break;
	case 4: 	// 修改
		...
		break;
	case 5: 	// 打印
		...
		break;
	case 6: 	// 清空
		...
		break;
	case 7: 	// 排序
		...
		break;
	case 0: 	// 退出
		...
		break;
	default: 	// 输入其他提示错误
		printf("选择错误\n");
	}
	
} while (input);

我们可以使用枚举类型将功能和对应的序号关联起来,这样代码的可读性就能大大地提高了:

enum Option 
{
	EXIT,	// 0
	ADD,	// 1
	DELETE, 	// 2
	SEARCH, 	// 3
	MODIFY, 	// 4
	PRINT, 	// 5
	EMPTY, 	// 6
	SORT 	// 7
};

do {
	menu();
	printf("请选择->");
	scanf("%d", &input);
	switch (input) {
	case ADD: 	// 添加
		...
		break;
	case DELETE: 	// 删除
		...
		break;
	case SEARCH: 	// 查找
		...
		break;
	case MODIFY: 	// 修改
		...
		break;
	case PRINT: 	// 打印
		...
		break;
	case EMPTY: 	// 清空
		...
		break;
	case SORT: 	// 排序
		...
		break;
	case EXIT: 	// 退出
		...
		break;
	default: 	// 输入其他提示错误
		printf("选择错误\n");
	}
	
} while (input);

个人信息类型 PeoInfo

对于一个人的信息,基本上都是通过字符串来描述,都需要使用字符数组来存放,数组的长度可以使用宏定义来进行替换,方便后期管理。对于每个人的信息我们可以将其定义为结构体:

#define MAX_NAME 20
#define MAX_SEX 3
#define MAX_AGE 3
#define MAX_TELE 12
#define MAX_ADDRS 30

typedef struct PeoInform 
{
	char name[MAX_NAME];
	char sex[MAX_SEX];
	char age[MAX_AGE];
	char telephon[MAX_TELE];
	char addrs[MAX_ADDRS];
} PeoInform;

通讯录类型 Contact

通讯录的是存放所有人的信息的,那么需要能够存放所有人的信息的空间,我们直接使用数组来实现,因为添加操作的时候我们需要标记哪个位置可以使用,所以需要使用size来记录通讯录的大小。

#define MAX 1000 	// 通讯录人数的上限

typedef struct Contact 
{
	PeoInform data[1000];
	int size;
} Contact;

‍ 功能的实现

数据的类型确定了,我们就可以来实现各种功能了。

初始化通讯录 InitContact

由于通讯录是一个结构体,定义出来的又是局部变量,其内容是随机值。所以在使用之前需要先初始化一下,为了后期更好的维护,还是通过函数来进行初始化。

// 初始化
void InitContact(Contact* con)
{
	assert(con);
	con->size = 0;
	memset(con->data, 0, sizeof(con->data));
}

添加功能 AddContact

因为有了size,所以新加入的联系人可以之间存放在data数组的size位置上。如果

// 添加联系人
void AddContact(Contact* con)
{
	assert(con);
	puts("");

	if (con->size == MAX)	// 满了就不能再添加
	{
		puts("通讯录已满!!!");
	}
	else
	{
		printf("请输入姓名 ->");
		scanf("%s", con->data[con->size].name);
		printf("请输入性别 ->");
		scanf("%s", con->data[con->size].sex);
		printf("请输入年龄 ->");
		scanf("%s", con->data[con->size].age);
		printf("请输入电话号码 ->");
		scanf("%s", con->data[con->size].telephon);
		printf("请输入地址 ->");
		scanf("%s", con->data[con->size].addrs);
		puts("");

		con->size++;

		printf("添加成功!\n");
	}
}

打印功能 PrintContact

添加成功后我们可以通过打印功能来进行查看,在参数方面,因为我们只是访问一下数据,所以加上const修饰一下比较好。

// 打印联系人的信息
void PrintContact(const Contact* con)
{
	assert(con);

	printf("%-20s %-5s %-5s %-12s %-30s\n",
			"名字", "性别", "年龄", "电话号码", "地址");
	
	for (int i = 0; i < con->size; i++) 
	{
		printf("%-20s %-5s %-5s %-12s %-30s\n", 
			con->data[i].name, con->data[i].sex, 
			con->data[i].age, con->data[i].telephon, 
			con->data[i].addrs);
	}
}

删除联系人 DeleteContact

通过名字查找对应下标 FindByName

删除联系人一般是按照名字来进行删除的,所以我们需要先通过名字找到对应的下标再进行删除,因为后面需要查找的功能也需要通过名字来找人,所以这里之间实现一个函数:FindByName

// 通过名字来寻找联系人所在的下标
int FindByName(Contact* con, char* name)
{
	int i = 0;
	for (; i < con->size; i++)
	{
		if (strcmp(con->data[i].name, name) == 0) return i;
	}

	return -1;
}

如果通讯录中没有该名字,提示后返回,如果有,找到后通过覆盖的方式进行删除

// 删除指定联系人
void DeleteContact(Contact* con)
{
	assert(con);
	puts("");
	// 1. 找到联系人
	char name[MAX_NAME] = { 0 };
	printf("请输入需要删除的联系人的姓名->");
	scanf("%s", name);
	int pos = FindByName(con, name);


	// 2. 覆盖删除联系人
	if (pos == -1)
	{
		puts("");
		puts("无该联系人!!!");
	}
	else
	{
		for (int i = pos; i < con->size - 1; i++) 
		{
			con->data[i] = con->data[i + 1];
		}
		con->size--;
		printf("删除成功!\n");
	}
}

查找联系人 SearchContact

通过名字查找,找到后直接输出信息,没找到提示后返回

// 查找指定联系人
void SearchContact(const Contact* con)
{
	assert(con);

	puts("");
	// 1. 找到联系人
	char name[MAX_NAME] = { 0 };
	printf("请输入需要删除的联系人的姓名->");
	scanf("%s", name);
	int pos = FindByName(con, name);

	if (pos == -1)
	{
		puts("找不到该联系人???");
	}
	else
	{
		printf("%-20s %-5s %-5s %-12s %-30s\n",
			"名字", "性别", "年龄", "电话号码", "地址");

		printf("%-20s %-5s %-5s %-12s %-30s\n",
			con->data[pos].name, con->data[pos].sex,
			con->data[pos].age, con->data[pos].telephon,
			con->data[pos].addrs);
	}
}

修改联系人信息 ModifyContact

名字作为关键字来修改个人信息。

// 修改指定联系人信息
void ModifeContact(Contact* con)
{
	assert(con);

	puts("");
	// 1. 找到联系人
	char name[MAX_NAME] = { 0 };
	printf("请输入需要删除的联系人的姓名->");
	scanf("%s", name);
	int pos = FindByName(con, name);

	if (pos == -1)
	{
		puts("找不到该联系人???");
	}
	else
	{
		printf("请输入姓名 ->");
		scanf("%s", con->data[pos].name);
		printf("请输入性别 ->");
		scanf("%s", con->data[pos].sex);
		printf("请输入年龄 ->");
		scanf("%s", con->data[pos].age);
		printf("请输入电话号码 ->");
		scanf("%s", con->data[pos].telephon);
		printf("请输入地址 ->");
		scanf("%s", con->data[pos].addrs);
		printf("\n");

		printf("修改成功!\n");

		printf("%-20s %-5s %-5s %-12s %-30s\n", 
				"名字", "性别", "年龄", "电话号码", "地址");

		printf("%-20s %-5s %-5s %-12s %-30s\n", 
				con->data[pos].name, con->data[pos].sex, 
				con->data[pos].age, con->data[pos].telephon, 
				con->data[pos].addrs);
	}
}

清空通讯录 EmptyContact

因为全部的访问操作都跟size有关,所以清空时只需要将size置为0即可。

// 清空通讯录
void EmptyContact(Contact* con)
{
	assert(con);

	con->size = 0;
	printf("清空成功!\n");
}

排序功能 SortContact

还是老样子,用名字作为关键字,这里我使用的是冒泡排序,相对简单一点。

// 通过姓名排序
void SortContact(Contact* con)
{
	assert(con);

	for (int i = 0; i < con->size; i ++)
		for (int j = 0; j < con->size - 1 - i; j++)
		{
			if (strcmp(con->data[j].name, con->data[j + 1].name) > 0)
			{
				PeoInform temp = con->data[j];
				con->data[j] = con->data[j + 1];
				con->data[j + 1] = temp;
			}
		}

	puts("排序成功");
}

总结

以上就是第一个版本的通讯录的实现了。看似简单,但是对C语言的基础知识也是有一定的考验的,想要打牢基础还是要多写写联系一下的。

源码地址:静态数组版通讯录

你可能感兴趣的:(C语言,c语言,算法,数据结构)