用c语言实现通讯录

news2024/11/17 1:47:10

目录

静态简易通讯录

代码:

功能模块展示:

设计思路:

动态简易通讯录(本质顺序表)

代码:

扩容模块展示:

设计思路:

文件版本通讯录

代码:

文件模块展示:

设计思路:


静态简易通讯录

代码:

//头文件内容

#pragma once

#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <stdlib.h>

//声明一个枚举类型增加主程序代码(switch部分)可读性
enum method
{
	EXIT,
	ADD,
	DELETE,
	FIND,
	MODIFY,
	SHOW,
	DESTROY,
	SORT
};

//定义标识符常量便于对数据大小修改
#define  MAX_NAME 20
#define  MAX_SEX 6
#define  MAX_TELEPHONE 12
#define  MAX_ADDRESS 20
#define  Max_PEOINFO 1000

//定义一个联系人信息结构体类型
typedef struct PeoInfo
{
	char name[MAX_NAME];
	char sex[MAX_SEX];
	int age;
	char Telephone[MAX_TELEPHONE];
	char address[MAX_ADDRESS];
}PeoInfo;

//创建一个联系人信息结构体数组和计数联系人个数的变量组成联系人结构体
typedef struct Contact
{
	PeoInfo data[Max_PEOINFO];
	int sz;
}Contact;


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

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

//展示所有联系人函数
void ShowContact(Contact* pc);

//删除联系人函数
void DeleteContact(Contact* pc);

//查找联系人函数
void FindContact(Contact* pc);

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

//清空联系人函数
void DestroyContact(Contact* pc);

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


//函数实现源文件内容

//初始化函数
void InitContact(Contact* pc)
{
    assert(pc);
	//利用库函数将整个数组所有元素初始化为0
	memset(pc->data, 0, sizeof(pc->data));
	//通讯录没有联系人
	pc->sz = 0;
}

//增加联系人函数
void AddContact(Contact* pc)
{
	assert(pc);
    //通讯录已满情况
	if (pc->sz == Max_PEOINFO)
	{
		printf("通讯录已满\n");
		return;
	}
    //通讯录未满情况
	printf("请输入联系人的姓名:>");
	scanf("%s", pc->data[pc->sz].name);
	printf("请输入联系人的性别:>");
	scanf("%s", pc->data[pc->sz].sex);
	printf("请输入联系人的年龄:>");
	scanf("%d", &(pc->data[pc->sz].age));
	printf("请输入联系人的电话:>");
	scanf("%s", pc->data[pc->sz].Telephone);
	printf("请输入联系人的地址:>");
	scanf("%s", pc->data[pc->sz].address);
    //每增加一个联系人,计数变量加1
	pc->sz = pc->sz + 1;
	printf("增加联系人成功\n");
}

//为了便于局部调试程序,先实现显示函数
//显示所有联系人
void ShowContact(Contact* pc)
{
	assert(pc);
	int i = 0;
    //打印内容左对齐
	printf("%-20s\t%-6s\t%-4s\t%-12s\t%-20s\n", "姓名", "性别", "年龄", "电话", "地址");
	for (i = 0; i < pc->sz; i++)
	{
		printf("%-20s\t%-6s\t%-4d\t%-12s\t%-20s\n",
			pc->data[i].name,
			pc->data[i].sex,
			pc->data[i].age,
			pc->data[i].Telephone,
			pc->data[i].address);
	}
}

//删除联系人时我们需要知道联系人在数组中的位置(以名字删除联系人)
//名字检索函数(不需要在头文件中声明)
//此函数无法在有同名联系人时精确找到联系人
int ModifyName(char* str, Contact* pc)
{
	assert(pc && str);
	int i = 0;
	//遍历已经存储了联系人的数组元素寻找第一个名字相符的联系人并返回下标
	for (i = 0; i < pc->sz; i++)
	{
		if (0 == strcmp(str, pc->data[i].name))
			return i;
	}
	//找不到
	return -1;
}

