网络知识 娱乐 【C语言】通讯录《静态内存版本》

【C语言】通讯录《静态内存版本》

Hello🥂謓泽👋多多指教😛

HY点赞👍收藏⭐️留言📝​

⛳通讯录✔目录   

✨前言  

✨模块化编程 

🎓通讯录的逻辑实现 

✨实现通讯录の步骤

🖊创建颜色函数color() 

🖊菜单界面函数menu()

🎓通讯录的定义

🖊枚举类型

🎓初始化通讯录

🎓增加通讯录的信息 

🎓打印通讯录的信息 

🎓删除通讯录的信息 

🎓查找通讯录的信息 

🎓修改指定通讯录人的信息

🎓排查通讯录当中人员的信息

✨模块化代码实现

🖊test.c

🖊address_book.c 

🖊address_book.h 

✨最后✨



✨前言  

本篇博客会带大家如何去自己实现一个通讯录的一个程序代码,再说代码之前讲讲什么是模块化编程吧


✨模块化编程 

传统方式编程→所有的函数均放在main.c里,若使用的模块比较多,则一个文件内会有很多的代码,不利于代码的组织和管理,而且很影响编程者的思路。

模块化编程:把各个模块的代码放在不同的.c文件里,在.h文件里提供外部可调用函数的声明,其它.c文件想使用其中的代码时,只需要#include "XXX.h"文件即可。使用模块化编程可极大的提高代码的可阅读性、可维护性、可移植性等。

传统方式编程:所有的函数均放在main.c里,若使用的模块比较多,则一个文件内会有很多的代码,不利于代码的组织和管理,而且很影响编程者的思路。

模块化编程:把各个模块的代码放在不同的.c文件里,在.h文件里提供外部可调用函数的声明,其它.c文件想使用其中的代码时,只需要#include "XXX.h"文件即可。使用模块化编程可极大的提高代码的可阅读性、可维护性、可移植性等!

总的来说就是:当你代码比较多的时候,就可以采用模块化编程来完成这个程序😜


🎓通讯录的逻辑实现 

通讯录中我们规定总共可以存放1000个人的信息。

每个人的信息分别有→名字、年龄、性别、电话、地址。

增加人的信息,放在通讯录当中去。

删除指定存在通讯录人当中的信息。

修改指定通讯录人的信息。

查找指定通讯录人的信息。

排查通讯录当中人员的信息。

打印通讯录当中人员的信息。

当我不想用这个通讯录的话就退出。


✨实现通讯录の步骤

那么接下来就是实现通讯录这个程序一个实现的步骤;


🖊创建颜色函数color() 

前景色颜色的对应值↓

0=黑色                8=灰色  
1=蓝色                9=淡蓝色        十六进制                                  
2=绿色                10=淡绿色        A          
3=湖蓝色              11=淡浅绿色      B 
4=红色                12=淡红色        C  
5=紫色                13=淡紫色        D          
6=黄色                14=淡黄色        E         
7=白色                15=亮白色        F

color()创建颜色函数如下↓ 

void color(short x)	
{
	if (x >= 0 && x <= 15)
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), x);	 
	else
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7);
}

使用颜色函数的好处实际上无非就是让程序运行看上去更加美观、鲜明,实际上没什么实际作用,这点是我们要知道的。 

这里的STD_OUTPUT_HANDLE需要引头文件#include,才可以进行使用。


🖊菜单界面函数menu()

菜单界面函数实际上就像是我们的一个界面,就好比是游戏的界面目录,餐馆当中的菜单。一样的道理。这个是库函数就有的我们只需要直接引用下即可。示例代码如下↓

void menu()
{
	color(0);//黑色
	system("cls");//清屏
	color(7);//白色
	printf("■■■■■■■■→通讯录v1.0←■■■■■■■■n");
	printf("★★★★★→1.increase ■ 2.delete←★★★★★n");
	printf("★★★★★→3.find     ■ 4.Revise←★★★★★n");
	printf("★★★★★→5.Check    ■ 6.Print ←★★★★★n");
	printf("★★★★★→0.Exit     ■         ←★★★★★n");
	printf("■■■■■■■■→通讯录v1.0←■■■■■■■■n");
}

