通讯录【C语言版】---- 超级详细 + 动态演示 + 完整源码


㊙️小明博客主页:➡️ 敲键盘的小明 ㊙️
✅关注小明了解更多知识☝️



前言

提示:本篇文章为C语言【通讯录】实现的详细笔记和完整的源码,内容如若有误,请联系小明及时更正。

  • 转载请注明原创,谢谢。

一、通讯录效果

剧情抢先看:
在这里插入图片描述

  功能如此齐全的通讯录是如何实现的呢?让我们来看今天的博客内容:


在这里插入图片描述

提示:以下是本篇文章正文内容:

二、整体思路分析

  我们在制作通讯录之前,很重要的一件事情,就是我们需要理清楚思路,以及我们需要做些什么。
  通讯录 ,顾名思义是存储一个联系人的各种信息,我们今天就比较简单地实现一下存放个人信息的通讯录。
  当我们进行制作通讯录的时候,尤其是在进行分文件操作的时候,一定会碰到很多难点,而且我们进行制作的时候,必须要用到以前的知识,就像以前实现三子棋那种小项目一样,但是同时也要加入新的元素进去,所以我们要先对整体工程的逻辑尽可能详细的梳理。

需要实现的功能:

  • 添加联系人
  • 删除指定联系人
  • 查找指定联系人
  • 修改指定联系人的信息
  • 显示所有联系人
  • 联系人的排序

需要存储的个人信息:

  • 姓名   年龄  性别  电话  地址

三、逻辑实现

3.1 创建菜单

  首先,我们的代码堆在一起显得很冗余,所以还是像之前的三子棋一样,分成三个文件实现:

在这里插入图片描述
  

  其次呢,我们需要在test.c项目里,进行总体函数的框架制作,所以我们需要在contact.h 头文件里面包含所有的头文件以及函数声明,因为这样很清晰,很简洁;
  我们在其他两个项目文件里面加上 #include “contact.h” 即可,我们就可以直接用头文件里面的头文件和声明了:

在这里插入图片描述
  接下来我们就可以先来实现一下通讯录的菜单了,看过三子棋的朋友们应该都知道,我们执行代码框架的代码应该在 contact.c 文件中写,所以还是老样子,让我们在 contact.c 文件中先将通讯录的菜单写出来:

#include"contact.h"

void menu()
{
	printf("**********************************\n");
	printf("****  1. add        2. del    ****\n");
	printf("****  3. search     4. modify ****\n");
	printf("****  5. show       6. sort   ****\n");
	printf("****  0. exit 【退出程序】    ****\n");
	printf("**********************************\n");
}

int main()
{
	int input = 0;
	do
	{
		menu();
		printf("请输入你的选择:");
	} while(input);
	
	return 0;
}

代码运行结果:
在这里插入图片描述

  这样,我们通讯录的菜单就成功的打印出来了,但这时的通讯录菜单是没什么效果的!因为我们还没有开始写输入选择的操作,接下来我们在 do while 中再加一段 scanf 的菜单功能选择操作的代码:

#define _CRT_SECURE_NO_WARNINGS 1

//代码的测试
#include"contact.h"

void menu()
{
	printf("**********************************\n");
	printf("****  1. add        2. del    ****\n");
	printf("****  3. search     4. modify ****\n");
	printf("****  5. show       6. sort   ****\n");
	printf("****  0. exit 【退出程序】    ****\n");
	printf("**********************************\n");
}

int main()
{
	int input = 0;
	do
	{
		menu();
		printf("请输入你的选择:");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			//add  添加
			break;
		case 2:
			//del  删除
			break;
		case 3:
			//search  查找
			break;
		case 4:
			//modify  修改
			break;
		case 5:
			//show  显示
			break;
		case 6:
			//sort  排序
			break;
		case 0:
			printf("退出成功!\n");
			break;
		default:
			printf("输入的选择错误!\n");
			break;
		}
	} while(input);


	return 0;
}

代码运行结果:
在这里插入图片描述

  截至到这里,我们就可以成功的打印出通讯录的菜单了,但这时的菜单暂时还没有写我们选择 1 ~ 6 时的功能,由于我们 do while 是由 input 来判断的,所以我们在输入 0 的时候,程序就退出了!

  当然,由于我们在 switch 中只有 1 ~ 6 和 0 的选项,所以当我们输入除了这七个数字以外的数字时,就会显示输入的选择错误

  至于 1 ~ 6 的功能实现会在下面的文章中实现。

  我们这里的选择是由 1~6 来选择的,我们可以看到 switch 的选项都是数字,在没有注释的情况下很难阅读代码:
