通讯录的实现(C语言版)

2023-10-27

实现一个通讯录;

通讯录可以用来存储1000个人的信息,每个人的信息包括:姓名、性别、年龄、电话、住址

提供方法:

  1. 添加联系人信息
  2. 删除指定联系人信息
  3. 查找指定联系人信息
  4. 修改指定联系人信息
  5. 显示所有联系人信息
  6. 清空所有联系人
  7. 以名字排序所有联系人

目录

通讯录的创建

通讯录功能的实现

添加联系人信息

删除指定联系人信息

查找指定联系人信息

修改指定联系人信息

显示所有联系人信息

清空所有联系人

以名字排序所有联系人

以文件的形式保存(进阶)

实现效果

源码展示


通讯录的创建

首先我们知道通讯录中的信息不可能是单一的类型,他一定是多种数据类型整合而成的,因此需要创建一个结构体来存放通讯录信息:(为了能够方便更改某些信息, 可以把某些量设置为宏)

#define NAME_MAX 15//名字最大长度
#define SEX_MAX 8//性别最大长度
#define TELE_MAX 12//电话号码最大长度
#define ADDS_MAX 30//地址最大长度
struct Telephone
{
	char name[NAME_MAX];
	char sex[SEX_MAX];
	int age;
	char tele[TELE_MAX];
	char adds[ADDS_MAX];
};

这样一个结构体就可以存放一个人的信息,而要存放1000个人的信息,可以再创建一个结构体用来存放这些结构体数据:

struct TeleInfo
{
	struct Telephone* data;
	int sz;//表示通讯录的容量
};

我们知道这样一个结构体类型占用的内存比较大,而假如我们仅需要存储10个人20个人的信息,这时创建一个容量1000的通讯录就造成了内存的大量浪费,因此我们可以将其改进,设置成动态增长的模式:

#define CAPACITY 3//通讯录初始容量
#define ADD_CAPACITY 2//每次扩容增加的容量大小
#define NAME_MAX 15//名字最大长度
#define SEX_MAX 8//性别最大长度
#define TELE_MAX 12//电话号码最大长度
#define ADDS_MAX 30//地址最大长度
struct Telephone
{
	char name[NAME_MAX];
	char sex[SEX_MAX];
	int age;
	char tele[TELE_MAX];
	char adds[ADDS_MAX];
};
struct TeleInfo
{
	struct Telephone* data;
	int sz;
	int capacity;
};

初始设置的结构体大小比较小,等到内存不够时再重新开辟空间,这样就可以避免空间的浪费。

而这时再将其初始化,就创建出一个空通讯录:

void Init_TeleInfo(struct TeleInfo* p)
{
	assert(p);
	p->data = (struct Telephone*)malloc(CAPACITY * sizeof(struct Telephone));
	if (p->data == NULL)
	{
		perror("Init_TeleInfo()");
		return;
	}
	p->sz = 0;
	p->capacity = CAPACITY;
}

接着就可以根据要求设计内需了。

通讯录功能的实现

为了能够是的各部分功能都能实现,首先需要两个重要的函数:

1、保证容量功能(如果不够先进行增容)

这个判断函数不通过使用者直接调用,因此可以在函数前添加static:

static int check_TeleInfo(struct TeleInfo* p)
{
	if (p->sz == p->capacity)
	{
		//扩容
		struct Telephone* ptr = (struct Telephone*)realloc(p->data,
			(p->capacity + ADD_CAPACITY) * sizeof(struct Telephone));
		if (ptr == NULL)
		{
			perror("add_TeleInfo()");
			return -1;
		}
		p->data = ptr;
		p->capacity += ADD_CAPACITY;
		return 1;
	}
	return 0;
}

这时通讯录的容量确保是充足的,因此可以进行录入信息。

2、搜索信息功能

对于删除、查找、修改等操作,都需要首先判断通讯录中是否存在该联系人才能进行后续相关操作。因此首先需要写一个查找函数(这个函数同上,不通过使用者直接调用,因此可以在函数前添加static):