//删除指定联系人
//此函数无法在有同名联系人时精确删除联系人
void DeleteContact(Contact* pc)
{
	assert(pc);
	//以名字查找指定联系人
	char name[MAX_NAME] = { 0 };
	printf("请输入要删除的联系人的名字\n");
	scanf("%s", name);
	int num = ModifyName(name, pc);
	//找到了
	if (num != -1)
	{
		int i = 0;
		for (i = num; i < pc->sz; i++)
		{
			memcpy(pc->data + i, pc->data + (i + 1), sizeof(PeoInfo));
		}
		//删除后计数变量减1
		pc->sz = pc->sz - 1;
		printf("删除成功\n");
	}
	//没找到
	else
		printf("删除失败,找不到指定联系人\n");
}

//查找指定联系人
//此函数无法在有同名联系人时精确查找联系人
void FindContact(Contact* pc)
{
	assert(pc);
	//以名字查找指定联系人
	char name[MAX_NAME] = { 0 };
	printf("请输入要查找的联系人的名字\n");
	scanf("%s", name);
	//调用上面定义的名字检索函数
	int num = ModifyName(name, pc);
	//找到了打印此联系人信息
	if (num != -1)
	{
		printf("%-20s\t%-6s\t%-4s\t%-12s\t%-20s\n", "姓名", "性别", "年龄", "电话", "地址");
		printf("%-20s\t%-6s\t%-4d\t%-12s\t%-20s\n",
			pc->data[num].name,
			pc->data[num].sex,
			pc->data[num].age,
			pc->data[num].Telephone,
			pc->data[num].address);
	}
	//找不到
	else
		printf("找不到指定联系人\n");
}

//修改指定联系人
void ModifyContact(Contact* pc)
{
	assert(pc);
	//以名字查找指定联系人
	char name[MAX_NAME] = { 0 };
	printf("请输入要修改的联系人的名字\n");
	scanf("%s", name);
	//调用名字检索函数
	int num = ModifyName(name, pc);
	//找到后重新输入此联系人信息
	if (num != -1)
	{
		printf("请输入新的姓名\n");
		scanf("%s", pc->data[num].name);
		printf("请输入新的性别\n");
		scanf("%s", pc->data[num].sex);
		printf("请输入新的年龄\n");
		scanf("%d", &(pc->data[num].age));
		printf("请输入新的电话\n");
		scanf("%s", pc->data[num].Telephone);
		printf("请输入新的地址\n");
		scanf("%s", pc->data[num].address);
		printf("修改联系人成功\n");
	}
	//找不到
	else
		printf("找不到指定联系人\n");
}

//清空所有联系人
void DestroyContact(Contact* pc)
{
	assert(pc);
    //调用初始化函数将联系人结构体初始化
	InitContact(pc);
	printf("联系人已清空\n");
}

//拓展功能
//以名字对所有联系人升序排序
void SortContact(Contact* pc)
{
	assert(pc);
	int i = 0;
	//选择排序
	for (i = 0; i < pc->sz -  1; i++)
	{
		int j = i;
		for (j = i; j < pc->sz; j++)
		{
			if (strcmp(pc->data[i].name, pc->data[j].name) > 0)
			{
				PeoInfo tmp;
				memcpy(&tmp, pc->data[i].name, sizeof(PeoInfo));
				memcpy(pc->data[i].name, pc->data[j].name, sizeof(PeoInfo));
				memcpy(pc->data[j].name, &tmp, sizeof(PeoInfo));

			}
		}
	}
	printf("排序完成\n");
}


//主程序源文件内容

//菜单
void menu()
{
	printf("****** 1.ADD      2.DELETE ********\n");
	printf("****** 3.FIND     4.MODIFY ********\n");
	printf("****** 5.SHOW     6.DESTROY********\n");
	printf("****** 7.SORT     0.EXIT   ********\n");
}