在这里插入图片描述
这种情况,又该如何优化代码呢?
  我们可以使用枚举来将这些功能选项替换掉!创建一个 Option (选项)枚举,具体实现效果如下:

  先写一个枚举,然后将 switch 的选项1~6全部替换成 Option 元素:

enum Option
{
	EXIT,//0  退出
	ADD,//1  添加
	DEL,//2  删除
	SEARCH,//3  查找
	MODIFY,//4  修改
	SHOW,//5  显示
	SORT,//6  排序
};

总体代码:

#define _CRT_SECURE_NO_WARNINGS 1

//代码的测试
#include"contact.h"

void menu()
{
	printf("**********************************\n");
	printf("****  1. add        2. del    ****\n");
	printf("****  3. search     4. modify ****\n");
	printf("****  5. show       6. sort   ****\n");
	printf("****  0. exit 【退出程序】    ****\n");
	printf("**********************************\n");
}

enum Option
{
	EXIT,//0  退出
	ADD,//1  添加
	DEL,//2  删除
	SEARCH,//3  查找
	MODIFY,//4  修改
	SHOW,//5  显示
	SORT,//6  排序
};

int main()
{
	int input = 0;
	do
	{
		menu();
		printf("请输入你的选择:");
		scanf("%d", &input);
		switch (input)
		{
		case ADD:
			//添加
			break;
		case DEL:
			//删除
			break;
		case SEARCH:
			//查找
			break;
		case MODIFY:
			//修改
			break;
		case SHOW:
			//显示
			break;
		case SORT:
			//排序
			break;
		case EXIT:
			printf("退出成功!\n");
			break;
		default:
			printf("输入的选择错误!\n");
			break;
		}
	} while(input);

	return 0;
}

  

3.2 创建通讯录

  上面的代码可以让我们成功的打印出通讯录的菜单,我们接下来开始创建通讯录:
  我们在对通讯录进行各种操作前先得有个通讯录吧!
  通讯录的本质还是描述一个人的属性,例如:姓名、年龄、性别、电话、住址等。这些都是不同的类型,所以我们可以很容易的想到,用结构体来解决;但这只是描述一个人,我们的通讯录不会只有一个人,而是应该是有很多个!而这些联系人又是同一类型,因此采用结构体数组来创建通讯录!
  

contact.h 文件中实现:

typedef struct PeoInfo
{
	char name[20];
	int age;
	char sex[5];
	char tele[15];
	char addr[20];
}PeoInfo;

  这就是描述一个人基本属性的结构体
  当我们创建好了这个结构体后,我们就可以创建结构体数组来作为通讯录了:

contact.h 文件中实现:

typedef struct Contact
{
	PeoInfo data[100];//存放数据
	int sz;//记录当前通讯录中存放了多少个人的信息
}Contact;

  OK,这个创建通讯录记好了!
  但是,我们会发现两个结构体中都出现了大量的常数,我们万一后期需求有变,这些都得修改,因此为了后期修改方便,我们把这些都改成#define 常量,后期修改起来容易:

#define _CRT_SECURE_NO_WARNINGS 1

#pragma once//确保一个头文件只编译一次

//函数的声明
#include<stdio.h>

#define NAME_MAX 20  //名字
#define SEX_MAX 5    //性别
#define TELE_MAX 12  //电话
#define ADDR_MAX 30  //住址

#define MAX 100  //存放数据

typedef struct PeoInfo
{
	//一个人的信息
	char name[NAME_MAX];  //名字
	int age;   //年龄
	char sex[SEX_MAX];  //性别
	char tele[TELE_MAX];  //电话
	char addr[ADDR_MAX];  //地址
}PeoInfo;


typedef struct Contact
{
	PeoInfo data[MAX];//存放数据
	int sz;//记录当前通讯录中存放了多少个人的信息
}Contact;

  
然后再在test.c文件中创建即可:
在这里插入图片描述

3.3 初始化通讯录

  我们创建好了通讯录之后,我们需要先对其进行一个初始化!
  把结构体数组的每个元素都初始化为 0,通讯录大小也置为0!
  而且,因为我们要改变结构体的内容,所以应该传地址!我们这里采用的是 memset 这个函数直接初始化为0,也可以用个循环来初始化!

contact.h 文件中实现:

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

contact.c 文件中实现:

void InitContact(Contact* pc)
{
	assert(pc);//防止pc是无效的

	memset(pc->data, 0, sizeof(pc->data));
	pc->sz = 0;
}