static int seek_TeleInfo(struct TeleInfo* p)
{
	assert(p);
	char name[NAME_MAX] = { 0 };
	printf("请输入联系人姓名:>");
	scanf("%s", name);
	int i = 0;
	for (i = 0; i < p->sz; i++)
	{
		if (strcmp(p->data[i].name, name) == 0)
		{
			return i;
		}
	}
	return -1;
}

有了这两个前置函数,就可以无障碍实现各部分功能,具体如下:

添加联系人信息

void add_TeleInfo(struct TeleInfo* p)
{
	assert(p);
	int flag = check_TeleInfo(p);
	if (flag == 1)
		printf("增容成功\n");
	else if (flag == -1)
		return;
	printf("请输入名字:>");
	scanf("%s", p->data[p->sz].name);
	printf("请输入性别:>");
	scanf("%s", p->data[p->sz].sex);
	printf("请输入年龄:>");
	scanf("%d", &(p->data[p->sz].age));
	printf("请输入电话:>");
	scanf("%s", p->data[p->sz].tele);
	printf("请输入地址:>");
	scanf("%s", p->data[p->sz].adds);
	p->sz++;
	printf("添加成功\n");
}

删除指定联系人信息

void del_TeleInfo(struct TeleInfo* p)
{
	assert(p);
	//判断联系人是否存在
	int ret = seek_TeleInfo(p);
	if (ret == -1)
	{
		printf("该联系人不存在\n");
		return;
	}
	else
	{
        //该位置后面的所有信息前移一格
		for (; ret < p->sz; ret++)
			p->data[ret] = p->data[ret + 1];
		p->sz--;
		printf("删除成功\n");
	}
}

查找指定联系人信息

void find_TeleInfo(struct TeleInfo* p)
{
	assert(p);
	int ret = seek_TeleInfo(p);
	if (ret == -1)
		return;
	else
	{
        //这里主要保证上下内容位置统一
		printf("%-10s\t%-10s\t%-10s\t%-10s\t%-20s\n", "姓名", "性别", "年龄", "电话", "地址");
		printf("%-10s\t%-10s\t%-10d\t%-10s\t%-20s\n", p->data[ret].name, p->data[ret].sex,
		p->data[ret].age, p->data[ret].tele, p->data[ret].adds);
	}
}

修改指定联系人信息

void modify_TeleInfo(struct TeleInfo* p)
{
	assert(p);
	//判断联系人是否存在
	int ret = seek_TeleInfo(p);
	if (ret == -1)
	{
		printf("该联系人不存在\n");
		return;
	}
	printf("请输入名字:>");
	scanf("%s", p->data[ret].name);
	printf("请输入性别:>");
	scanf("%s", p->data[ret].sex);
	printf("请输入年龄:>");
	scanf("%d", &(p->data[ret].age));
	printf("请输入电话:>");
	scanf("%s", p->data[ret].tele);
	printf("请输入地址:>");
	scanf("%s", p->data[ret].adds);
}

显示所有联系人信息

void show_TeleInfo(struct TeleInfo* p)
{
	int i = 0;
	printf("%-10s\t%-10s\t%-10s\t%-10s\t%-20s\n", "姓名", "性别", "年龄", "电话", "地址");
	for (i = 0; i < p->sz; i++)
	{
		printf("%-10s\t%-10s\t%-10d\t%-10s\t%-20s\n", p->data[i].name, p->data[i].sex,
			p->data[i].age, p->data[i].tele, p->data[i].adds);
	}
}

清空所有联系人

void destroy_TeleInfo(struct TeleInfo* p)
{
	free(p->data);
	p->data = NULL;
	p->sz = 0;
	p->capacity = 0;
}

以名字排序所有联系人

int cmp_name(const struct Telephone* str1, const struct Telephone* str2)
{
	return strcmp(str1->name, str2->name);
}
void sort_TeleInfo(struct TeleInfo* p)
{
	qsort(p->data, p->sz, sizeof(struct Telephone), cmp_name);
}

以文件的形式保存(进阶)

这时通讯录的功能已经全部实现,不过我们发现这样的通讯录无法保存,即下次使用时并不能找到上次退出前存储的信息。要解决这个问题,其实将信息以文件的形式保存即可。