界面上的数字所对应的功能(@^0^@)/

1.increase → 增加人的信息,放在通讯录当中去。

2.delete → 删除指定存在通讯录人当中的信息。

3.find → 查找指定通讯录人的信息。

4.Revise → 修改指定通讯录人的信息。

5.Check → 排查通讯录当中人员的信息。

6.Print → 打印通讯录当中人员的信息。

0.Exit → 当我不想用这个通讯录的话就退出。

注→在这里用到了一个system("cls"); 达到了一个清屏的效果,只有加了这个,你才可以让cmd中的界面全部为黑色。因为我们还在这个清屏指令上+color(0); 这个代表的是,黑色。


🎓通讯录的定义

在这里我们要实现↓

通讯录中我们规定总共可以存放1000个人的信息。

每个人的信息分别有→名字、年龄、性别、电话、地址。

于是我们就可以创建个通讯录信息的结构体类型来进行定义。

#define Max_name 5
#define Max_age 100
#define Max_genger 3
#define Max_address 20
#define Max_telephone 20

typedef struct information
{
	//名字、年龄、性别、电话、地址。
	char name[Max_name];
	int age[Max_age];
	char genger[Max_genger];
	int telephone[Max_telephone];
	char address[Max_address];
}information;

这个是每个人的信息分别有→名字、年龄、性别、电话、地址。 

#define num 1000
typedef struct Contact
{
	//这里用了个结构体嵌套
	information date[num];//存放添加进来的信息
	int sz;//记录当前通讯录有效信息的个数
}Conta;

通讯录中我们规定总共可以存放1000个人的信息。 

在上面代码当中我们使用大量 #define 宏定义在这里的好处:

  1. 方便程序的修改,不用对整个程序进行修改,只需对宏定义上进行修改。
  2. 提高程序的运行效率,更加方便模块化。
  3. 我们只需改变宏定义的值,就可以实现不同人数的效果且易于修改。

🖊枚举类型

这里我们可以配合使用枚举类型常量来和 switch case 语句当中进行使用。因为枚举的默认取值是为0的,可以与上面界面当中的值一一对应,放在case当中的常量表达式当中代码的可读性也会更高。

enum Number
{
	Exit,
	Increase,
	DeLete,
	Find,
	Revise,
	Check,
	Print,
};

推荐枚举常量当中的值大写。 那么此时我们的case语句当中常量表达式的值就可以放上枚举常量这些值了。就像下面这样,示例代码如下↓

switch (input)
{
case Exit:printf("退出通讯录v1.0n");
	break;
case Increase:
	break;
case DeLete:
	break;
case Find:
	break;
case Revise:
	break;
case Check:
	break;
case Print:
	break;
default:printf("你输入的数字找不到,请重新输入~");
}


🎓初始化通讯录

在增加通讯录信息之前,我们首先要把通讯录的信息给初始化下。

void InitContact(Contact* pc)
{
	pc->sz = 0;//sz初始化
	//memest() - 内存设置
	memset(pc->date, 0, sizeof(pc->date)); 
}

如果不知道memset()这个内存函数什么意思的话,可以去查下。 

有的人可能会有疑问,这里直接就可以把我们通讯录的结构体类型给初始化0,为什么还需要这个样子。因为这样的话,可以面对较为复杂的问题,之所以能就是因为我们使用了memset()这个内存函数。


🎓增加通讯录的信息 

对通讯录进行初始化之后,那么就可实现我们的增加通讯录的信息了。ヽ(✿゚▽゚)ノ