void test()
{
	//定义一个通讯录结构体变量
	Contact con;
	//初始化
	InitContact(&con);
	enum method input = 0;
	do
	{
		menu();
		printf("请选择你的操作\n");
		scanf("%d", &input);
		switch (input)
		{
		case ADD:
			AddContact(&con);
			break;
		case DELETE:
			DeleteContact(&con);
			break;
		case FIND:
			FindContact(&con);
			break;
		case MODIFY:
			ModifyContact(&con);
			break;
		case SHOW:
			ShowContact(&con);
			break;
		case DESTROY:
			DestroyContact(&con);
			break;
		case SORT:
			SortContact(&con);
			break;
		case EXIT:
			printf("程序已退出\n");
			break;
		default:
			printf("输入错误,请重新输入:>\n");
			break;
		}
	} while (input);
}
int main()
{
	test();
	return 0;
}

功能模块展示:

增加功能:

删除功能:

查找功能:

修改功能:

拓展功能:

设计思路:

要实现一个简易版静态通讯录,无非是在实现增删查改的基础上进行进一步的功能拓展,因此设计的重点是在增删查改的功能实现上,静态版本存储通讯录内容的是定长数组,因此要实现这些功能,我们需要围绕数组下标和已经存储的联系人个数作为文章。

只要知道已经存储的联系人个数,增加联系人就会变得轻而易举。而删除,查找,修改联系人时都必须先找到要操作的联系人,因此我们需要先实现一个检索联系人接口供它们调用,此接口实现的越精确,删查改就会越精确。

为了方便对数组下标进行操作,将计数联系人个数的变量和记录联系人信息的数组都作为通讯录结构体的成员,计数变量从0开始,每增加一个联系人就加1,删除减1,这样我们就会得到通讯录的实时大小从而可以非常容易的操作通讯录,实现通讯录的功能也就变的非常简单。

动态简易通讯录(本质顺序表)

代码:

动态版本的代码只需在静态版本上稍作修改即可。

//头文件增加和修改的内容

//初始容量
#define  INIT_SZ 3
//每次扩容增加容量
#define  ADD_SZ 2

//修改后通讯录结构体
typedef struct Contact
{
	//PeoInfo data[Max_PEOINFO];
    //用结构体指针代替结构体数组
	PeoInfo* data;
	int sz;
    //增加一个记录通讯录容量的变量
	int capacity;
}Contact;


//函数实现源文件增加和修改的内容

//动态版本初始化函数
void InitContact(Contact* pc)
{
	assert(pc);
    //先开辟INIT_SZ个空间
	pc->data = (PeoInfo*)malloc(INIT_SZ * sizeof(PeoInfo));
    //开辟失败
	if (pc->data == NULL)
	{
		perror("InitContact");
		return;
	}
	pc->sz = 0;
    //记录容量
	pc->capacity = INIT_SZ;
}

//增加联系人时需要先检查容量是否已满,若满则增加容量
//空间动态增长(无需在头文件中声明)
int mallocContact(Contact* pc)
{
	assert(pc);
	//已满
	if (pc->sz == pc->capacity)
	{
		//扩容
		PeoInfo* ptr = (PeoInfo*)realloc(pc->data, (pc->capacity + ADD_SZ) * sizeof(PeoInfo));
		//扩容失败
		if (ptr == NULL)
		{
			perror("mallocContact");
			return 0;
		}
		//扩容成功
		else
		{
			pc->data = ptr;
			pc->capacity += ADD_SZ;
			printf("扩容成功\n");
			return 1;
		}
	}
	//未满
	return 1;
}