test.c 文件中实现:

Contact con;//通讯录
//初始化通讯录
InitContact(&con);

在这里插入图片描述

代码运行效果:
在这里插入图片描述
  我们可以看到成功的结构体将内部初始化为了 0

  
  

此处插播:

memset的使用方法:
在这里插入图片描述

3.4 添加联系人

  

contact.h 文件中实现:

//增加联系人
void AddContact(Contact* pc);

test.c 文件中的case ADD中添加:

case ADD:
	//添加
	AddContact(&con);
	break;

在这里插入图片描述

有了上面两段代码,我们就可以在contact.c 文件中写添加联系人的代码了。

  
  

contact.c 文件中实现:

3.4.1 判断是否有效

  先写一个 assert 断言一下 pc 是否有效:

void AddContact(Contact* pc)
{
	assert(pc);//防止pc是无效的
}

3.4.2 判断通讯录是否已满

  当我们断言之后,判断一下通讯录中是否还有位置可供我们添加新的联系人信息,在 contact.h 文件中我们的联系人设置的 MAX 是100人。
在这里插入图片描述
  所以我们用 if 来判断一下,如果此时的 pc 等于了最大人数时,我们就显示:通讯录已满,无法继续添加联系人

void AddContact(Contact* pc)
{
	assert(pc);//防止pc是无效的
	if (pc->sz == MAX)
	{
		printf("通讯录已满,无法继续添加联系人\n");
		return;
	}
}

3.4.3 添加新的信息

  接下来我们就可以写添加新联系人信息的代码了:

void AddContact(Contact* pc)
{
	assert(pc);//防止pc是无效的
	if (pc->sz == MAX)
	{
		printf("通讯录已满,无法继续添加联系人\n");
		return;
	}
	//添加信息
	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);
	//联系人的个数 +1
	pc->sz++;

	printf("添加成功!\n");
}

3.4.4 添加效果展示

在这里插入图片描述
现在是不是就可以成功的添加联系人了。

3.5 显示联系人

  添加了联系人之后,我们就应该显示一下,还是老样子,先声明后使用:
contact.h 文件中实现:

//显示联系人
void ShowContact(Contact* pc);

test.c 文件中的case ADD中添加:

case SHOW:
	//显示
	ShowContact(&con);
	break;

