用C语言实现-通讯录(静态)

用C语言实现-通讯录(静态),第1张

在掌握了C语言的指针,函数,结构体,并对他们有着一些了解之后。


可以试着完成一个通讯录。


实现思路:


一、创建好结构体

要做一个通讯录,它保存的联系人信息肯定有很多种类,可以把他们封装成一个结构体。


其中联系人包含信息有:姓名,性别,年龄,电话,住址

//联系人信息:姓名,性别,年龄,电话,住址
typedef struct PeoInFo
{
	char name[NAME_MAX];
	char sex[SEX_MAX];
	int age;
	char tele[TELE_MAX];
	char addr[ADDR_MAX];
}PeoInFo;            //这里重命名结构体名字为PeoInFo(增加可读性)

那通讯录其实就算这么多个联系人信息的集合呀。


(结构体嵌套)

因此可以创建一个通讯录结构体类型,其中包含:

1.联系人信息

2.保存了多少个信息

就是这个样子:

 


二、整体框架

依然是熟悉的do while结构。


先打印菜单,再根据菜单中的提示完成相应的选择。


为显得简洁易读,这里创建三个工作单元。


test.c: 代码的逻辑思路。


contact.h: 所用到的头文件和函数的声明、全局变量的定义

contact.h:        实现的函数的具体代码

先将test.c的代码放出来:

#define _CRT_SECURE_NO_WARNINGS 1

