C语言小作业实现通讯录

实现通讯录主要使用到结构体和指针相关知识,这些知识在我的博客中都有介绍,欢迎观看。

源码:Contact · 斯文/mytest - 码云 - 开源中国 (gitee.com)

目录

1.  了解需求

2. 代码实现

2.1 创建合适的结构体变量来保存联系人信息。

2.2 创建通讯录

2.3 初始化通讯录

2.3 打印菜单,switch case 语句,实现选择。

2.4 增加函数的实现

2.5 查找函数的实现

2.6 删除函数

2.7 修改函数

2.8 排序函数

2.9 打印函数

3.优化为动态版本通讯录


1.  了解需求

首先我们了解一下需求:

1.1 可以保存1000个联系人信息,包括姓名,号码。

1.2 需要实现的功能:1增加,2删除,3修改,4查找,5排序,6打印,7退出

2. 代码实现

我选择将代码分为三个部分来实现,

1. contact.g  用于声明        包括创造结构体的说明,功能函数的声明,枚举,#define定义的标识符常量

2. contact.c 用于实现具体的函数功能,比如增加,删除,一系列的自定义函数。

3. test.c 主函数,调试程序

代码封装为3个部分,更加合理,便于调试,更有条理性。

2.1 创建合适的结构体变量来保存联系人信息。

typedef struct peoinfo
{
	char name[NAME_MAX];
	char tele[TELE_MAX];
}peoinfo;

创造一个结构体,包含俩个字符数组,用来存放联系人姓名和号码。但是字符数组的大小最好是通过 #define 定义的标识符常量,便于程序的创作及调试和后续如果有修改字符数组大小的需要。

#define NAME_MAX 7
#define TELE_MAX 12

2.2 创建通讯录

 虽然我们通过第一个结构体,可以保存一个联系人信息。但是如果直接使用这个结构体创造1000个变量,显然过于繁琐,也不太实际。

#define MAX 1000

typedef struct contact
{
	peoinfo data[MAX];

	int sz;
}contact;

我们选择使用结构体嵌套,结构体中,包含用联系人结构体创造的数组,数组的大小同样使用#define 定义。同时,为了掌握我们具体存入了多少个联系人信息,我们创建整形变量sz来保存。(关于结构体嵌套,我的关于结构体的博客有详细解释)

2.3 初始化通讯录

创造完通讯录后,其中的内容,比如sz都是随机值,我们需要将其重置为0.

contact con;

	Init_Contact(&con);

创造结构体 con ,使用初始化函数时需注意,我们不推荐直接传整个结构体,数据太大,没有必要,,而且 形参只是实参的一份临时拷贝,对于形参的修改不会影响实参,所以我们更推荐使用传递结构体的地址。

void Init_Contact(contact* pc)
{
	pc->sz = 0;
	memset((pc->data), 0, sizeof(pc->data));
}

使用结构体指针来接收参数,使用memset函数来初始化联系人数组的数据。

2.3 打印菜单,switch case 语句,实现选择。

enum option
{
	EXIT,
	ADD,
	DEL,
	SEARCH,
	MODIFY,
	SORT,
	PRINT,
};


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");
}
void test()
{
	int input = 0;

	contact con;

	Init_Contact(&con);

	do 
	{
		menu();
	    printf("请输入:>");
		scanf("%d", &input);
		switch (input)
		{
		case EXIT:
			printf("退出通讯录\n");
			break;
		case ADD:
			Addcontact(&con);
			break;
		case DEL:
			Delcontact(&con);
			break;
		case SEARCH:
			Searchcontact(&con);
			break;
		case MODIFY:
			Modifycontact(&con);
			break;
		case SORT:
			Sortcontact(&con);
			break;
		case PRINT:
		      Printcontact(&con);
			break;
		default:
			printf("输入错误,重新输入\n");
		}

	} while (input);

}


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

值得一提的是,我们可以使用枚举常量,来代替数字,增加代码的关联和可读性。

2.4 增加函数的实现