既然如此,我们就需要在打开时首先读取文件,而在结束退出后保存文件,那么只需添加两个函数,就可以达到保存信息的功能。

读取文件可以在初始化通讯录后进行:

void Init_TeleInfo(struct TeleInfo* p)
{
	assert(p);
	p->data = (struct Telephone*)malloc(CAPACITY * sizeof(struct Telephone));
	if (p->data == NULL)
	{
		perror("Init_TeleInfo()");
		return;
	}
	p->sz = 0;
	p->capacity = CAPACITY;
	load_TeleInfo(p);//仅多一次函数调用
}

读取文件内容函数:

void load_TeleInfo(struct TeleInfo* p)
{
	//打开文件
	FILE* pf = fopen("contact.txt", "rb");
	if (pf == NULL)
	{
		perror("load_TeleInfo:fopen()");
		return;
	}
	//读取文件内容并存储在结构体中
	struct Telephone tmp = { 0 };
	while (fread(&tmp, sizeof(struct Telephone), 1, pf))
	{
		check_TeleInfo(p);
		p->data[p->sz] = tmp;
		p->sz++;
	}
	//关闭文件
	fclose(pf);
	pf = NULL;
}

通讯录保存可以在退出前进行:

void save_TeleInfo(struct TeleInfo* p)
{
	//打开文件
	FILE* pf = fopen("contact.txt", "wb");
	if (pf == NULL)
	{
		perror("save_TeleInfo:fopen");
		return;
	}
	//写文件
	int i = 0;
	while (i < p->sz) 
	{
		fwrite(p->data + i, sizeof(struct Telephone), 1, pf);
		i++;
	}
	//关闭文件
	fclose(pf);
	pf = NULL;
}

实现效果

源码展示

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<assert.h>

#define CAPACITY 3//通讯录容量
#define ADD_CAPACITY 2//每次扩容增加的容量大小
#define NAME_MAX 15//名字最大长度
#define SEX_MAX 8//性别最大长度
#define TELE_MAX 12//电话号码最大长度
#define ADDS_MAX 30//地址最大长度
struct Telephone
{
	char name[NAME_MAX];
	char sex[SEX_MAX];
	int age;
	char tele[TELE_MAX];
	char adds[ADDS_MAX];
};
struct TeleInfo
{
	struct Telephone* data;
	int sz;
	int capacity;
};
//初始化通讯录
void Init_TeleInfo(struct TeleInfo* p);
//保存通讯录
void save_TeleInfo(struct TeleInfo* pc);
//销毁通讯录
void destroy_TeleInfo(struct TeleInfo* p);
//添加联系人
void add_TeleInfo(struct TeleInfo* p);
//删除指定联系人
void del_TeleInfo(struct TeleInfo* p);
//查找指定联系人
void find_TeleInfo(struct TeleInfo* p);
//修改指定联系人
void modify_TeleInfo(struct TeleInfo* p);
//展示通讯录所有联系人
void show_TeleInfo(struct TeleInfo* p);
//将通讯录按名字排序
void sort_TeleInfo(struct TeleInfo* p);
#include"contact2.h"

static int check_TeleInfo(struct TeleInfo* p)
{
	if (p->sz == p->capacity)
	{
		//扩容
		struct Telephone* ptr = (struct Telephone*)realloc(p->data,
			(p->capacity + ADD_CAPACITY) * sizeof(struct Telephone));
		if (ptr == NULL)
		{
			perror("add_TeleInfo()");
			return -1;
		}
		p->data = ptr;
		p->capacity += ADD_CAPACITY;
		return 1;
	}
	return 0;
}

void load_TeleInfo(struct TeleInfo* p)
{
	//打开文件
	FILE* pf = fopen("contact.txt", "rb");
	if (pf == NULL)
	{
		perror("load_TeleInfo:fopen()");
		return;
	}
	//读取文件
	struct Telephone tmp = { 0 };
	while (fread(&tmp, sizeof(struct Telephone), 1, pf))
	{
		check_TeleInfo(p);
		p->data[p->sz] = tmp;
		p->sz++;
	}
	//关闭文件
	fclose(pf);
	pf = NULL;
}

