动态增长的通讯录的实现


一、基本结构的实现

1.菜单

通讯录需要实现添加、删除、查找、展示、修改,基于此可以设计出下面的菜单。

代码如下(示例):

void menu()
{
	printf("0.exit\n1.add\n2.del\n");
	printf("3.search\n4.modify\n5.show\n\n");
}
int main()
{
	int input = 0;
	do
	{
		menu();
		scanf("%d", &input);
		switch (input)
		{
		case 0:
			printf("exit success\n\n");
			break;
		case 1:
			addContact(&con);
			break;
		case 2:
			delContact(&con);
			break;
		case 3:
			searchContact(&con);
			break;
		case 4:
			showContact(&con);
			break;
		case 5:
			modifyContact(&con);
			break;
		default:
			printf("input error\n\n");
			break;
		}
	} while (input);
	return 0;
}

这样一个简易的菜单就做好了,但是switch中的case语句后跟的全部是数字,在编写程序时不便于理解。

由于枚举常量在不初始化的情况下默认从0开始依次递增1,所以这里可以用枚举常量来实现,提高代码的可读性。

代码如下(示例):

void menu()
{
	printf("0.exit\n1.add\n2.del\n");
	printf("3.search\n4.modify\n5.show\n\n");
}
enum Option
{
	EXIT,//0
	ADD,//1
	DEL,//2
	SEARCH,//3
	MODIFY,//4
	SHOW//5
};
int main()
{
	int input = 0;
	do
	{
		menu();
		scanf("%d", &input);
		switch (input)
		{
		case EXIT:
			printf("exit success\n\n");
			break;
		case ADD:
			addContact(&con);
			break;
		case DEL:
			delContact(&con);
			break;
		case SEARCH:
			searchContact(&con);
			break;
		case SHOW:
			showContact(&con);
			break;
		case MODIFY:
			modifyContact(&con);
			break;
		default:
			printf("input error\n\n");
			break;
		}
	} while (input);
	return 0;
}

2.通讯录结构体

以下代码就可以实现最简单的功能。

代码如下(示例):

struct Info
{
	char name[20];
	int age;
	char tel[20];
};

但是上面的代码也有缺点,比如无法得知当前通讯录中已经存放的信息个数,如果名字或电话的最大长度超过20需要大量修改代码等等,所以可将其优化为下面的代码。

代码如下(示例):

#define NAME_MAX 20
#define TEL_MAX 14
#define MAX 1000

struct Info
{
	char name[NAME_MAX];
	int age;
	char tel[TEL_MAX];
};

struct Contact
{
	struct Info a[MAX];
	int sz;//存储当前通讯录中的信息个数
};

而要实现通讯录的动态增长就需要继续对struct Contuct改进。

代码如下(示例):

struct Contact
{
	struct Info *a;//存放信息
	int capacity;//通讯录存放的最大信息个数
	int sz;//通讯录当前存放的信息个数
};

二、通讯录功能的实现

1.通讯录的初始化

在main函数中建立一个通讯录结构体后,首先需要对其进行初始化,否则可能出现难以预料的问题。

(这里要注意,想要通过函数修改主函数内变量的值,就需要传变量的地址,否则无法修改,之后的代码同理)

代码如下(示例):

#define DEFAULT_CAP 4//为便于修改使用宏定义定义capacity的初始值
void initContact(struct Contact* pc)
{
	assert(pc);//检查pc是否为空指针
	pc->sz = 0;
	pc->a = (struct Info*)malloc(sizeof(struct Info)* DEFAULT_CAP);
	if (pc->a == NULL)//检查动态开辟是否成功
	{
		printf("init error\n");
		exit(1);
	}
	pc->capacity = DEFAULT_CAP;
}

2.添加信息

添加信息时要注意先检查当前通讯录是否已满,如果已满则需要扩容,否则直接添加。

代码如下(示例):