//动态版本增加函数
void AddContact(Contact* pc)
{
	assert(pc);
	//扩容失败
	if (0 == mallocContact(pc))
	{
		return;
	}
	//未满或扩容成功
	printf("请输入联系人的姓名\n");
	scanf("%s", pc->data[pc->sz].name);
	printf("请输入联系人的性别\n");
	scanf("%s", pc->data[pc->sz].sex);
	printf("请输入联系人的年龄\n");
	scanf("%d", &(pc->data[pc->sz].age));
	printf("请输入联系人的电话\n");
	scanf("%s", pc->data[pc->sz].Telephone);
	printf("请输入联系人的地址\n");
	scanf("%s", pc->data[pc->sz].address);
	pc->sz = pc->sz + 1;
	printf("增加联系人成功\n");
	
}

//动态版本清空函数
void DestroyContact(Contact* pc)
{
	assert(pc);
    free(pc->data);
    pc->data = NULL;
	pc->sz = 0;
    pc->capacity = 0;
	printf("联系人已清空\n");
}

扩容模块展示:

设计思路:

静态版本的通讯录十分死板,需要存储的数据少了就会存在空间浪费,多了又会不够,因此衍生出动态版本来解决这一问题,当存储空间不够时就向内存申请新的空间来增加容量,更加灵活。

为了实现实时向内存申请空间,需要一个变量用来记录通讯录结构体的容量,当存储的联系人个数等于容量时就需要进行扩容,同时由于通讯录的大小是动态变化的,因此用结构体指针替代结构体数组来维护存储空间。

由于每次扩容后的存储空间依然是连续的,因此在没有发生访问越界时可以像操作数组一样操作指针,静态版本的大多数代码都无需修改。

文件版本通讯录

代码:

在动态版本上稍作修改。

//函数实现源文件增加和修改的内容

//容量检查函数声明
int mallocContact(Contact* pc);

//初始化时需要先读取文件contact.dat的内容到data中去
void LoadContact(Contact* pc)
{
	//打开文件
	FILE* pf = fopen("contact.dat", "rb");
    //若路径下没有此文件,则打开文件失败
	if (pf == NULL)
	{
		perror("LoadContact");
		return;
	}
	PeoInfo tmp = { 0 };
	//读文件
	while (fread(&tmp, sizeof(PeoInfo), 1, pf))
	{
		//扩容判断
		if (0 == mallocContact(pc))
			return;
		pc->data[pc->sz] = tmp;
		//每读取一个计数变量加1
		pc->sz++;
	}
	//关闭文件
	fclose(pf);
	pf = NULL;
}

//动态版本初始化函数
void InitContact(Contact* pc)
{
	assert(pc);
	pc->data = (PeoInfo*)malloc(INIT_SZ * sizeof(PeoInfo));
	if (pc->data == NULL)
	{
		perror("InitContact");
		return;
	}
	pc->sz = 0;
	pc->capacity = INIT_SZ;
	//载入文件内容
	LoadContact(pc);
}

//将通讯录信息以二进制形式保存到contact.dat文件中
void SaveContact(Contact* pc)
{
	//打开文件(若路径下没有此文件,则新建一个此文件)
	FILE* pf = fopen("contact.dat", "wb");
	if (pf == NULL)
	{
		perror("SaveContact");
		return;
	}
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		//写入文件
		fwrite(pc->data + i, sizeof(PeoInfo), 1, pf);
	}
	//关闭文件
	fclose(pf);
	pf == NULL;
	printf("通讯录内容已保存到contact.dat文件中\n");
}


//主程序源文件修改内容

case EXIT:
    //在退出程序时将内存中的信息保存到文件中去
	SaveContact(&con);
	printf("程序已退出\n");
	break;

文件模块展示:

设计思路:

无论是静态版本还是动态版本,联系人信息都是存储在内存中的,一旦程序退出运行,这些信息也会随之消失,为了长久存储这些信息,衍生出了文件版本的通讯录,即利用文件操作函数将存储在内存中的信息存储到文件中长久保存。

我们只需要在动态版本的基础上增加一个读取文件函数和写入文件函数,在程序开始时先将文件中的信息读取到内存中,在程序退出时再将内存中的数据写回文件中即可。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1839351.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

运维篇-配置高级