void Init_TeleInfo(struct TeleInfo* p)
{
	assert(p);
	p->data = (struct Telephone*)malloc(CAPACITY * sizeof(struct Telephone));
	if (p->data == NULL)
	{
		perror("Init_TeleInfo()");
		return;
	}
	p->sz = 0;
	p->capacity = CAPACITY;
	load_TeleInfo(p);
}
void add_TeleInfo(struct TeleInfo* p)
{
	assert(p);
	int flag = check_TeleInfo(p);
	if (flag == 1)
		printf("增容成功\n");
	else if (flag == -1)
		return;
	printf("请输入名字:>");
	scanf("%s", p->data[p->sz].name);
	printf("请输入性别:>");
	scanf("%s", p->data[p->sz].sex);
	printf("请输入年龄:>");
	scanf("%d", &(p->data[p->sz].age));
	printf("请输入电话:>");
	scanf("%s", p->data[p->sz].tele);
	printf("请输入地址:>");
	scanf("%s", p->data[p->sz].adds);
	p->sz++;
	printf("添加成功\n");
}

static int seek_TeleInfo(struct TeleInfo* p)
{
	assert(p);
	char name[NAME_MAX] = { 0 };
	printf("请输入联系人姓名:>");
	scanf("%s", name);
	int i = 0;
	for (i = 0; i < p->sz; i++)
	{
		if (strcmp(p->data[i].name, name) == 0)
		{
			return i;
		}
	}
	return -1;
}
void find_TeleInfo(struct TeleInfo* p)
{
	assert(p);
	int ret = seek_TeleInfo(p);
	if (ret == -1)
	{
		printf("该联系人不存在\n");
		return;
	}
	else
	{
		printf("%-10s\t%-10s\t%-10s\t%-10s\t%-20s\n", "姓名", "性别", "年龄", "电话", "地址");
		printf("%-10s\t%-10s\t%-10d\t%-10s\t%-20s\n", p->data[ret].name, p->data[ret].sex,
		p->data[ret].age, p->data[ret].tele, p->data[ret].adds);
	}
}
void del_TeleInfo(struct TeleInfo* p)
{
	assert(p);
	//判断联系人是否存在
	int ret = seek_TeleInfo(p);
	if (ret == -1)
	{
		printf("该联系人不存在\n");
		return;
	}
	else
	{
		for (; ret < p->sz; ret++)
			p->data[ret] = p->data[ret + 1];
		p->sz--;
		printf("删除成功\n");
	}
}

void modify_TeleInfo(struct TeleInfo* p)
{
	assert(p);
	//判断联系人是否存在
	int ret = seek_TeleInfo(p);
	if (ret == -1)
	{
		printf("该联系人不存在\n");
		return;
	}
	printf("请输入名字:>");
	scanf("%s", p->data[ret].name);
	printf("请输入性别:>");
	scanf("%s", p->data[ret].sex);
	printf("请输入年龄:>");
	scanf("%d", &(p->data[ret].age));
	printf("请输入电话:>");
	scanf("%s", p->data[ret].tele);
	printf("请输入地址:>");
	scanf("%s", p->data[ret].adds);

}

void show_TeleInfo(struct TeleInfo* p)
{
	int i = 0;
	printf("%-10s\t%-10s\t%-10s\t%-10s\t%-20s\n", "姓名", "性别", "年龄", "电话", "地址");
	for (i = 0; i < p->sz; i++)
	{
		printf("%-10s\t%-10s\t%-10d\t%-10s\t%-20s\n", p->data[i].name, p->data[i].sex,
			p->data[i].age, p->data[i].tele, p->data[i].adds);
	}
}

int cmp_name(const struct Telephone* str1, const struct Telephone* str2)
{
	return strcmp(str1->name, str2->name);
}
void sort_TeleInfo(struct TeleInfo* p)
{
	qsort(p->data, p->sz, sizeof(struct Telephone), cmp_name);
}