![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/e3f7e65df4e0436794dd2ef6917bc577.png

有了上面两段代码,我们就可以在contact.c 文件中写显示联系人的代码了。

  
  

contact.c 文件中实现:

3.5.1 判断通讯录是否为空

  这里和添加联系人时一样,先断言,然后判断一下此时的通讯录是否时空的,如果为 0 ,证明通讯录还没有联系人的信息,没法打印显示,所以提示:通讯录为空,请先添加联系人!

void ShowContact(Contact* pc)
{
	assert(pc);//防止pc是无效的
	if (pc->sz == 0)
	{
		printf("通讯录为空,请先添加联系人!\n");
		return;
	}
}

在这里插入图片描述

3.5.2 显示联系人

  那么,如果此时通讯录不为空,说明通讯录里已经存在联系人的信息了,那我们就直接打印显示即可:

void ShowContact(Contact* pc)
{
	assert(pc);//防止pc是无效的
	if (pc->sz == 0)
	{
		printf("通讯录为空,请先添加联系人!\n");
		return;
	}
	int i = 0;
	printf("%-s\t%-s\t%-5s\t%-15s\t%-20s\n", "姓名", "年龄", "性别", "电话", "住址");
	for (int i = 0; i < pc->sz; i++)
	{
		printf("%-s\t%-d\t%-5s\t%-15s\t%-20s\n",
			pc->data[i].name,
			pc->data[i].age,
			pc->data[i].sex,
			pc->data[i].tele,
			pc->data[i].addr
		);
	}
}

3.5.3 显示效果展示

  这里,我们先显示一下空通讯录的效果,然后再添加联系人信息,最后显示一下:
在这里插入图片描述

添加多个联系人并显示:
在这里插入图片描述
效果:
在这里插入图片描述

  至此,添加联系人和显示联系人的功能我们都成功的实现了!

3.6 删除指定联系人

  还是和之前一样,我们上来就先在 contact.h 文件和 test.c 文件添加声明和使用,然后在contact.c 文件中实现:

contact.h 文件中实现:

//删除联系人
void DelContact(Contact* pc);

test.c 文件中的case ADD中添加:

case DEL:
	//删除
	DelContact(&con);
	break;

在这里插入图片描述

有了上面两段代码,我们就可以在contact.c 文件中写删除联系人的代码了。

  
  

contact.c 文件中实现:

3.6.1 判断通讯录是否为空

  同样的,我们还是先断言,然后判断一下此时的通讯录是否时空的,如果为 0 ,证明通讯录还没有联系人的信息,没法删除联系人信息,所以提示:通讯录为空,无需删除!

void DelContact(Contact* pc)
{
	assert(pc);//防止pc是无效的
	if (pc->sz == 0)
	{
		printf("通讯录为空,无需删除!\n");
		return;
	}
}

3.6.2 查找联系人

  然后重点来了 !!!
  然后重点来了 !!!
  然后重点来了 !!!

  不管是我们是查找某个人的信息删除某个人信息还是修改某个人信息,都需要先输入那个人的姓名,然后进行查找,找到了再删除,找不到就提示查无此人!注意考虑通讯录为空的情况!
  所以,我们需要单独封装一个查找函数,然后不管我们之后查找删除还是修改的时候,都可以直接调用这个查找函数去找到通讯录中这个人的信息。
  这里的查找返回下标即可。
封装的查找函数:

//查找要删除的人并返回下标
int FindContact(const Contact* pc, const char* name)
{
	for (int i = 0; i < pc->sz; i++)
	{
		if (strcmp(pc->data[i].name, name) == 0)
		{
			return i;//找到了
		}
	}

	return -1;//没找到
}

3.6.3 删除该联系人信息

  判断通讯录不为空,且能找到这个联系人,那么我们就该删除这个联系人了:

void DelContact(Contact* pc)
{
	assert(pc);//防止pc是无效的
	if (pc->sz == 0)
	{
		printf("通讯录为空,无需删除!\n");
		return;
	}
	char name[NAME_MAX];
	printf("请输入要删除人的名字:");
	scanf("%s",name);
	//查找名字为 name 的这个人
	int ret = FindByName(pc, name);
	if (ret == -1)
	{
		printf("要删除的这个人不存在!\n");
		return;
	}
	//删除找到的这个联系人
	int i = 0;
	for (int i = ret; i < pc->sz - 1; i++)
	{
		pc->data[i] = pc->data[i + 1];
	}
	pc->sz--;
	printf("成功删除联系人%s!\n",name);
}

3.6.4 效果展示

在这里插入图片描述

删除前后对比:
在这里插入图片描述

  OK,这里我们也是成功的删除了通讯录中指定的联系人。

3.7 查找指定联系人

3.7.1 查找并显示

  查找指定联系人还是先按指定方式进行查找, 找到了打印,否则显示通讯录为空,查找失败!

老样子,contact.h 文件中实现:

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

test.c 文件中实现:

case SEARCH:
	//查找
	SearchContact(&con);
	break;

在这里插入图片描述

contact.c 文件中实现:
  有了上面的经验,这时我们写查找这个人的代码就轻车熟路了:

void SearchContact(Contact* pc)
{
	assert(pc);//防止pc是无效的
	if (pc->sz == 0)
	{
		printf("通讯录为空,查找失败!\n");
		return;
	}
	char name[NAME_MAX];
	printf("请输入要查找人的名字:");
	scanf("%s", name);
	//查找名字为 name 的这个人
	int ret = FindByName(pc, name);
	if (ret == -1)
	{
		printf("要查找的这个人不存在!\n");
		return;
	}
}

然后将我们查到的这个人显示出来:

//显示找到的这个联系人
printf("%-s\t%-s\t%-5s\t%-15s\t%-20s\n", "姓名", "年龄", "性别", "电话", "住址");
printf("%-s\t%-d\t%-5s\t%-15s\t%-20s\n",
	pc->data[ret].name,
	pc->data[ret].age,
	pc->data[ret].sex,
	pc->data[ret].tele,
	pc->data[ret].addr
);

3.7.2 效果展示

在这里插入图片描述

  OK,这里我们也是成功的找到了通讯录中指定的联系人。

3.8 修改联系人的信息

3.8.1 查找联系人

  老样子:

contact.h 文件中实现:

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

test.c 文件中的case ADD中添加:

case MODIFY:
	//修改
	ModifyContact(&con);
	break;

在这里插入图片描述

有了上面两段代码,我们就可以在contact.c 文件中写删除联系人的代码了。

  
  

contact.c 文件中实现:

我们先实现一下是否能找到要修改的联系人:

void ModifyContact(Contact* pc)
{
	assert(pc);
	//判断是否为空
	if (pc->sz == 0)
	{
		printf("通讯录为空,无法进行修改!!\n");
		return;
	}

	char name[NAME_MAX];
	printf("请输入要修改的联系人姓名: ");
	scanf("%s", name);
	//判断是否有该联系人
	int ret = FindByName(pc, name);

	//有该联系人
	if (ret == -1)
	{
		printf("要修改的联系人不存在!\n");
		return;
	}
	int n = 0;
}

  然后重点来了 !!!
  然后重点来了 !!!
  然后重点来了 !!!

3.8.2 修改的菜单

  修改联系人信息这块就有很多种情况了,比如只修改一项,例如只修改名字或性别,也有可能修改多项例如名字、年龄等,也有可能得全部修改这几种情况。
  当我们要修改之前,我们能还是期望有一个菜单供我们选择,当修改完一项后我们可能还要继续修改。
  基于此我们还是采用和 test.c 文件中得 do…while 循环+菜单来提供选择不同的情况:

//修改联系人信息菜单
void Modifymenu()
{
	printf("*****************************************\n");
	printf("********* 1. name     2. age   **********\n");
	printf("********* 3. sex      4. tele  **********\n");
	printf("********* 5. addr     6. all   **********\n");
	printf("********* 0. exit              **********\n");
	printf("*****************************************\n");
}
//修改名字
void ModName(Contact* pc, int ret)
{
	assert(pc);
	printf("请输入修改后联系人姓名: ");
	scanf("%s", pc->data[ret].name);
	printf("名字修改成功!\n");
}
//修改年龄
void ModAge(Contact* pc, int ret)
{
	assert(pc);
	printf("请输入修改后联系人年龄: ");
	scanf("%d", &pc->data[ret].age);
	printf("年龄修改成功!\n");
}
//修改性别
void ModSex(Contact* pc, int ret)
{
	assert(pc);
	printf("请输入修改后联系人性别: ");
	scanf("%s", &pc->data[ret].sex);
	printf("性别修改成功!\n");
}
//修改电话
void ModTele(Contact* pc, int ret)
{
	assert(pc);
	printf("请输入修改后联系人电话: ");
	scanf("%s", &pc->data[ret].tele);
	printf("电话修改成功!\n");
}
//修改地址
void ModAddr(Contact* pc, int ret)
{
	assert(pc);
	printf("请输入修改后联系人地址: ");
	scanf("%s", &pc->data[ret].addr);
	printf("地址修改成功!\n");
}
void ModAll(Contact* pc, int ret)
{
	assert(pc);
	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");
}

  有了这个菜单,我们就能完善剩下的代码了:

enum Option
{
	EXIT,//0  退出
	NAME,//1  名字
	AGE,//2  年龄
	SEX,//3  性别
	TELE,//4  电话
	ADDR,//5  地址
	ALL,//6  全部
};
//修改联系人
void ModifyContact(Contact* pc)
{
	assert(pc);
	//判断是否为空
	if (pc->sz == 0)
	{
		printf("通讯录为空,无法进行修改!!\n");
		return;
	}

	char name[NAME_MAX];
	printf("请输入要修改的联系人姓名: ");
	scanf("%s", name);
	//判断是否有该联系人
	int ret = FindByName(pc, name);

	//有该联系人
	if (ret == -1)
	{
		printf("要修改的联系人不存在!\n");
		return;
	}
	int n = 0;
	do
	{
		Modifymenu();
		printf("请选择修改内容: ");
		scanf("%d", &n);
		//修改
		switch (n)
		{
		case NAME:
			ModName(pc, ret);
			break;
		case AGE:
			ModAge(pc, ret);
			break;
		case SEX:
			ModSex(pc, ret);
			break;
		case TELE:
			ModTele(pc, ret);
			break;
		case ADDR:
			ModAddr(pc, ret);
			break;
		case ALL:
			ModAll(pc, ret);
			break;
		case EXIT:
			printf("修改结束!\n");
			break;
		default:
			printf("选择数非法!\n");
			break;
		}
	} while (n);
}

3.8.3 效果展示

修改前的输入:
在这里插入图片描述
在这里插入图片描述

修改后的效果:

在这里插入图片描述

3.9 联系人的排序

3.9.1 代码

  上面,我们已经实现了通讯录的增删查改的基本功能!
  现在呢,我们还想让它再有一个排序功能,比如按名字排序,或年龄排序!我们在指针进阶那块介绍过回调函数,这里我们用 qsort 进行对通讯录排序!我们期望还是和上面的修改联系人一样,一开始有个菜单选择,然后可以让我们选择用名字排序还是用年龄排序:
  此处我们长话短说,一段代码全部显示:

//排序菜单
void Sortmenu()
{
	printf("**********************************\n");
	printf("***** 1. name    2. age **********\n");
	printf("**********************************\n");
}
//名字比较函数
int cmp_name(const void* str1, const void* str2)
{
	return strcmp((((Contact*)str1)->data)->name, (((Contact*)str2)->data)->name);
}
//年龄比较函数
int cmp_age(const void* str1, const void* str2)
{
	return (((Contact*)str1)->data)->age - (((Contact*)str2)->data)->age;
}
//名字排序
void SortName(Contact* pc)
{
	qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp_name);
}
//年龄排序
void SortAge(Contact* pc)
{
	qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp_age);
}
//排序联系人信息
void SortContact(Contact* pc)
{
	assert(pc);
	if (pc->sz == 0)
	{
		printf("通讯录为空,无法排序!\n");
		return;
	}

	Sortmenu();
	int n = 0;
	printf("请选择排序方式: ");
	scanf("%d", &n);
	//排序
	switch (n)
	{
	case 1:
		SortName(pc);
		printf("按名字排序成功!\n");
		break;
	case 2:
		SortAge(pc);
		printf("按年龄排序成功!\n");
		break;
	default:
		printf("选择的数是非法的!\n");
		break;
	}
}

