C语言模拟实现动态通讯录

 更新时间:2021年07月23日 11:32:39   作者:小周同学ヾ(❀╹◡╹)ノ゙❀~  
本文主要介绍了C语言模拟实现动态通讯录,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

1.模拟实现通讯录总体架构一览图

在这里插入图片描述

2.文件执行任务

在这里插入图片描述

3.分模块实现

 测试模块 test.c

1.为了更好地展示,制作一个菜单,在菜单中有 添加,删除,查找,修改,排序,清空,退出的选项。
2.因为起先要进入程序一趟,所以用do····while循环(输入选项来看具体操作,退出还是其他操作)

 #include "contact.h"
void menu()
{

	printf("*****************************************\n");
	printf("********          Contact          ******\n");
	printf("********     1.add     2. del      ******\n");
	printf("********     3.search  4.modify    ******\n");
	printf("********     5.print   6.empty     ******\n");
	printf("********     7.sort    0.exit      ******\n");
	printf("*****************************************\n");

}
enum Option
//为什么要使用枚举
//因为这样可以防止命名污染,而且使用枚举,枚举成员有默认初始值,默认从0开始,这样省去的诸多的代码量
{
	EXIT,
	ADD,
	DEL,
	SEARCH,
	MODIFY,
	PRINT,
	EMPTY,
	SORT,
};
int main()
{
	//先打印菜单,展示通讯录功能
	int input = 0;
	//先进行设置一个通讯录
	//设置每个人的信息
	//初始化通讯录 
	//通讯录中的一个元素
	contact con; 
	//contact 是自定义数据类型,包括一个联系人的基本信息
	InitContact(&con);
	do
	{
		menu();//设置菜单
		printf("请选择>");
		scanf("%d", &input);
		switch (input)
		{
		case ADD:
			//实现添加功能
			AddContact(&con);
			break;
		case DEL:
			//实现删除功能
			DelContact(&con);
			break;
		case SEARCH:
			//实现查找功能
			SearchContact(&con);
			break;
		case MODIFY:
			//实现修改功能
			ModifyContact(&con);
			break;
		case PRINT:
			//显示
			PrintContact(&con);
			break;
		case SORT:
			//实现名字排序
			SortContact(&con);
			break;
		case EMPTY:
			//实现清空
			EmptyContact(&con);
			break;
		case EXIT:
			//退出程序
			ExitContact(&con);
			break;
		default:
			printf("输入错误,请重新输入\n");
		}
	} while (input);
	return 0;
}

头文件 功能函数声明 contact.h

1.声明各类功能函数
2.定义各个常量,把常量定义成通俗易懂的变量,便于在多处使用。
3.定义结构体,自定义类型中,有一个联系人的基本信息。

 #include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX_NAME 20 //定义姓名字符串的大小为20
#define MAX_SEX 10 //定义性别字符串的大小为10
#define MAX_TELE 12 //定义电话字符串的大小为12
#define MAX_ADDR 20 //定义地址字符串的大小为20
#define MAX 1000  //定义通讯录的最大容量为1000
#define IN_NUM 3  //在动态申请空间时默认空间为3
#define SET_NUM 2  //当基本信息大于3份时,开辟两个空间
//设置每一个人的信息
//通讯录规定要求一共有1000个人
typedef struct base
{
	char name[MAX_NAME]; //姓名
	char sex[MAX_SEX];   //性别
	int age;             //年龄
	char tele[MAX_TELE]; //电话
	char addr[MAX_ADDR]; //住址
}base;
//设置1000人的通讯录
//静态版
//typedef struct contact
//{
//	 
//	int sz;           //计算当前通讯录中联系人的个数
//	base data[MAX]; //存放联系人的信息
// 
//}contact;
//动态初始化通讯录
typedef struct contact
{
	//有个结构体类型中需要,监视通讯录人数的一项,还有当联系人为3人时,这时候要进行增容
	int sz;   //计算当前联系人的个数
	base* data; //指向动态申请的空间,存放联系人的信息
	int capciaty; //计算当前通讯录中的最大容量
}contact;

//初始化通讯录
void InitContact(contact* pc);
//添加联系人
void AddContact(contact* pc);
//显示
void PrintContact(contact* pc);
//删除联系人
void DelContact(contact* pc);
//查找联系人
void SearchContact(contact* pc);
//修改信息
void ModifyContact(contact* pc);
//排序联系人信息
void SortContact(contact* pc);
//清空联系人信息
void EmptyContact(contact* pc);
//退出程序时,释放空间
void ExitContact(contact* pc);

功能函数逐一实现

contact.c 1.初始化通讯录

