C语言实现简单通讯录

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

通过对C语言结构体的深入学习,终于能够自主实现简单通讯录的程序编写,希望在这里记录自己对C语言的学习,以及分享自己对该程序的思路和见解。


一、分析问题

1.通讯录,包括联系人的姓名,年龄,性别,电话号码和家庭地址五个成员变量,且他们的数据类型各不相同,所以首先创建一个结构体来存放联系人的信息。
2.通讯录不可能只包含一个人的信息,所以我们应该创建一个结构体数组以存放多个人的信息。因为我们需要一个标记来记录当前通讯录中存放了多少人的信息,又结构体可以成为另一个结构体的成员变量,所以我们可以再创建一个结构体,把结构体数组和标记作为新的结构体的成员变量。
3.通讯录的主要功能有增删改查,打印通讯录,对通讯录进行排序和清空。
增加联系人:往数组中增加元素,联系人个数加一;
删除联系人:找到想要删除联系人的数组下标,把该下标后的每一个元素向前覆盖,联系人个数减一。
修改联系人:按名字找到想要修改的联系人的下标,然后对其元素进行修改。
搜索联系人:按名字找到联系人的下标,进行打印。
打印通讯录:打印结构体数组。
排序通讯录:用C语言自带的库函数qsort()按名字进行排序。
清空通讯录:用内存函数memset()把结构体数组元素置零,再把标记置零。
4.通过对不同函数的说明可以发现,删,改,搜索都要利用联系人的名字来找到下标,所以我们可以创建这样一个函数,利用联系人的名字来找到他在结构体数组的下标。

二、函数具体功能的实现

1.结构体的创建

定义两个结构体,一个结构体用来保存联系人信息,另一个结构体用来报仇呢通讯录。

#define MAX_NAME 20
#define MAX_SEX 12
#define MAX_TELE 12
#define MAX_ADDR 20
#define MAX_SIZE 1000
//存储个人信息
typedef struct PeoInfo
{
	char name[MAX_NAME];
	int age;
	char sex[MAX_SEX];
	char tele[MAX_TELE];
	char addr[MAX_ADDR];
}PeoInfo;
//通讯录
typedef struct Contact
{
	PeoInfo data[MAX_SIZE];//最多能存储1000个人的信息
	int sz;//当前存储的联系人的个数
}Contact;

2.对结构体进行初始化

结构体刚初始化时,没有联系人的信息,所以sz置为0,用memset()内存函数初始化结构体数组。

void InitContact(Contact* pc)
{
	pc->sz = 0;
	memset(pc->data,0,sizeof(pc->data));//用memset内存函数初始化
}

3.增加联系人

首先判断通讯录是否装满,如果装满,给出提醒并返回,没有装满,存储联系人信息,通讯录存储联系人的个数加一。

void AddContact(Contact* pc)
{
	//判断通讯录是否已满
	if (pc->sz == MAX_SIZE)
	{
		printf("通讯录已满,不能添加!\n");
	}
	//如果通讯录未满
	else
	{
		printf("请输入姓名:");
		scanf("%s", pc->data[pc->sz].name);
		printf("请输入年龄:");
		scanf("%d", &(pc->data[pc->sz].age));
		printf("请输入性别:");
		scanf("%s", pc->data[pc->sz].sex);
		printf("请输入电话号码:");
		scanf("%s", pc->data[pc->sz].tele);
		printf("请输入地址:");
		scanf("%s", pc->data[pc->sz].addr);
		pc->sz++;
	}
}

4.find_by_name函数

在问题的分析中我们提出通讯录实现的删除、修改、查找的功能,都要通过名字来查找,所以我们创建一个函数来实现这个功能,且这个函数只能在该程序内使用,因此我们用statci来修饰。
在这个函数中,我们找到下标就返回,没找到,返回-1。

static int find_by_name(Contact* pc, char* tmp)
{
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		if (strcmp(pc->data[i].name, tmp) == 0)
			return i;
	}
	return -1;
}

5.删除联系人

寻找要删除联系人所在的数组下标,如果找到了,该下标后的每一个元素向前覆盖,联系人个数减一。没找到,给出提示并返回。

void DelContact(Contact* pc)
{
	//通讯录为空,不需要进行删除
	if (pc->sz == 0)
	{
		printf("该通讯录为空,无需删除!\n");
		return;
	}
	//如果通讯录不为空,先按名字找到需要删除的人的数组下标
	char tmp[MAX_NAME] = {0};
	printf("请输入需要删除人的姓名:");
	scanf("%s", tmp);
	int ret = find_by_name(pc, tmp);
	if (ret < 0)
	{
		printf("没有该联系人,删除失败\n");
	}
	else
	{
		int i = 0;
		for (i = ret; i < pc->sz - 1; i++)
		{
			pc->data[i] = pc->data[i + 1];
		}
		printf("删除成功!\n");
		pc->sz--;
	}
}