3.9.2 效果显示

按名字排序:
在这里插入图片描述

按年龄排序:
在这里插入图片描述


四、显示优化

  截至到此,我们所有的功能就都实现了,但是我们可以发现我们的通讯录显示起来还是有点不舒服,每次选择完的结果都全部堆在了一起,看起来很乱!
  解决方法呢,就是将完成功能后的屏幕清理掉!而且清理前再加一个睡眠时间,避免操作后的结果一闪而过 !!!
  

在每次屏幕打印东西时都加上下面两段代码:

Sleep(1500);    //睡眠1.5秒
system(“cls”);   //清屏

Sleep(1500); //睡眠1.5秒
system("cls"); //清屏

当然记得包含头文件:#include<windows.h>

效果举例:
在这里插入图片描述


到这里就是全部代码的笔记了。




五、全部源码汇总

5.1 contact.h

#define _CRT_SECURE_NO_WARNINGS 1

#pragma once//确保一个头文件只编译一次

//函数的声明
#include<stdio.h>
#include<string.h>
#include<assert.h>
#include<stdlib.h>
#include<windows.h>

#define NAME_MAX 20  //名字
#define SEX_MAX 5    //性别
#define TELE_MAX 12  //电话
#define ADDR_MAX 30  //住址

#define MAX 100  //存放数据