黑马程序员Spring Boot2 文章目录 1、临时属性1.1 命令行中使用临属性1.2 开发环境设定临时属性 2、配置文件分类3、自定义配置文件 1、临时属性 1.1 命令行中使用临属性 使用jar命令启动Sprigboot工程师可以使用临时属性替换配置文件中的属性临时属性添加方式&#xff1a;ja…

数据结构——排序(期末总结)

1. 插入排序 1.1 直接插入排序 思想 假设第一个元素是已经排好序的元素&#xff0c;从第二个元素开始依次插入操作&#xff0c;大的放后面&#xff0c;小的放前面。 代码 void insert(int a[], int n) {int i, j, key;for (i 2; i < n; i){key a[i];j i - 1;while (j…

SCI绘图【1】-不同颜色表示密度和差异--密度图

参考资料&#xff1a;密度图&#xff08;Density Plot&#xff09; - 数据可视化图表 - 数字孪生百科 密度图是快速观察变量数值分布的有效方法之一。通常情况下&#xff0c;会根据两个变量将平面绘图区域分为非常多的子区域&#xff0c;之后以不同颜色表示落在该区域上样本的…

【Linux】—MySQL安装

文章目录 前言一、下载官方MySQL包二、下载完成后&#xff0c;通过xftp6上传到Linux服务器上三、解压MySQL安装包四、在安装目录下执行rpm安装&#xff0c;请按顺序依次执行。五、配置MySQL六、启动MySQL数据库七、退出&#xff0c;重新登录数据库 前言 本文主要介绍在Linux环境…

内网渗透什么意思,怎么做好安全防范?

在当前高度数字化的世界中&#xff0c;企业和组织使用内网&#xff08;即内部网络&#xff09;来处理各种敏感数据与关键业务活动。然而&#xff0c;内网同样面临各种网络安全威胁&#xff0c;内网渗透就是其中一种。了解内网渗透的具体含义&#xff0c;并采取相应的安全防范措…

新火种AI|实属罕见!四大AI顶流同台,有哪些关键信息值得关注?

作者&#xff1a;小岩 编辑&#xff1a;彩云 在有着“AI春晚”之称的2024年智源大会上&#xff0c;非常难得的一幕出现了&#xff1a;当下国内的四大AI顶流公司——月之暗面&#xff0c;百川智能&#xff0c;智谱AI&#xff0c;面壁智能齐聚一堂&#xff0c;十分罕见的同台了…

注塑件检测视觉检测中可能遇到的外观缺陷

机器视觉检测注塑件不良特征有哪些&#xff1f;按照检测需求一般分为两类&#xff1a;外观缺陷和尺寸缺陷。但由于注塑件的工艺特点及原材料特性&#xff0c;注塑件外观缺陷在生产过程中出现的概率于频率远远大于尺寸缺陷。 注塑件检测视觉检测中可能遇到的外观缺陷 1、色差&a…

【Linux】 yum学习

yum介绍 在Linux系统中&#xff0c;yum&#xff08;Yellowdog Updater, Modified&#xff09;是一个用于管理软件包的命令行工具&#xff0c;特别适用于基于RPM&#xff08;Red Hat Package Manager&#xff09;的系统&#xff0c;如CentOS、Fedora和Red Hat Enterprise Linux…

油猴hook+内存爆破

hook方式 说明&#xff1a;来回翻页发现只有请求体的token需要逆向&#xff0c;而这个请求体是在params里&#xff0c;拼接到url里&#xff0c;可以直接用油猴hook url里的关键字token。 正常步骤 hook代码 // UserScript // name hookparams // namespace htt…

【Pmac】PMAC QT联合开发中各种可能遇到的坑

目录 1. 错误 C2027 使用了未定义类型“PCOMMSERVERLib::DEVUPLOAD”2. 输入了正确的pmac的ip地址&#xff0c;没有显示可选的pmac设备3. Pmac DTC-28B无读数 使用QT编写PMAC上位机程序时&#xff0c;利用QT中的dump工具可以将pcommserver.exe转化为pcommserverlib.h和pcommser…