6.修改联系人信息

void ModifyContact(Contact* pc)
{
	printf("请输入你想修改的人的信息的名字:");
	char tmp[MAX_NAME] = { 0 };
	scanf("%s", tmp);
	int ret = find_by_name(pc, tmp);
	if (ret < 0)
	{
		printf("你想要修改的人信息不存在!");
		return;
	}
	else
	{
		printf("请输入修改后姓名:");
		scanf("%s", pc->data[ret].name);
		printf("请输入修改后年龄:");
		scanf("%d", &(pc->data[ret].age));
		printf("请输入修改后性别:");
		scanf("%s", pc->data[ret].sex);
		printf("请输入修改后电话号码:");
		scanf("%s", pc->data[ret].tele);
		printf("请输入修改后地址:");
		scanf("%s", pc->data[ret].addr);
		printf("修改成功!\n");
	}
}

7.查找联系人

void SearchContact(Contact* pc)
{
	printf("请输入你要查找人的姓名:");
	char tmp[MAX_NAME] = { 0 };
	scanf("%s", tmp);
	int ret = find_by_name(pc, tmp);
	if (ret < 0)
	{
		printf("你查找的人的信息不存在!\n");
	}
	else
	{
		printf("查询成功!\n");
		printf("%-15s\t%-5d\t%-5s\t%-12s\t%-20s\n", pc->data[ret].name, pc->data[ret].age, pc->data[ret].sex, pc->data[ret].tele, pc->data[ret].addr);
	}
}

8.按名字排序通讯录

利用qsort()函数,qsort函数第一个参数填要排序对象的首地址,第二个参数是要排序对象的个数,第三个参数是待排序对象中每个元素的大小(字节),第四个参数是函数,该函数决定了是按升序还是降序排列。

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

void SortContact(Contact* pc)
{
	qsort(pc->data, pc->sz, sizeof(pc->data[0]), sort_by_name);
	printf("排序成功!\n");
}

9.打印通讯录

void PrintContact(Contact* pc)
{
	int i = 0;
	printf("%-15s\t%-5s\t%-5s\t%-12s\t%-20s\n", "名字", "年龄", "性别", "电话", "地址");
	for (i = 0; i < pc->sz; i++)
	{
		printf("%-15s\t%-5d\t%-5s\t%-12s\t%-20s\n", pc->data[i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].tele, pc->data[i].addr);
	}
}

10.销毁通讯录

销毁的操作和创建一样。

void ClearContact(Contact* pc)
{
	memset(pc->data, 0, sizeof(pc->data));
	pc->sz = 0;
	printf("销毁成功!\n");
}

源码

我这里使用的是分文件编写,分别是Contact.h,Contact.c和test.c三个文件。
Contact.h

#define _CRT_SECURE_NO_WARNINGS 1

//创建一个通讯录
//通讯录包括:名字,年龄,性别,电话,住址
//功能:增加,删除,搜索,修改,排序,输出,清空


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


#define MAX_NAME 20
#define MAX_SEX 12
#define MAX_TELE 12
#define MAX_ADDR 20
#define MAX_SIZE 1000
//存储个人信息
typedef struct PeoInfo
{
	char name[MAX_NAME];
	int age;
	char sex[MAX_SEX];
	char tele[MAX_TELE];
	char addr[MAX_ADDR];
}PeoInfo;
//通讯录
typedef struct Contact
{
	PeoInfo data[MAX_SIZE];//最多能存储1000个人的信息
	int sz;//当前存储的联系人的个数
}Contact;

//通讯录初始化
void InitContact(Contact* pc);
//通讯录添加
void AddContact(Contact* pc);
//通讯录删除
void DelContact(Contact* pc);
//通讯录的打印
void PrintContact(Contact* pc);
//通讯录的查找
void SearchContact(Contact* pc);
//通讯录的修改
void ModifyContact(Contact* pc);
//通讯录的清空
void ClearContact(Contact* pc);
//通讯录的排序
void SortContact(Contact* pc);

Contact.c

#include "Contact.h"

void InitContact(Contact* pc)
{
	pc->sz = 0;
	memset(pc->data,0,sizeof(pc->data));//用memset内存函数初始化
}

void AddContact(Contact* pc)
{
	//判断通讯录是否已满
	if (pc->sz == MAX_SIZE)
	{
		printf("通讯录已满,不能添加!\n");
	}
	//如果通讯录未满
	else
	{
		printf("请输入姓名:");
		scanf("%s", pc->data[pc->sz].name);
		printf("请输入年龄:");
		scanf("%d", &(pc->data[pc->sz].age));
		printf("请输入性别:");
		scanf("%s", pc->data[pc->sz].sex);
		printf("请输入电话号码:");
		scanf("%s", pc->data[pc->sz].tele);
		printf("请输入地址:");
		scanf("%s", pc->data[pc->sz].addr);
		pc->sz++;
	}
}