typedef struct PeoInfo
{
	//一个人的信息
	char name[NAME_MAX];  //名字
	int age;   //年龄
	char sex[SEX_MAX];  //性别
	char tele[TELE_MAX];  //电话
	char addr[ADDR_MAX];  //地址
}PeoInfo;


typedef struct Contact
{
	PeoInfo data[MAX];//存放数据
	int sz;//记录当前通讯录中存放了多少个人的信息
}Contact;


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

//增加联系人
void AddContact(Contact* pc);

//显示联系人
void ShowContact(Contact* pc);

//删除联系人
void DelContact(Contact* pc);

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

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

//排序联系人
void SortContact(Contact* pc);

5.2 contact.c

#define _CRT_SECURE_NO_WARNINGS 1

//通讯录的实现
#include"contact.h"

void InitContact(Contact* pc)
{
	assert(pc);//防止pc是无效的

	memset(pc->data, 0, sizeof(pc->data));
	pc->sz = 0;
}

void AddContact(Contact* pc)
{
	assert(pc);//防止pc是无效的
	if (pc->sz == MAX)
	{
		printf("通讯录已满,无法继续添加联系人\n");
		Sleep(1500);
		return;
	}
	//添加信息
	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);

	//联系人的个数 +1
	pc->sz++;

	printf("添加成功!\n");
	Sleep(1500);
}