【面试实战】# 并发编程之线程池配置实战

1.先了解线程池的几个参数含义 corePoolSize (核心线程池大小): 作用: 指定了线程池维护的核心线程数量&#xff0c;即使这些线程处于空闲状态&#xff0c;它们也不会被回收。用途: 核心线程用于处理长期的任务&#xff0c;保持最低的线程数量&#xff0c;以减少线程的创建和…

科学技术创新杂志科学技术创新杂志社科学技术创新编辑部2024年第12期目录

科技创新 基于均质与细晶化的高性能限动芯棒生产工艺优化与实践 吕鹏昊;刘松; 1-4 大地电磁测深法在水文地质勘察中的应用研究 熊俊杰;毛卫东; 5-8 电石乙炔法制取聚氯乙烯生产工艺分析 龚志平; 9-12《科学技术创新》投稿&#xff1a;cnqikantg126.com 地面三维…

【LeetCode:394. 字符串解码 + 栈 | 递归】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

VUE3实现个人网站模板源码

文章目录 1.设计来源1.1 网站首页页面1.2 个人工具页面1.3 个人日志页面1.4 个人相册页面1.5 给我留言页面 2.效果和源码2.1 动态效果2.2 目录结构 源码下载万套模板&#xff0c;程序开发&#xff0c;在线开发&#xff0c;在线沟通 作者&#xff1a;xcLeigh 文章地址&#xff1…

头歌资源库(13)背包问题

一、 问题描述 二、算法思想 这是一个背包问题&#xff0c;可以使用动态规划算法来解决。具体思路如下&#xff1a; 定义一个二维数组dp&#xff0c;dp[i][j]表示前i个物品在背包容量为j时能获取的最大价值。初始化dp数组的第一行和第一列为0&#xff0c;表示当只有一个物品或…

西木科技Westwood-Robotics人型机器人Bruce配置和真机配置

西木科技Westwood-Robotics人型机器人Bruce配置和真机配置 本文内容机器人介绍Bruce机器人Gazebo中仿真代码部署Bruce真机代码部署 本文内容 人形机器人Brcue相关介绍docker中安装Gazebo并使用Bruce机器人控制器更换环境配置 机器人介绍 公司&#xff1a;西木科技Westwood-R…

Microsoft AI Day:支持开放合作,普及技术应用,推进行业企业智慧化创新

微软在北京举办以“共创AI创新&#xff0c;智启无限可能”为主题的Microsoft AI Day活动&#xff0c;集中展示了在生成式智能技术加速发展普及的过程中&#xff0c;微软取得的最新技术突破与进展&#xff0c;并同步更新了在Microsoft Build 2024全球开发者大会上发布的一系列Az…

【MATLAB源码-第227期】基于matlab的北方苍鹰优化算法(NGO)机器人栅格路径规划,输出做短路径图和适应度曲线。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 鼠群优化算法&#xff08;Rat Swarm Optimization, RSO&#xff09; 简介 鼠群优化算法&#xff08;Rat Swarm Optimization, RSO&#xff09;是一种模仿鼠类群体觅食行为的优化算法。该算法属于群体智能算法&#xff0c;通…

Mathtype7.6最新破解版下载,功能超乎你想象!

嘿&#xff0c;亲爱的小伙伴们&#xff01;今天我要分享一个让你的学术生涯或教育工作变得轻松无比的秘密工具 —— Mathtype7.6最新破解版下载。&#x1f389; MathType最新Win官方版本下载如下: https://wm.makeding.com/iclk/?zoneid34223 MathType最新Mac官方版本下载如…

macOS聚集搜索功能开启与关闭

按下command空格弹出 使用搜索 关闭搜索 sudo mdutil -a -i off 启用搜索 sudo mdutil -a -i on