void save_TeleInfo(struct TeleInfo* p)
{
	//打开文件
	FILE* pf = fopen("contact.txt", "wb");
	if (pf == NULL)
	{
		perror("save_TeleInfo:fopen");
		return;
	}
	//写文件
	int i = 0;
	while (i < p->sz) 
	{
		fwrite(p->data + i, sizeof(struct Telephone), 1, pf);
		i++;
	}
	//关闭文件
	fclose(pf);
	pf = NULL;
}

void destroy_TeleInfo(struct TeleInfo* p)
{
	free(p->data);
	p->data = NULL;
	p->sz = 0;
	p->capacity = 0;
}
#include"contact2.h"

void menu()
{
	printf("***********************\n");
	printf("****1.add   2.delete***\n");
	printf("****3.seek  4.modify***\n");
	printf("****5.show  6.clear ***\n");
	printf("****7.sort  0.exit  ***\n");
	printf("***********************\n");
}
enum choose
{
	EXIT,
	ADD,
	DELETE,
	SEEK,
	MODIFY,
	SHOW,
	CLEAR,
	SORT
};
int main()
{
	int input;
	struct TeleInfo con;
	//初始化通讯录
	Init_TeleInfo(&con);
	do
	{
		menu();
		printf("请选择你要进行的操作:>");
		scanf("%d", &input);
		switch (input)
		{
		case EXIT:
			save_TeleInfo(&con);
			printf("保存成功\n");
			destroy_TeleInfo(&con);
			printf("退出成功\n");
			break;
		case ADD:
			add_TeleInfo(&con);
			break;
		case DELETE:
			del_TeleInfo(&con);
			break;
		case SEEK:
			find_TeleInfo(&con);
			break;
		case MODIFY:
			modify_TeleInfo(&con);
			break;
		case SHOW:
			show_TeleInfo(&con);
			break;
		case CLEAR:
			destroy_TeleInfo(&con);
			break;
		case SORT:
			sort_TeleInfo(&con);
			break;		
		default:
			break;
		}
	} while (input);
	return 0;
}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

通讯录的实现(C语言版) 的相关文章