void ShowContact(Contact* pc)
{
	assert(pc);//防止pc是无效的
	if (pc->sz == 0)
	{
		printf("通讯录为空,请先添加联系人!\n");
		Sleep(1500);
		return;
	}
	int i = 0;
	printf("\n%-s\t%-s\t%-5s\t%-15s\t%-20s\n", "姓名", "年龄", "性别", "电话", "住址");
	for (int i = 0; i < pc->sz; i++)
	{
		printf("%-s\t%-d\t%-5s\t%-15s\t%-20s\n",
			pc->data[i].name,
			pc->data[i].age,
			pc->data[i].sex,
			pc->data[i].tele,
			pc->data[i].addr
		);
	}
	printf("\n");
}

//查找要删除的人并返回下标
int FindByName(const Contact* pc, const char* name)
{
	assert(pc);
	for (int i = 0; i < pc->sz; i++)
	{
		if (strcmp(pc->data[i].name, name) == 0)
		{
			return i;//找到联系人并返回其下标
		}
	}
	return -1;//找不到
}

void DelContact(Contact* pc)
{
	assert(pc);//防止pc是无效的
	if (pc->sz == 0)
	{
		printf("通讯录为空,无需删除!\n");
		Sleep(1500);
		return;
	}
	char name[NAME_MAX];
	printf("请输入要删除人的名字:");
	scanf("%s",name);
	//查找名字为 name 的这个人
	int ret = FindByName(pc, name);
	if (ret == -1)
	{
		printf("要删除的这个人不存在!\n");
		Sleep(1500);
		return;
	}
	//删除找到的这个联系人
	int i = 0;
	for (int i = ret; i < pc->sz - 1; i++)
	{
		pc->data[i] = pc->data[i + 1];
	}
	pc->sz--;
	printf("成功删除联系人%s!\n",name);
	Sleep(1500);
}

void SearchContact(Contact* pc)
{
	assert(pc);//防止pc是无效的
	if (pc->sz == 0)
	{
		printf("通讯录为空,查找失败!\n");
		Sleep(1500);
		return;
	}
	char name[NAME_MAX];
	printf("请输入要查找人的名字:");
	scanf("%s", name);
	//查找名字为 name 的这个人
	int ret = FindByName(pc, name);
	if (ret == -1)
	{
		printf("要查找的这个人不存在!\n");
		Sleep(1500);
		return;
	}
	//显示找到的这个联系人
	printf("%-s\t%-s\t%-5s\t%-15s\t%-20s\n", "姓名", "年龄", "性别", "电话", "住址");
	printf("%-s\t%-d\t%-5s\t%-15s\t%-20s\n",
		pc->data[ret].name,
		pc->data[ret].age,
		pc->data[ret].sex,
		pc->data[ret].tele,
		pc->data[ret].addr
	);
}

//修改联系人信息菜单
void Modifymenu()
{
	printf("*****************************************\n");
	printf("********* 1. name     2. age   **********\n");
	printf("********* 3. sex      4. tele  **********\n");
	printf("********* 5. addr     6. all   **********\n");
	printf("********* 0. exit              **********\n");
	printf("*****************************************\n");
}
//修改名字
void ModName(Contact* pc, int ret)
{
	assert(pc);
	printf("请输入修改后联系人姓名: ");
	scanf("%s", pc->data[ret].name);
	printf("名字修改成功!\n");
}
//修改年龄
void ModAge(Contact* pc, int ret)
{
	assert(pc);
	printf("请输入修改后联系人年龄: ");
	scanf("%d", &pc->data[ret].age);
	printf("年龄修改成功!\n");
}
//修改性别
void ModSex(Contact* pc, int ret)
{
	assert(pc);
	printf("请输入修改后联系人性别: ");
	scanf("%s", &pc->data[ret].sex);
	printf("性别修改成功!\n");
}
//修改电话
void ModTele(Contact* pc, int ret)
{
	assert(pc);
	printf("请输入修改后联系人电话: ");
	scanf("%s", &pc->data[ret].tele);
	printf("电话修改成功!\n");
}
//修改地址
void ModAddr(Contact* pc, int ret)
{
	assert(pc);
	printf("请输入修改后联系人地址: ");
	scanf("%s", &pc->data[ret].addr);
	printf("地址修改成功!\n");
}
void ModAll(Contact* pc, int ret)
{
	assert(pc);
	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");
	Sleep(1000);
}
enum ModifyOption
{
	EXIT,//0  退出
	NAME,//1  名字
	AGE,//2  年龄
	SEX,//3  性别
	TELE,//4  电话
	ADDR,//5  地址
	ALL,//6  全部
};
//修改联系人
void ModifyContact(Contact* pc)
{
	assert(pc);
	//判断是否为空
	if (pc->sz == 0)
	{
		printf("通讯录为空,无法进行修改!!\n");
		Sleep(1500);
		return;
	}

	char name[NAME_MAX];
	printf("请输入要修改的联系人姓名: ");
	scanf("%s", name);
	//判断是否有该联系人
	int ret = FindByName(pc, name);

	//有该联系人
	if (ret == -1)
	{
		printf("要修改的联系人不存在!\n");
		Sleep(1500);
		return;
	}
	int n = 0;
	do
	{
		Modifymenu();
		printf("请选择修改内容: ");
		scanf("%d", &n);
		//修改
		switch (n)
		{
		case NAME:
			ModName(pc, ret);
			break;
		case AGE:
			ModAge(pc, ret);
			break;
		case SEX:
			ModSex(pc, ret);
			break;
		case TELE:
			ModTele(pc, ret);
			break;
		case ADDR:
			ModAddr(pc, ret);
			break;
		case ALL:
			ModAll(pc, ret);
			break;
		case EXIT:
			printf("修改结束!\n");
			Sleep(1000);
			break;
		default:
			printf("选择数非法!\n");
			Sleep(1000);
			break;
		}
	} while (n);
}