void Add_Contact(Contact* pc)
{
	if (pc->sz == num)
	{
		printf("通讯录成员已满n");
		return;
	}
	//增加一个人的信息
	printf("n");
	printf("请输入增加人的名字->:");
	scanf("%s", pc->date[pc->sz].name);//注意→数组名是首元素地址,所以不用进行取地址.

	printf("请输入增加人的年龄->:");
	scanf("%s", pc->date[pc->sz].age);

	printf("请输入增加人的性别->:");
	scanf("%s", pc->date[pc->sz].genger);

	printf("请输入增加人的电话->:");
	scanf("%s", pc->date[pc->sz].telephone);

	printf("请输入增加人的地址->:");
	scanf("%s", pc->date[pc->sz].address);
	//成功~
	pc->sz++;
	printf("★恭喜你~添加信息成功★n");
	printf("n");
}

在这里是有两种情况的,一个是我们通讯录当中1000人已经是存放满的情况,还有一种是没有存在满,还可以继续添加的情况。存在满了的话直接return;返回即可,没有输入即可。

示例→添加信息如下图所示↓


🎓打印通讯录的信息 

那么假设我们增加了通讯录的信息想要打印出来看看的话,这个时候就必须要打印我们通讯录的信息才行。如下代码所示↓

void Print_Contact(const Contact* pc)
{
	int i = 0;
	//打印标题栏的信息
	printf("|-------------------------------------------------------|n");
	printf("|%-3st%-3st%-3st%-11st%-10st|n", "名字", "年龄", "性别", "电话", "地址");

	for (i = 0; i sz; i++)
	{
		printf("|%-3st%-3st%-3st%-11st%-10st|n", pc->date[i].name,
			pc->date[i].age,
			pc->date[i].genger,
			pc->date[i].telephone,
			pc->date[i].address);
	}
}

 - 是左对齐,%3s的数字3是打印空3格位置。

在这里的话假设我们要输入一组通讯录人员的信息,那我们来打印下看下会不会成功。

成功的打印出来了(^∀^●)ノシ 


🎓删除通讯录的信息 

删除通讯录的信息实际上就是假设我们输入了一组通讯录的信息,我们不想要了的话那么我们可以进行删除,这样当我们打印通讯录的信息就不会再有原来我们输入的那组信息了。

void DeLete_Contact(Contact* pc)
{
	char name[Max_name] = { 0 };
	//通讯录为空的时候
	if (pc->sz == 0)
	{
		printf("通讯录当中没有任何信息n");
		return;
	}
	printf("请输入你要删除的名字->:n");
	scanf("%s", name);
	//查找要删除的人:有/没有
	int ret = FindByname(pc, name);
	if (ret == -1)
	{
		printf("没有查找到当前人的信息n");
		return;
	}
	//删除
	int i = 0;
	for (i = ret; i sz - 1; i++)
	{
		pc->date[i] = pc->date[i + 1];
	}
	pc->sz--;//因为我们删除成功下标要减1
	printf("★恭喜你~删除信息成功★n");
	printf("n");
}

在这里我们还创建了一个函数 FindByname(),它的功能实际上就是要帮我们查找通讯录当中人员的信息存在不存在,以输入名字的形式来进行查找通讯录人员的信息。

static int FindByname(Contact* pc, char name[])
{
	int i = 0;
	//用for循环进行遍历
	for (i = 0; i sz; i++)
	{
		//strcmp()比较字符串
		if (strcmp(pc->date[i].name, name) == 0)
		{
			return i;//返回下标
		}
	}
	return -1;
}

在这里我们用静态局部变量 static 修饰函数↓

函数被静态 (static) 修饰函数也是在其他的源文件是不能被使用的,只能在源文件当中去进行使用 !

那我们程序运行下看看是不是达到了我们想实现的一个效果。

运行结果证明程序是成功的ヽ(✿゚▽゚)ノ


🎓查找通讯录的信息 

查询通讯录和我们上面实现的 FindByname() 都是很类似的。