void addContact(struct Contact* pc)
{
	assert(pc);
	if (pc->sz == pc->capacity)//通讯录已满
	{
		//以扩容二倍为例
		pc->a = (struct Info*)realloc(pc->a, pc->capacity * 2 *(sizeof(struct Info)));
		if (pc->a == NULL)
		{
			printf("add1 error\n");
			return;
		}
		else
		{
			printf("add1 success\n");
			pc->capacity *= 2;//注意扩容成功后修改pc->capacity
		}
	}
	//在控制台依次给出输入提示并录入数据
	printf("name:");
	scanf("%s", pc->a[pc->sz].name);

	printf("age:");
	scanf("%d", &(pc->a[pc->sz].age));

	printf("tel:");
	scanf("%s", pc->a[pc->sz].tel);

	pc->sz++;//当前通讯录中的信息个数+1
	printf("add success\n\n");
}

3.删除信息

删除信息时首先要输入要删除信息的姓名,然后找到这个信息再删除。由于这里通过名字来定位信息的代码在之后也会多次用到,所以这里将它封装为函数来调用,这样可以让代码更加简洁,同时可读性更好。

代码如下(示例):

//由于查找不需要修改,所以用const保护pc的内容
int FindByName(const struct Contact* pc, char name[])
{
	int i = 0;
	//遍历寻找信息
	for (i = 0; i < pc->sz; i++)
	{
		if (strcmp(pc->a[i].name, name) == 0)
			return i;
	}
	return -1;//找不到返回-1
}

void delContact(struct Contact* pc)
{
	assert(pc);
	if (pc->sz == 0)//判断通讯录是否为空
		printf("empty\n\n");
	else
	{
		printf("name:");
		char name[NAME_MAX];
		scanf("%s", name);//从控制台输入要删除信息的名字
		int pos = FindByName(pc, name);//找到该信息的位置
		if (pos == -1)//找不到直接返回
		{
			printf("delete error\n");
			return;
		}
		int i = 0;
		//从pos开始,将后面的信息依次向前挪一位(删除pos位置的数据)
		for (i = pos; i < pc->sz - 1; i++)
		{
			pc->a[i] = pc->a[i + 1];
		}
		pc->sz--;//注意pc->sz--
		printf("del success\n\n");
	}
}

4.查找信息

查找时可以借用FindByName函数来实现。

代码如下(示例):

//加const保护pc的内容
void searchContact(const struct Contact* pc)
{
	assert(pc);
	printf("name\n");
	char name[NAME_MAX];
	scanf("%s", name);//输入要查找信息的姓名
	int pos = FindByName(pc, name);
	if (pos == -1)
		printf("no\n");
	//找到后打印信息
	else
	{
		printf("%-15s%-5s%-20s\n", "name", "age", "telephone");
		printf("%-15s%-5d%-20s\n", pc->a[pos].name, pc->a[pos].age, pc->a[pos].tel);
	}
}

5.展示信息

展示信息时按照一定的格式打印,看起来更加美观。

代码如下(示例):

void showContact(const struct Contact* pc)
{
	assert(pc);
	printf("%-15s%-5s%-20s\n", "name", "age", "telephone");
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		printf("%-15s%-5d%-20s\n", pc->a[i].name, pc->a[i].age, pc->a[i].tel);
	}
	printf("\n");
}

6.修改信息

代码如下(示例):

void modifyContact(struct Contact* pc)
{
	assert(pc);
	printf("name\n");
	char name[NAME_MAX];
	scanf("%s", name);
	int pos = FindByName(pc, name);//找到要修改信息的位置
	if (pos == -1)
		printf("no\n");
	else
	{
		//依次录入修改后的内容
		printf("name:");
		scanf("%s", pc->a[pos].name);

		printf("age:");
		scanf("%d", &(pc->a[pos].age));

		printf("tel:");
		scanf("%s", pc->a[pos].tel);

		printf("modify success\n\n");
	}
}

7.销毁通讯录

代码如下(示例):

void DestroyContact(struct Contact* pc)
{
	free(pc->a);
	pc->a = NULL;
	pc->capacity = 0;
	pc->sz = 0;
}

三、完整代码

contact.h

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

#define NAME_MAX 20
#define TEL_MAX 14
#define MAX 1000
#define DEFAULT_CAP 4

struct Info
{
	char name[NAME_MAX];
	int age;
	char tel[TEL_MAX];
};

struct Contact
{
	struct Info *a;
	int capacity;
	int sz;
};

void initContact(struct Contact* pc);

void addContact(struct Contact* pc);

void delContact(struct Contact* pc);

void showContact(const struct Contact* pc);

void searchContact(const struct Contact* pc);