//排序菜单
void Sortmenu()
{
	printf("**********************************\n");
	printf("***** 1. name    2. age **********\n");
	printf("**********************************\n");
}
//名字比较函数
int cmp_name(const void* str1, const void* str2)
{
	return strcmp((((Contact*)str1)->data)->name, (((Contact*)str2)->data)->name);
}
//年龄比较函数
int cmp_age(const void* str1, const void* str2)
{
	return (((Contact*)str1)->data)->age - (((Contact*)str2)->data)->age;
}
//名字排序
void SortName(Contact* pc)
{
	qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp_name);
}
//年龄排序
void SortAge(Contact* pc)
{
	qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp_age);
}
//排序联系人信息
void SortContact(Contact* pc)
{
	assert(pc);
	if (pc->sz == 0)
	{
		printf("通讯录为空,无法排序!\n");
		Sleep(1500);
		return;
	}

	Sortmenu();
	int n = 0;
	printf("请选择排序方式: ");
	scanf("%d", &n);
	//排序
	switch (n)
	{
	case 1:
		SortName(pc);
		printf("按名字排序成功!\n");
		Sleep(1000);
		break;
	case 2:
		SortAge(pc);
		printf("按年龄排序成功!\n");
		Sleep(1000);
		break;
	default:
		printf("选择的数是非法的!\n");
		Sleep(1000);
		break;
	}
}

5.3 test.c

#define _CRT_SECURE_NO_WARNINGS 1

//代码的测试
#include"contact.h"

void menu()
{
	printf("**********************************\n");
	printf("****  1. add        2. del    ****\n");
	printf("****  3. search     4. modify ****\n");
	printf("****  5. show       6. sort   ****\n");
	printf("****  0. exit 【退出程序】    ****\n");
	printf("**********************************\n");
}

enum Option
{
	EXIT,//0  退出
	ADD,//1  添加
	DEL,//2  删除
	SEARCH,//3  查找
	MODIFY,//4  修改
	SHOW,//5  显示
	SORT,//6  排序
};

int main()
{
	int input = 0;

	Contact con;//通讯录
	//初始化通讯录
	InitContact(&con);

	do
	{
		menu();
		printf("请输入你的选择:");
		scanf("%d", &input);
		switch (input)
		{
		case ADD:
			//添加
			AddContact(&con);
			Sleep(1500);
			system("cls");
			break;
		case DEL:
			//删除
			DelContact(&con);
			Sleep(1500);
			system("cls");
			break;
		case SEARCH:
			//查找
			SearchContact(&con);
			Sleep(1500);
			system("cls");
			break;
		case MODIFY:
			//修改
			ModifyContact(&con);
			Sleep(1500);
			system("cls");
			break;
		case SHOW:
			//显示
			ShowContact(&con);
			Sleep(1500);
			system("cls");
			ShowContact(&con);
			break;
		case SORT:
			//排序
			SortContact(&con);
			Sleep(1500);
			system("cls");
			break;
		case EXIT:
			printf("退出成功!\n");
			Sleep(1500);
			system("cls");
			break;
		default:
			printf("输入的选择错误!\n");
			Sleep(1500);
			system("cls");
			break;
		}
	} while(input);

	return 0;
}


完结

好啦,阅读到这里就已经看完了本期博客的全部内容了
在这里插入图片描述

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

敲键盘的小明

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

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

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

打赏作者

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

抵扣说明:

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

余额充值