动态申请空间
默认在动态空间中存放3个基本单位信息

 void InitContact(contact* pc)
{

	pc->data = (base*)malloc(sizeof(base) * IN_NUM);

	if (pc->data == NULL)
	//如果空间开辟失败
	//退出程序
	{
		perror("InitContact");
		return;
	}
	//把每个成员都设置为0
	pc->sz = 0;
 
	pc->capciaty = IN_NUM;
}

2.添加联系人

当默认的空间被装满时,然后以后的每一次都开辟两个基本空间

void AddContact(contact* pc)
{
//先判断通讯录中是否满了
	//if (pc->sz == MAX)
	//{
	//	printf("通讯录已满,无法添加\n");
	//	return;
	//}
	//动态判断人的个数是否满足3
	if (pc->sz == pc->capciaty)
	{
		printf("开始增容:\n");
		//从新设置一个指针,存放新开辟的内存
		base* ptr = (base*)realloc(pc->data, (pc->capciaty + SET_NUM) * sizeof(base));
		//判断是否开辟成功
		if (ptr == NULL)
		{
			printf("开辟失败\n");
			perror("AddContact");
			return;
		}
		else
		{
			printf("开辟成功\n");
			//开辟成功的话,把ptr转交给data来维护,这样在内存释放的时候只需要释放pc->data
			pc->data = ptr;
			//增加基本信息数量
			pc->capciaty += SET_NUM;
		}
		printf("增容完毕\n");
	}
	//添加
	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++;
	printf("添加成功\n");
}

3.显示联系人信息

逐一打印联系人信息,注意之间的距离(保持美观)

 //显示
void PrintContact(contact* pc)
{
	//显示标题
	printf("%-20s %-10s %-5s %-15s %-20s\n", "姓名", "性别", "年龄", "电话", "住址");
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		printf("%-20s %-10s %-5d %-15s %-20s\n", 
		    pc->data[i].name,
			pc->data[i].sex,
			pc->data[i].age,
			pc->data[i].tele,
			pc->data[i].addr);
	}
}

4.删除联系人

在删除联系人之前,首先要查找要删除联系人的名字,然后进行删除,注意如何删除
让删除的这个单位的后一个单位去覆盖这个删除的单位(这样原来要删除的地方变成了后面一个值) i = i+1
当通讯录中有被删除着的名字时,返回这个单位的下标
当通讯录中没有时,返回-1

 //查找联系人
static int Find_name(contact* pc, char name[])
{
	int i = 0;
	for ( i = 0; i < pc->sz; i++)
	{
		if (strcmp(pc->data[i].name, name) == 0)
		{
			return i;
		}
	}
	return -1;
}
//删除联系人
void DelContact(contact* pc)
{
	//如果通讯录是空的
	if (pc->sz == 0)
	{
		printf("通讯为空,无需删除\n");
		return;
	}
//下进行查找被删除联系人的名字
	char name[MAX_NAME];
	printf("请输入要删除联系人的名字:");
	scanf("%s", name);
	int ret = Find_name(pc, name);
	if (ret == -1)
	{
		printf("该联系人不存在\n");
		return;
	}
	//删除
	//删除项后边的一项,覆盖前面的一项
	for (int i = ret; i < pc->sz; i++)
	{
		pc->data[i] = pc->data[i + 1];
	}
	pc->sz--;
	printf("删除成功\n");
}

4.查找联系人

在删除联系人的时候有查找函数,在这里直接引用,并打印。这个人的信息。

 //查找联系人
void SearchContact(contact* pc)
{
	char name[MAX_NAME];
	printf("请输入要查找联系人的名字:");
	scanf("%s", name);
	int ret = Find_name(pc, name);
	if (ret == -1)
	{
		printf("该联系人不存在\n");
		return;
	}
	printf("%-20s %-10s %-5s %-15s %-20s\n", "姓名", "性别", "年龄", "电话", "住址");
	printf("%-20s %-10s %-5d %-15s %-20s\n", pc->data[ret].name,
			pc->data[ret].sex,
			pc->data[ret].age,
			pc->data[ret].tele,
			pc->data[ret].addr);
}

5.修该联系人信息

还是现在通讯录中查找这个联系人,在进行输入修改

 //修改信息
void ModifyContact(contact* pc)
{
	char name[MAX_NAME];
	printf("请输入要修改联系人的名字:");
	scanf("%s", name);
	int ret = Find_name(pc, name);
	if (ret == -1)
	{
		printf("该联系人不存在\n");
		return;
	}
	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);
}

6.排序联系人姓名

利用冒泡排序对联系人的名字进行排序(也可以使用快排)

 //排序