void Find_Contact(Contact* pc)
{
	char name[Max_name] = { 0 };
	printf("请输入你要删除的名字->:");
	scanf("%s", name);
	int ret = FindByname(pc, name);
	if (ret == -1)
	{
		printf("没有查找到当前人的名字n");
		return;
	}
	else
	{
		printf("|-------------------------------------------------------|n");
		printf("|%-3st%-3st%-3st%-11st%-10st|n", "名字", "年龄", "性别", "电话", "地址");

		printf("|%-3st%-3st%-3st%-11st%-10st|n", 
			pc->date[ret].name,
			pc->date[ret].age,
			pc->date[ret].genger,
			pc->date[ret].telephone,
			pc->date[ret].address);
	}
}

让我们来查找下"张三"的信息。 

是不是查找成功了(^∀^●)ノシ 


🎓修改指定通讯录人的信息

那么假设我输入了一个人的信息,但是我后面想要修改掉换成另外一个人的信息怎么办。如下代码所示↓ 

void Revise_Contact(Contact* pc)
{
	char name[Max_name] = { 0 };
	printf("请输入你要修改通讯录人的名字->:");
	scanf("%s", name);
	int ret = FindByname(pc, name);
	if (ret == -1)
	{
		printf("当前修改人的信息不存在n");
		return;
	}
	else
	{
		printf("请输入修改人的名字->:");
		scanf("%s", pc->date[ret].name);//注意→数组名是首元素地址,所以不用进行取地址.

		printf("请输入修改人的年龄->:");
		scanf("%s", pc->date[ret].age);

		printf("请输入修改人的性别->:");
		scanf("%s", pc->date[ret].genger);

		printf("请输入修改人的电话->:");
		scanf("%s", pc->date[ret].telephone);

		printf("请输入修改人的地址->:");
		scanf("%s", pc->date[ret].address);
		printf("恭喜你,修改成功~n");
	}
}

那么让我们来看看修改结果。 

修改结果成功了ヽ(✿゚▽゚)ノ 


🎓排查通讯录当中人员的信息

这里我们排查通讯录当中人员的信息实际上就是通过名字来进行序的,用qsort()函数通过比较首字母来进行排序。

int sort_name_max(const void* e1, const void* e2)
{
	return (strcmp(((struct Contact*)e1)->date->name, ((struct Contact*)e2)->date->name));
}

void Check_Contact(Contact* pc)
{
	//qosrt()函数首字母进行排序
	qsort(pc->date, pc->sz, sizeof(pc->date[0]), sort_name_max);
	printf("|%-3st%-3st%-3st%-11st%-10st|n", "名字", "年龄", "性别", "电话", "地址");
	int i;
	for (i = 0; i sz; i++)
	{
		printf("|%-3st%-3st%-3st%-11st%-10st|n", pc->date[i].name,
			pc->date[i].age,
			pc->date[i].genger,
			pc->date[i].telephone,
			pc->date[i].address);
	}
}

让我们来输入三组信息来看下,是不是可以通过排查通讯录当中人员的信息。 

从上述的运行结果可以看出,编译器进行了排查。根据ASCll码的值从小到大进行了排序。


✨模块化代码实现

🖊test.c

示例代码如下↓