void modifyContact(struct Contact* pc);

void DestroyContact(struct Contact* pc);

contact.c

#include "contact.h"


void initContact(struct Contact* pc)
{
	assert(pc);
	pc->sz = 0;
	pc->a = (struct Info*)malloc(sizeof(struct Info) * DEFAULT_CAP);
	if (pc->a == NULL)
	{
		printf("init error\n");
		exit(1);
	}
	pc->capacity = DEFAULT_CAP;
}

void addContact(struct Contact* pc)
{
	assert(pc);
	if (pc->sz == pc->capacity)
	{
		pc->a = (struct Info*)realloc(pc->a, pc->capacity * 2 *(sizeof(struct Info)));
		if (pc->a == NULL)
		{
			printf("add error\n");
			return;
		}
		else
		{
			printf("add1 success\n");
			pc->capacity *= 2;
		}
	}
	printf("name:");
	scanf("%s", pc->a[pc->sz].name);

	printf("age:");
	scanf("%d", &(pc->a[pc->sz].age));

	printf("tel:");
	scanf("%s", pc->a[pc->sz].tel);

	pc->sz++;
	printf("add success\n\n");
}

int FindByName(const struct Contact* pc, char name[])
{
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		if (strcmp(pc->a[i].name, name) == 0)
			return i;
	}
	return -1;
}

void delContact(struct Contact* pc)
{
	assert(pc);
	if (pc->sz == 0)
		printf("empty\n\n");
	else
	{
		printf("name:");
		char name[NAME_MAX];
		scanf("%s", name);
		int pos = FindByName(pc, name);
		if (pos == -1)
		{
			printf("delete error\n");
			return;
		}
		int i = 0;
		for (i = pos; i < pc->sz - 1; i++)
		{
			pc->a[i] = pc->a[i + 1];
		}
		pc->sz--;
		printf("del success\n\n");
	}
}

void showContact(const struct Contact* pc)
{
	assert(pc);
	printf("%-15s%-5s%-20s\n", "name", "age", "telephone");
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		printf("%-15s%-5d%-20s\n", pc->a[i].name, pc->a[i].age, pc->a[i].tel);
	}
	printf("\n");
}

void searchContact(const struct Contact* pc)
{
	assert(pc);
	printf("name\n");
	char name[NAME_MAX];
	scanf("%s", name);
	int pos = FindByName(pc, name);
	if (pos == -1)
		printf("no\n");
	else
	{
		printf("%-15s%-5s%-20s\n", "name", "age", "telephone");
		printf("%-15s%-5d%-20s\n", pc->a[pos].name, pc->a[pos].age, pc->a[pos].tel);
	}
}

void modifyContact(struct Contact* pc)
{
	assert(pc);
	printf("name\n");
	char name[NAME_MAX];
	scanf("%s", name);
	int pos = FindByName(pc, name);
	if (pos == -1)
		printf("no\n");
	else
	{
		printf("name:");
		scanf("%s", pc->a[pos].name);

		printf("age:");
		scanf("%d", &(pc->a[pos].age));

		printf("tel:");
		scanf("%s", pc->a[pos].tel);

		printf("modify success\n\n");
	}
}

void DestroyContact(struct Contact* pc)
{
	free(pc->a);
	pc->a = NULL;
	pc->capacity = 0;
	pc->sz = 0;
}

test.c

#include "contact.h"

void menu()
{
	printf("0.exit\n1.add\n2.del\n3.search\n4.modify\n5.show\n\n");
}

enum Option
{
	EXIT,
	ADD,
	DEL,
	SEARCH,
	MODIFY,
	SHOW
};

int main()
{
	int input = 0;
	struct Contact con;
	initContact(&con);
	do
	{
		menu();
		scanf("%d", &input);
		switch (input)
		{
		case EXIT:
			DestroyContact(&con);
			printf("exit success\n\n");
			break;
		case ADD:
			addContact(&con);
			break;
		case DEL:
			delContact(&con);
			break;
		case SEARCH:
			searchContact(&con);
			break;
		case SHOW:
			showContact(&con);
			break;
		case MODIFY:
			modifyContact(&con);
			break;
		default:
			printf("input error\n\n");
			break;
		}
	} while (input);
	return 0;
}

感谢阅读,如有错误请批评指正

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

山舟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值