//交换名字,但是名字要和联系人的信息匹配
//先比较名字,根据名字的大小,再排序
static void SwapByname(base* pa, base* pb)
{
	base b;
	b = *pa;
	*pa = *pb;
	*pb = b;
}
void SortContact(contact* pc)
{
	printf("开始排序\n");
  //使用冒泡排序对联系人的名字进行排序
	int i = 0;
	int j = 0;
	for (i = 0; i < pc->sz; i++)
	{
		for (j = 0; j < pc-> sz - i - 1; j++)
		{
			if (strcmp(pc->data[j].name, pc->data[j + 1].name) > 0)
			{
				 //实现交换姓名
				SwapByname(&pc->data[j], &pc->data[j + 1]);
			}
		}
	}
	printf("排序结束\n");
}

7.清空联系人

在这里直接使用sz–,就可以删除

 //清空
void EmptyContact(contact* pc)
{
//如果原来的通讯录是空的就无须清空
	if (pc->sz == 0)
	{
		printf("通讯录为空,无需清空\n");
		return;
	}
	 
	printf("开始清除数据:\n");
	int num = pc->sz;
	for (int i = 0; i < num; i++)
	{
		pc->sz--;
	}
	printf("清空完毕\n");
}

8.退出通讯录

手动开辟,手动释放

 //退出程序,释放空间
void ExitContact(contact* pc)
{
	//释放空间
	free(pc->data);
	pc->data = NULL;
	pc->sz = 0;
	pc->capciaty = 0;
}

运行展示:

在这里插入图片描述

到此这篇关于C语言模拟实现动态通讯录的文章就介绍到这了,更多相关C语言 动态通讯录内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C++获取本机登陆过的QQ号码示例程序

    C++获取本机登陆过的QQ号码示例程序

    这篇文章主要介绍了使用C++获取本机登陆过的QQ号码列表的程序示例,大家可以参考使用
    2013-11-11
  • VC++ loadlibrary()加载三方dll失败, 返回错误码:126的解决方法

    VC++ loadlibrary()加载三方dll失败, 返回错误码:126的解决方法

    今天在编写VC++ loadlibrary()加载三方dll是总是失败,并且返回错误码:126,这里就为大家分享一下具体的解决方法
    2021-03-03
  • C/C++根据年月日计算星期几(蔡勒公式篇)

    C/C++根据年月日计算星期几(蔡勒公式篇)

    这篇文章主要给大家介绍了关于C/C++根据年月日计算星期几(蔡勒公式篇)的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-03-03
  • C++类成员函数中的名字查找问题

    C++类成员函数中的名字查找问题

    这篇文章主要介绍了C++类成员函数中的名字查找问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-11-11
  • C++ Boost MetaStateMachine定义状态机超详细讲解

    C++ Boost MetaStateMachine定义状态机超详细讲解

    Boost是为C++语言标准库提供扩展的一些C++程序库的总称。Boost库是一个可移植、提供源代码的C++库,作为标准库的后备,是C++标准化进程的开发引擎之一,是为C++语言标准库提供扩展的一些C++程序库的总称
    2022-12-12
  • C++浅析类与对象基础点

    C++浅析类与对象基础点

    类和对象是两种以计算机为载体的计算机语言的合称。对象是对客观事物的抽象,类是对对象的抽象。类是一种抽象的数据类型;变量就是可以变化的量,存储在内存中—个可以拥有在某个范围内的可变存储区域
    2022-07-07
  • C++标准之(ravalue reference) 右值引用介绍

    C++标准之(ravalue reference) 右值引用介绍

    临时对象的产生和拷贝所带来的效率折损,一直是C++所为人诟病的问题,下面简单地介绍一下Copy Elision、RVO,对此不感兴趣的可以直接跳过
    2012-11-11
  • 浅谈C++STL之双端队列容器

    浅谈C++STL之双端队列容器

    deque双端队列容器与vector很类似,采用线性表顺序存储结构。但与vector区别,deque采用分块的线性存储结构来存储数据,每块的大小一般为512B,将之称为deque块,所有的deque块使用一个map块进行管理,每个map数据项记录各个deque块的首地址。
    2021-06-06
  • C++实现String与UF8互转

    C++实现String与UF8互转

    这篇文章介绍了C++实现String与UF8互转的方法,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-05-05
  • C++ 11和C++98相比有哪些新特性

    C++ 11和C++98相比有哪些新特性

    C++11标准提供了许多有用的新特性。这篇文章特别针对使C++11和C++98相比看上去像一门新语言的特性
    2017-03-03

最新评论