#include"address_book.h"
//颜色函数
void color(short x)
{
	if (x >= 0 && x <= 15)
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), x);
	else
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7);
}
//创建菜单函数
void menu()
{
	color(0);//黑色
	system("cls");//清屏
	color(12);//白色
	printf("¤--------------------------------------------¤n");
	printf("|■■■■■■■■→通讯录v1.0←■■■■■■■■|n");
	printf("|———————————————————————|n");
	printf("|★★★★★→1.increase ■ 2.deLete←★★★★★|n");
	printf("|★★★★★→3.find     ■ 4.Revise←★★★★★|n");
	printf("|★★★★★→5.Check    ■ 6.Print ←★★★★★|n");
	printf("|★★★★★→0.Exit     ■         ←★★★★★|n");
	printf("|———————————————————————|n");
	printf("|■■■■■■■■→通讯录v1.0←■■■■■■■■|n");
	printf("¤--------------------------------------------¤n");
}
enum Number
{
	Exit,
	Increase,
	DeLete,
	Find,
	Revise,
	Check,
	Print,
};
int main(void)
{
	menu();
	int input = 0;
	//当然初始化全0:Contact con = {0};也是可以的,当然我们这里的初始化不是这样的原因是可以应对比较复杂的问题。
	Contact con;//通讯录
	//初始化通讯录
	InitContact(&con);
	do
	{
		color(5);
		printf("¤----------------¤n");
		printf("|请输入界面上的数字|:");
		scanf("%d", &input);
		printf("¤----------------¤n");
		color(1);
		switch (input)
		{
		case Exit:
			printf("══════════════@n");
			printf("退出通讯录v1.0@n");
			printf("══════════════@n");
			break;
		case Increase:
			//增加人的信息,放在通讯录当中去。
			Add_Contact(&con);
			break;
		case DeLete:
			//删除通讯人的信息
			DeLete_Contact(&con);
			break;
		case Find:
			//查找指定通讯录人的信息
			Find_Contact(&con);
			break;
		case Revise:
			//修改指定通讯录人的信息
			Revise_Contact(&con);
			break;
		case Check:
			//排查通讯录当中人员的信息
			Check_Contact(&con);
			break;
		case Print:
			//打印通讯录当中人员的信息。
			Print_Contact(&con);
			break;
		default:printf("你输入的数字找不到,请重新输入~n");
		}
	} while (input);
	return 0;
}

🖊address_book.c 

示例代码如下↓

#define _CRT_SECURE_NO_WARNINGS 1
#include"address_book.h"

void InitContact(Contact* pc)
{
	pc->sz = 0;
	//memest() - 内存设置
	memset(pc->date, 0, sizeof(pc->date)); 
}

void Add_Contact(Contact* pc)
{
	if (pc->sz == num)
	{
		printf("通讯录成员已满n");
		return;
	}
	//增加一个人的信息
	printf("n");
	printf("请输入增加人的名字->:");
	scanf("%s", pc->date[pc->sz].name);//注意→数组名是首元素地址,所以不用进行取地址.

	printf("请输入增加人的年龄->:");
	scanf("%s", pc->date[pc->sz].age);

	printf("请输入增加人的性别->:");
	scanf("%s", pc->date[pc->sz].genger);

	printf("请输入增加人的电话->:");
	scanf("%s", pc->date[pc->sz].telephone);

	printf("请输入增加人的地址->:");
	scanf("%s", pc->date[pc->sz].address);
	//成功~
	pc->sz++;
	printf("★恭喜你~添加信息成功★n");
	printf("n");
}

void Print_Contact(const Contact* pc)
{
	int i = 0;
	//打印标题栏的信息
	printf("|-------------------------------------------------------|n");
	printf("|%-3st%-3st%-3st%-11st%-10st|n", "名字", "年龄", "性别", "电话", "地址");

	for (i = 0; i sz; i++)
	{
		printf("|%-3st%-3st%-3st%-11st%-10st|n", pc->date[i].name,
			pc->date[i].age,
			pc->date[i].genger,
			pc->date[i].telephone,
			pc->date[i].address);
	}
}

static int FindByname(Contact* pc, char name[])
{
	int i = 0;
	//用for循环进行遍历
	for (i = 0; i sz; i++)
	{
		//strcmp()比较字符串
		if (strcmp(pc->date[i].name, name) == 0)
		{
			return i;//返回下标
		}
	}
	return -1;
}

void DeLete_Contact(Contact* pc)
{
	char name[Max_name] = { 0 };
	//通讯录为空的时候
	if (pc->sz == 0)
	{
		printf("通讯录当中没有任何信息n");
		return;
	}
	printf("请输入你要删除的名字->:");
	scanf("%s", name);
	//查找要删除的人:有/没有
	int ret = FindByname(pc, name);
	if (ret == -1)
	{
		printf("没有查找到当前人的信息n");
		return;
	}
	//删除
	int i = 0;
	for (i = ret; i sz - 1; i++)
	{
		pc->date[i] = pc->date[i + 1];
	}
	pc->sz--;//因为我们删除成功下标要减1
	printf("★恭喜你~删除信息成功★n");
	printf("n");
}