#include"contact.h"
void menu()
{
	printf("\n\n\n************************************\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;

	//初始化通讯录
	InitContact(&con);
	
	do
	{
		menu();
		printf("请选择:");
		scanf("%d", &input);
		switch (input)                //这里case部分用到了contact.h中的枚举类型。


增加程序可读性 { case ADD: AddContact(&con); //增 break; case DEL: DeleContact(&con); //删 break; case SEARCH: SearchContact(&con); //查 break; case MODIFY: ModifyContact(&con); //改 break; case SORT: SortContact(&con); //排序 break; case PRINT: PrintContact(&con); //打印信息 break; case EXIT: printf("退出成功\n"); break; default: printf("输入错误,请重新输入!\n"); break; } } while (input); } int main() { test(); return 0; }

然后是contact.h

其中是函数声明及头文件的引用。


要注意,这是静态版本的通讯录,大小提前定义好了。


(开辟的是固定大小的空间)

#define _CRT_SECURE_NO_WARNINGS 1

#include
#include
#include
#include

#define MAX 10
#define NAME_MAX 20
#define SEX_MAX 5
#define TELE_MAX 12
#define ADDR_MAX 20

enum OPTION        //这里用到了枚举类型,增加代码可读性
{
	EXIT,
	ADD,
	DEL,
	SEARCH,
	MODIFY,
	SORT,
	PRINT
};

//联系人信息:姓名,性别,年龄,电话,住址
typedef struct PeoInFo
{
	char name[NAME_MAX];
	char sex[SEX_MAX];
	int age;
	char tele[TELE_MAX];
	char addr[ADDR_MAX];
}PeoInFo;

//创建一个名字为con的结构体类型  
//其中包含一个记录联系人信息的数组(数组的类型为联系人结构体),
//一个记录大小的整型变量count
// 
//创建通讯录结构体
typedef struct Contact
{
	//联系人信息(结构体)
	PeoInFo data[MAX];
	//多少个
	int count;
}Contact;


//初始化通讯录
void InitContact(Contact*pc);

//添加联系人信息
void AddContact(Contact* pc);

//打印联系人信息
void PrintContact(const Contact* pc);		//这里加const比较安全

//删除联系人的信息
void DeleContact(Contact* pc);

//查找联系人信息
void SearchContact(const Contact* pc);

//修改联系人信息
void ModifyContact(Contact* pc);

//对联系人信息进行排序
void SortContact(Contact* pc);

接下来就算contact.c,就是各个功能的实现:

#define _CRT_SECURE_NO_WARNINGS 1

//联系人信息:姓名,性别,年龄,电话,住址

#include"contact.h"
//Contact*pc其实就是通讯录结构体的指针,它指向的结构体包含两个元素
//一个是联系人信息的结构体,一个是记录当前联系人信息个数的count


//初始化通讯录            可以用memset函数帮助初始化通讯录中的信息
void InitContact(Contact*pc)
{
	assert(pc);
	//把sz置为0,把开辟的空间,都置成0
	pc->count = 0;
	memset(pc->data,0,sizeof(pc->data));			//数组名代表首元素地址,但是sizeof是个例外
}




//添加联系人信息
void AddContact(Contact* pc)
{
	assert(pc);
	//判断满了没
	if (pc->count == MAX)
	{
		printf("通讯录空间已满,无法添加\n");
		return;
	}
	//没满,添加
	printf("请输入联系人姓名:");
	scanf("%s", pc->data[pc->count].name);
	printf("请输入联系人性别:");
	scanf("%s", pc->data[pc->count].sex);
	printf("请输入联系人年龄:");
	scanf("%d", &(pc->data[pc->count]).age);		//年龄需要解引用,其他的都可以直接传地址
	printf("请输入联系人电话:");
	scanf("%s", pc->data[pc->count].tele);
	printf("请输入联系人地址:");
	scanf("%s", pc->data[pc->count].addr);
	
	pc->count++;
	printf("添加成功\n");
}


//打印联系人信息
//联系人信息:姓名,性别,年龄,电话,住址
void PrintContact(const Contact* pc)
{
	assert(pc);
	printf("%-20s %-5s %-5s %-12s %-30s\n", "姓名", "性别", "年龄", "电话", "住址");

	int i = 0;
	for (i = 0; i < pc->count; i++)
	{
		printf("%-20s %-5s %-5d %-12s %-30s\n",                         //增加代码美观性
											pc->data[i].name, 
											pc->data[i].sex, 
											pc->data[i].age, 
											pc->data[i].tele, 
											pc->data[i].addr);
	}
}

//查找信息,有就返回下标,没有返回-1
int FindByName(const Contact* pc, char name[NAME_MAX])				//这里又忘记const
{
	int i = 0;
	for (i = 0; i < pc->count; i++)
	{
		if (strcmp(pc->data[i].name, name) == 0)
		{
			return i;
		}
	}
	return -1;
}
//对于查找 *** 作来说,不会对通讯录内部的值进行更改,因此,加上const会使代码更加安全



//删除联系人的信息
void DeleContact(Contact* pc)
{
	assert(pc);
	//空了,无需删除
	if (pc->count == 0)
	{
		printf("无联系人信息需删除!\n");
		return;
	}
	//需要删除
	char name[NAME_MAX] = { 0 };
	printf("请输入您要删除的联系人的名字:");
	scanf("%s", name);
	//有 或者 没有
	int ret = FindByName(pc, name);                        //因为还需要实现查找联系人信息的功能,所以在这路封装了一个函数
	if (ret == -1)
	{
		printf("没有找到您要删除的联系人信息!\n");
	}
	else
	{
		//删除联系人信息
		int i = 0;
		for (i = ret; i < pc->count; i++)
		{
			pc->data[ret] = pc->data[ret + 1];
		}
		pc->count--;
		printf("删除成功\n");
		PrintContact(pc);
	}
}


//查找联系人信息
void SearchContact(const Contact* pc)
{
	assert(pc);
	//空了,无法查找
	if (pc->count == 0)
	{
		printf("无联系人信息!\n");
		return;
	}
	char name[NAME_MAX] = { 0 };
	printf("请输入您要查找的联系人的名字:");
	scanf("%s", name);
	//有 或者 没有
	int ret = FindByName(pc, name);
	if (ret == -1)
	{
		printf("没有找到您要查找的联系人信息!\n");
	}
	else
	{
		printf("该联系人信息为:\n");
		printf("\n\n%-20s %-5s %-5s %-12s %-30s\n", "姓名", "性别", "年龄", "电话", "住址");
		//打印联系人信息
		printf("%-20s %-5s %-5d %-12s %-30s\n",
			                                    pc->data[ret].name,
                                    			pc->data[ret].sex,
                                    			pc->data[ret].age,
                                    			pc->data[ret].tele,
                                    			pc->data[ret].addr);
	}
}


//修改联系人信息
void ModifyContact(Contact* pc)
{
	assert(pc);
	//空了,无法修改
	if (pc->count == 0)
	{
		printf("无联系人信息!\n");
		return;
	}
	char name[NAME_MAX] = { 0 };
	printf("请输入您要修改的联系人的名字:");
	scanf("%s", name);
	//有 或者 没有
	int ret = FindByName(pc, name);
	if (ret == -1)                              //这里返回-1的原因是0也有可能是数组下标
	{
		printf("没有找到您要修改的联系人信息!\n");
	}
	else                                        //这里修改信息的代码其实就和刚开始录入信息的是差不多的
	{
		printf("请输入联系人姓名:");
		scanf("%s", pc->data[ret].name);
		printf("请输入联系人性别:");
		scanf("%s", pc->data[ret].sex);
		printf("请输入联系人年龄:");
		scanf("%d", &(pc->data[ret]).age);		//年龄需要解引用,其他的都可以直接传地址
		printf("请输入联系人电话:");
		scanf("%s", pc->data[ret].tele);
		printf("请输入联系人地址:");
		scanf("%s", pc->data[ret].addr);
	}
	printf("修改成功!\n");
}



//对联系人信息进行排序
//这里用到了C语言提供的qsort函数,可以实现复杂类型的排序
//如果关于qsort函数用法有不懂的可以看我之前的博客


//这里除了年龄的排序不用strcmp外,其他的都用strcmp
//因为字符串的比较不能直接相减,需要用到strcmp函数
int cmp_by_name(const void* e1, const void* e2)
{
	return strcmp(((PeoInFo*)e1)->name , ((PeoInFo*)e2)->name);
}
int cmp_by_sex(const void* e1, const void* e2)
{
	return strcmp(((PeoInFo*)e1)->sex, ((PeoInFo*)e2)->sex);
}
int cmp_by_age(const void* e1, const void* e2)
{
	return ((PeoInFo*)e1)->age - ((PeoInFo*)e2)->age;
}
int cmp_by_tele(const void* e1, const void* e2)
{
	return strcmp(((PeoInFo*)e1)->tele, ((PeoInFo*)e2)->tele);
}
int cmp_by_addr(const void* e1, const void* e2)
{
	return strcmp(((PeoInFo*)e1)->addr, ((PeoInFo*)e2)->addr);
}
void SortContact(Contact* pc)
{
	int input = 0;
	printf("请输入您想要的排列方式:1.姓名 2.性别 3.年龄 4.电话 5. 住址");
	scanf("%d", &input);
	switch (input)
	{
	case 1:
		qsort(pc->data, pc->count, sizeof(PeoInFo), cmp_by_name);
		PrintContact(pc);
		break;
	case 2:
		qsort(pc->data, pc->count, sizeof(PeoInFo), cmp_by_sex);
		PrintContact(pc);

		break;
	case 3:
		qsort(pc->data, pc->count, sizeof(PeoInFo), cmp_by_age);
		PrintContact(pc);
		break;
	case 4:
		qsort(pc->data, pc->count, sizeof(PeoInFo), cmp_by_tele);
		PrintContact(pc);
		break;
	case 5:
		qsort(pc->data, pc->count, sizeof(PeoInFo), cmp_by_addr);
		PrintContact(pc);
		break;
	default:
		printf("输入错误请重新输入:");
		break;
	}
}

以上就是对于一个通讯录的具体实现了。


总结:

需要注意的是:

1.明白这两个结构体在内存中是怎样存在的(可以复制代码自己进行调试)

2.在实现时要分清每个指针指向的内容,特别是进行删除联系人信息的时侯。


要明白后边的元素“前移”的过程

3.qsort函数的使用。


qsort真的是一个很好用的排序函数。


自己实现通讯录真的很有成就感!

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

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

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

发表评论

登录后才能评论

评论列表(0条)

保存