static int find_by_name(Contact* pc, char* tmp)
{
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		if (strcmp(pc->data[i].name, tmp) == 0)
			return i;
	}
	return -1;
}

void DelContact(Contact* pc)
{
	//通讯录为空,不需要进行删除
	if (pc->sz == 0)
	{
		printf("该通讯录为空,无需删除!\n");
		return;
	}
	//如果通讯录不为空,先按名字找到需要删除的人的数组下标
	char tmp[MAX_NAME] = {0};
	printf("请输入需要删除人的姓名:");
	scanf("%s", tmp);
	int ret = find_by_name(pc, tmp);
	if (ret < 0)
	{
		printf("没有该联系人,删除失败\n");
	}
	else
	{
		int i = 0;
		for (i = ret; i < pc->sz - 1; i++)
		{
			pc->data[i] = pc->data[i + 1];
		}
		printf("删除成功!\n");
		pc->sz--;
	}
}

void PrintContact(Contact* pc)
{
	int i = 0;
	printf("%-15s\t%-5s\t%-5s\t%-12s\t%-20s\n", "名字", "年龄", "性别", "电话", "地址");
	for (i = 0; i < pc->sz; i++)
	{
		printf("%-15s\t%-5d\t%-5s\t%-12s\t%-20s\n", pc->data[i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].tele, pc->data[i].addr);
	}
}

void SearchContact(Contact* pc)
{
	printf("请输入你要查找人的姓名:");
	char tmp[MAX_NAME] = { 0 };
	scanf("%s", tmp);
	int ret = find_by_name(pc, tmp);
	if (ret < 0)
	{
		printf("你查找的人的信息不存在!\n");
	}
	else
	{
		printf("查询成功!\n");
		printf("%-15s\t%-5d\t%-5s\t%-12s\t%-20s\n", pc->data[ret].name, pc->data[ret].age, pc->data[ret].sex, pc->data[ret].tele, pc->data[ret].addr);
	}
}

void ModifyContact(Contact* pc)
{
	printf("请输入你想修改的人的信息的名字:");
	char tmp[MAX_NAME] = { 0 };
	scanf("%s", tmp);
	int ret = find_by_name(pc, tmp);
	if (ret < 0)
	{
		printf("你想要修改的人信息不存在!");
		return;
	}
	else
	{
		printf("请输入修改后姓名:");
		scanf("%s", pc->data[ret].name);
		printf("请输入修改后年龄:");
		scanf("%d", &(pc->data[ret].age));
		printf("请输入修改后性别:");
		scanf("%s", pc->data[ret].sex);
		printf("请输入修改后电话号码:");
		scanf("%s", pc->data[ret].tele);
		printf("请输入修改后地址:");
		scanf("%s", pc->data[ret].addr);
		printf("修改成功!\n");
	}
}

void ClearContact(Contact* pc)
{
	memset(pc->data, 0, sizeof(pc->data));
	pc->sz = 0;
	printf("清除成功!\n");
}

//排序用qsort()函数
int sort_by_name(const void* e1, const void* e2)
{
	return strcmp(((PeoInfo*)e1)->name, ((PeoInfo*)e2)->name);
}

void SortContact(Contact* pc)
{
	qsort(pc->data, pc->sz, sizeof(pc->data[0]), sort_by_name);
	printf("排序成功!\n");
}

test.c
在test.c文件中使用枚举类型,是为了使我在使用switch…case语句中实现功能时,混淆不同的函数。

#include "Contact.h"

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

void menu()
{
	printf("********************************\n");
	printf("**  1.add         2.del       **\n");
	printf("**  3.search      4.modify    **\n");
	printf("**  5.sort        6.print     **\n");
	printf("**         7.clear            **\n");
	printf("**         0.sort             **\n");
	printf("********************************\n");
}

int main()
{
	//创建通讯录,并初始化
	Contact con;
	InitContact(&con);
	int input = 0;
	do
	{
		menu();//打印菜单
		printf("请输入你想要进行的操作编号:");
		scanf("%d", &input);
		switch (input)
		{
		case ADD:
			AddContact(&con);
			break;
		case DEL:
			DelContact(&con);
			break;
		case PRINT:
			PrintContact(&con);
			break;
		case EXIT:
			printf("退出程序");
			break;
		case SEARCH:
			SearchContact(&con);
			break;
		case MODIFY:
			ModifyContact(&con);
			break;
		case CLEAR:
			ClearContact(&con);
			break;
		case SORT:
			SortContact(&con);//按名字
			break;
		default:
			printf("请输入正确的操作数:");
			break;
		}
	} while (input);

	return 0;
}

总结

这里只是简单通讯录的编写,代码中有很多不完善的地方,例如如果添加了相同的联系人,并没有去重功能,也不会有提醒,如果两个联系人只是名字相同,程序又该怎么完善,等等。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值