void Find_Contact(Contact* pc)
{
	char name[Max_name] = { 0 };
	printf("请输入你要查找的名字->:");
	scanf("%s", name);
	int ret = FindByname(pc, name);
	if (ret == -1)
	{
		printf("没有查找到当前人的名字n");
		return;
	}
	else
	{
		printf("|-------------------------------------------------------|n");
		printf("|%-3st%-3st%-3st%-11st%-10st|n", "名字", "年龄", "性别", "电话", "地址");

		printf("|%-3st%-3st%-3st%-11st%-10st|n", 
			pc->date[ret].name,
			pc->date[ret].age,
			pc->date[ret].genger,
			pc->date[ret].telephone,
			pc->date[ret].address);
		printf("查找%sの信息成功~n", pc->date[ret].name);
	}
}

void Revise_Contact(Contact* pc)
{
	char name[Max_name] = { 0 };
	printf("请输入你要修改通讯录人的名字->:");
	scanf("%s", name);
	int ret = FindByname(pc, name);
	if (ret == -1)
	{
		printf("当前修改人的信息不存在n");
		return;
	}
	else
	{
		printf("请输入修改人的名字->:");
		scanf("%s", pc->date[ret].name);//注意→数组名是首元素地址,所以不用进行取地址.

		printf("请输入修改人的年龄->:");
		scanf("%s", pc->date[ret].age);

		printf("请输入修改人的性别->:");
		scanf("%s", pc->date[ret].genger);

		printf("请输入修改人的电话->:");
		scanf("%s", pc->date[ret].telephone);

		printf("请输入修改人的地址->:");
		scanf("%s", pc->date[ret].address);
		printf("恭喜你,修改成功~n");
	}
}

int sort_name_max(const void* e1, const void* e2)
{
	return (strcmp(((struct Contact*)e1)->date->name, ((struct Contact*)e2)->date->name));
}

void Check_Contact(Contact* pc)
{
	//qosrt()函数首字母进行排序
	qsort(pc->date, pc->sz, sizeof(pc->date[0]), sort_name_max);
	printf("|%-3st%-3st%-3st%-11st%-10st|n", "名字", "年龄", "性别", "电话", "地址");
	int i;
	for (i = 0; i sz; i++)
	{
		printf("|%-3st%-3st%-3st%-11st%-10st|n", pc->date[i].name,
			pc->date[i].age,
			pc->date[i].genger,
			pc->date[i].telephone,
			pc->date[i].address);
	}
}

🖊address_book.h 

示例代码如下↓

#define _CRT_SECURE_NO_WARNINGS 1
#include 
#include
#include
#include

#define Max_name 5
#define Max_age 100
#define Max_genger 3
#define Max_address 20
#define Max_telephone 20

#define num 1000

//类型的定义
typedef struct information
{
	//名字、年龄、性别、电话、地址。
	char name[Max_name];
	char age[Max_age];
	char genger[Max_genger];
	char telephone[Max_telephone];
	char address[Max_address];
}information;
//通讯录
typedef struct Contact
{
	//这里用了个结构体嵌套
	information date[num];//存放添加进来的信息
	int sz;//记录当前通讯录有效信息的个数
}Contact;
//初始化通讯录
void InitContact(Contact* pc);
//增加通讯录信息
void Add_Contact(Contact* pc);
//打印通讯录的信息
void Print_Contact(const Contact* pc);
//删除通讯人的信息
void DeLete_Contact(Contact* pc);
//查找指定通讯录人的信息
void Find_Contact(Contact* pc);
//修改指定通讯录人的信息
void Revise_Contact(Contact* pc);
//排查通讯录当中人员的信息
void Check_Contact(Contact* pc);

✨最后✨

当然后续还是会用动态内存开辟的方法来实现这个通讯录的一个程序,因为上述程序实际上我们使用的是一个固定开辟内存空间的方式,是不太合适的。