void Addcontact(contact* pc)
{
	printf("请输入姓名:>");
	scanf("%s", pc->data[pc->sz].name);

	printf("请输入号码:>");
	scanf("%s", pc->data[pc->sz].tele);

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

同样的,我们使用结构体指针来接收,但是要注意的是,当我们记录第一个联系人信息时,sz为0,我们增加信息时,可以直接用sz作为下标   pc->data[pc->sz].name,增加信息完成后,sz++ .

2.5 查找函数的实现

我们首先封装一个搜索函数,因为无论是修改,删除,查找函数,都需要搜索到这个数据,因此我们直接封装一个搜索函数,其他部分的函数也可以使用。

//封装一个查找函数    找到了返回下标,没找到返回 -1
int FindByName(contact* pc, char arr[])
{
	int j = 0;
	for (j = 0; j < pc->sz; j++)
	{
		if (0 == strcmp(pc->data[j].name, arr))
		{
			return j;
		}
	}
	return -1;
}

我们是通过姓名来查找,比较字符串是否相等,使用 strcmp 函数(之前的博客有分析)

查找函数

void Searchcontact(contact* pc)
{
	assert(pc);

	printf("请输入要查找联系人的姓名:>");
	
	char arr[NAME_MAX] = { 0 };

	scanf("%s", arr);

	int b = FindByName(pc, arr);

	if (b == -1)
	{
		printf("未找到联系人\n");
		return;
	}
	printf("%7s,%12s", "姓名", "号码");
	printf("%7s %12s\n", pc->data[b].name, pc->data[b].tele);
	
}

上面代码中   %7s   ,7的作用是以指定宽度来打印,实现右对齐,如果我们想实现左对齐,数字前加负号

2.6 删除函数

void Delcontact(contact* pc)
{
	assert(pc);
	//查找
	char arr[NAME_MAX] = { 0 };

	printf("请输入姓名:>");

	scanf("%s", arr);

	int b =  FindByName(pc, arr);
	//删除
	if (b == -1)
	{
		printf("未找到联系人\n");
		return;
	}
	int j = 0;
	for (j = b; j < pc->sz - 1; j++)
	{
		pc->data[j] = pc->data[j + 1];
	}
	pc->sz--;
	printf("删除成功。\n");
}

找到联系人信息后,我们可以选择将后一个数据复制到当前的位置上,依次类推,将后面所以的数据前移一个,实现删除功能。同时减少sz 。 但是我们实现循环时,需要注意避免越界访问。

 当我们需要删除的数据在下标为999,即最后一个元素时,我们可以看到后面没有数据前移。但是当sz减一时,就自动将最后一个数据重置。这样既删除了数据,又不会造成数据的越界访问。

我们在设计时,应该仔细考虑边界问题,实现功能的同时保证没有错误

2.7 修改函数

void Modifycontact(contact* pc)
{
	printf("请输入需要修改联系人的姓名:>");

	char arr[NAME_MAX] = { 0 };

	scanf("%s", arr);

	int b = FindByName(pc, arr);

	if (b == -1)
	{
		printf("未找到联系人\n");
		return;
	}
	printf("请输入修改后的姓名:>");
	scanf("%s", pc->data[b].name);
	printf("请输入修改后的联系人电话号码:>");
	scanf("%s", pc->data[b].tele);
    printf("修改完成\n");
	
}

找到数据后,直接输入,然后覆盖源数据。

2.8 排序函数

我选择使用qsort函数实现


//排序   qsort排序
void cmp_by_name(const void* p1, const void* p2)
{
	return strcmp(((contact*)p1)->data->name, ((contact*)p2)->data->name);
}

void Sortcontact(contact* pc)
{
	qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp_by_name);
	printf("排序成功.");
}

后面我会出一个qsort函数的博客,先不做分析(很快就出)

2.9 打印函数

oid Printcontact(contact* pc)
{
	printf("%-7s,%-12s\n", "姓名","号码");   
	int j = 0;
	for (j = 0; j < pc->sz; j++)
	{
		printf("%-7s %-12s\n", pc->data[j].name, pc->data[j].tele);
	}

}

退出函数,比较简单,do while()  括号中 为输入,输入为0时直接退出。

本文中的函数很多用指针来接收地址,因为他们的数据都是数组,数据名就是地址,也就没有用&

其他类型的数据传地址时记得使用哈。

3.优化为动态版本通讯录

本文介绍的为静态版本,较为基础,有较多优化空间,后续会分享不同的优化版本。

动态版本博客介绍:http://t.csdn.cn/snW0G

 源码分享:Contact2.0 · 斯文/mytest - 码云 - 开源中国 (gitee.com)

全文结束,谢谢观看!如果有什么不同的见解,评论区欢迎讨论。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值