随机推荐

  • React前端渲染优化--父组件导致子组件重复渲染的问题

    1 适用场景 当父组件本身状态更新时 这个状态并没有作为props传给子组件 也会触发子组件更新机制 这样就造成了组件重复渲染的问题 2 解决 类组件 pureComponent 它是一个类 组件继承自它后 其作为子组件时 每次父组件更新后
  • 数据库视图、触发器

    1 delete和truncate区别 在有自动增长的前提上 用delete清空表后再插入数据 id会从被删除的最大的id 1开始 用 truncate清空表后再插入数据 id会从起始值开始 2 索引 唯一索引 已存在表 alter tab
  • 【C++简明教程】找数组或者Vector中最大最小值的索引

    导言 今天带来的程序是找出数组或者 Vector 中最大最小值的索引 在 Python 中 我们可以使用 numpy 库快速实现 那接下来就看看 C 是怎么实现的吧 主要使用到的函数是 max element 和 min element 基
  • 小程序自定义头部,返回按钮,指定返回某页面

    function navback backUrl if Taro getCurrentPages length lt 1 Taro switchTab url pages home home return if backUrl let Pa
  • 多线程的作用

    1 发挥多核CPU的优势 随着工业的进步 现在的笔记本 台式机乃至商用的应用服务器至少也都是双核的 4核 8核甚至16核的也都不少见 如果是单线程的程序 那么在双核CPU上就浪费了50 在4核CPU上就浪费了75 单核CPU上所谓的 多线程
  • 高性能Mysql——创建高性能的索引

    文章目录 索引类型 高性能的索引策略 独立的列 前缀索引和索引选择性 多列索引 覆盖索引 使用索引扫描来做排序 重复索引和冗余索引 索引优化 MRR ICP 索引类型 我们知道 索引的实现有很多种 在Mysql中 索引是在引擎中实现的 所以
  • Spring 框架基础(04):AOP切面编程概念,几种实现方式演示

    一 AOP基础简介 1 切面编程简介 AOP全称 Aspect Oriented Programming 面向切面编程 通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术 核心作用 可以对业务逻辑的各个部分进行隔离 从而使得业务
  • win10远程桌面连接服务器接示内部错误。

    搜出来的解决方案大多是让重置远程设置 这也是微软官方的解决方 案 如下 搜索框中输入 CMD 右键点击命令提示符 选择以管理员身份运行 在管理员运行的命令提示符窗口中执行以下的命令 netsh winsoc reset 奇怪的是我的电脑 重
  • GPT:通用预训练语言模型

    论文标题 Improving Language Understanding by Generative Pre Training 论文链接 https www cs ubc ca amuham01 LING530 papers radfor
  • linux下使用qt ,出现Unable to create a debugging engine问题的解决方法

    在进行调试 qt程序的时 出现了问题 Unable to create a debugging engine 根据百度经验 查看Kits下面的调试工具是否存在 如下图 我的调试工具是存在的 那么不能成功体调试的原因是什么呢 一个stack
  • MySQL之count(1)和count(*)的区别

    闲扯 很久以前 有一次我写了一个SQL select count from test 然后这个代码被我的其中一家公司的MySQL专家看到了 叫我过去说 你难道不知道咱们不允许写count 吗 你不知道count 1 更快吗 说完二话没说把我
  • jupyter修改默认工作路径

    修改Anaconda自动安装的jupyter notebook的默认工作路径 Anaconda默认安装的jupyter的工作路径是C Users 用户名 想要修改其默认的工作路径具体步骤如下 首先打开 Anaconda Prompt 在 A
  • 【react】react18的学习(十二)– 底层原理(二)之 迭代器 iterator

    迭代器iterator 是一种 ES6 规范 具有这种机制的数据结构才可以使用for of循环 返回每一项的值 原型链具有Symbol iterator属性的数据结构都具备 如数组 部分类数组 字符串等 普通对象就不能用 for of循环原
  • 【Echarts】配置项归纳

    Echarts 配置项归纳 一 title 二 legend 三 grid 四 xAxis yAxis 五 polar 六 radiusAxis 七 angleAxis 八 radar 九 dataZoom 1 内置型数据区域缩放组件 2
  • linux opencv人脸检测,OpenCV实现人脸检测例程

    前段时间看的OpenCV 其实有很多的例子程序 参考代码值得我们学习 对图像特征提取三大法宝 HOG特征 LBP特征 Haar特征有一定了解后 对本文中的例子程序刚开始没有调通 今晚上调通了 试了试效果还可以 还需要深入理解 值得大家动手试
  • Apache Commons DbUtils 快速上手

    Apache Commons DbUtils 快速上手 Hibernate太复杂 iBatis不好用 JDBC代码太垃圾 DBUtils在简单与优美之间取得了完美平衡 一 概述 DbUtils小巧的Java数据库操作工具 它在JDBC的基础
  • Keepalived结合Nginx实现WEB高可用服务

    前言 随着Nginx在国内的发展潮流 越来越多的互联网公司都在使用Nginx Nginx高性能 稳定性成为IT人士青睐的HTTP和反向代理服务器 Nginx负载均衡一般位于整个网站架构的最前端或者中间层 如果为最前端时单台Nginx会存在单
  • Lion:优化算法的符号发现

    文章目录 摘要 1 简介 2 算法的符号发现 2 1 程序搜索空间 2 2 高效搜索技术 2 3 泛化 方案选择与简化 3 Lion的推导与分析 3 1 求导 3 2 分析 4 Lion评估 4 1 图像分类 4 2 视觉 语言对比学习 4
  • 数据采集清洗

    文档名称 使用说明 程序名称 数据采集清洗分词V1 0 1简介 1 1数据采集程序 数据采集程序基于Python Urllib request模块编写 Urllib request是 HTTP 请求模块 可以模拟发送请求 支持自动确定响应内
  • 通讯录的实现(C语言版)

    实现一个通讯录 通讯录可以用来存储1000个人的信息 每个人的信息包括 姓名 性别 年龄 电话 住址 提供方法 添加联系人信息 删除指定联系人信息 查找指定联系人信息 修改指定联系人信息 显示所有联系人信息 清空所有联系人 以名字排序所有联