通讯录(顺序表的应用)

文章目录

  • 顺序表思想实现通讯录
    • 头文件
    • 接口函数
    • 主函数

顺序表思想实现通讯录

实现通讯录前,我们考虑一下,通讯录需要包含什么内容?

联系人,联系人需要包含姓名年龄电话性别这3种基本信息。

我们知道顺序表实质是个数组,如果我们让数组的每个元素都代表一个联系人,每个联系人又需要包含多条信息,所以,我们想到结构体,让数组的每个元素都是结构体,结构体就能很好地描述每一个联系人。

对于这样一个通讯录,我们采用顺序表的思想,但不单独写顺序表的接口,直接实现通讯录的接口,从无到有。

头文件

头文件的书写主要注意以下事项:

  • 结构体的声明
  • 命名的可读性,便于理解
  • 需要哪些对通讯录操作,声明出对应函数
//Contact.h

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

#define MAX_NAME 20
#define MAX_GENDER 10
#define MAX_TELNUM 20

typedef struct personinfo
{
	char name[MAX_NAME];
	size_t age;
	char telnum[MAX_TELNUM];
	char gender[MAX_GENDER];
}peoinfo;

typedef struct Contact
{
	peoinfo* a;
	int size;
	int capacity;
}Contact;

//初始化通讯录
void ContactInit(Contact* con);

//添加联系人
void ContactAdd(Contact* con);

//删除联系人
void ContactDel(Contact* con);

//修改联系人
void ContactModify(Contact* con);

//展示通讯录
void ContactShow(Contact* con);

//查找联系人信息
void ContactFind(Contact* con);

//销毁通讯录
void ContactDestory(Contact* con);

接口函数

注意:

  • 函数实现要包含必要的语句说明
  • 函数主体部分为顺序表的增删查改
//Contact.c

# define _CRT_SECURE_NO_WARNINGS 1
#include "Contact.h"

void ContactInit(Contact* con)
{
	assert(con);
	con->a = NULL;
	con->size = 0;
	con->capacity = 0;
}


void ContactAdd(Contact* con)
{
	assert(con);
	peoinfo new;
	printf("请输入新联系人的姓名:\n");
	scanf("%s", new.name);
	printf("请输入新联系人的年龄:\n");
	scanf("%zd", &new.age);
	printf("请输入新联系人的电话:\n");
	scanf("%s", new.telnum);
	printf("请输入新联系人的性别:\n");
	scanf("%s", new.gender);
	if (con->size == con->capacity)
	{
		int newcapacity = con->capacity == 0 ? 4 : con->capacity * 2;
		peoinfo* tmp = (peoinfo*)realloc(con->a, sizeof(peoinfo) * newcapacity);
		if (NULL == tmp)
		{
			printf("add error!REASON: realloc function failed!\n");
			exit(-1);
		}
		con->a = tmp;
		con->capacity = newcapacity;
	}
	con->a[con->size] = new;
	con->size++;
}


int FindIndex(Contact* con, char* obj)
{
	for (int i = 0; i < con->size; i++)
	{
		if (0 == strcmp(con->a[i].name, obj))
			return i;
	}
	return -1;
}
void ContactDel(Contact* con)
{
	assert(con);
	char del[MAX_NAME] = { 0 };
	printf("请输入要删除的联系人的姓名:\n");
	scanf("%s", del);
	int ret = FindIndex(con, del);
	if (ret < 0)
	{
		printf("您要删除的联系人不存在!\n");
		return;
	}
	else
	{
		for (int i = ret; i < con->size - 1; i++)
		{
			con->a[i] = con->a[i + 1];
		}
		con->size--;
		printf("删除成功!\n");
	}
}


void ContactModify(Contact* con)
{
	assert(con);
	char mod[MAX_NAME] = { 0 };
	printf("请输入要修改的联系人的姓名:\n");
	scanf("%s", mod);
	int ret = FindIndex(con, mod);
	if (ret < 0)
	{
		printf("您要修改的联系人不存在!\n");
		return;
	}
	else
	{
		char newmod[MAX_NAME] = { 0 };
		size_t newage = 0;
		char newtelnum[MAX_TELNUM] = { 0 };
		char newgender[MAX_TELNUM] = { 0 };

		printf("请输入新的联系人姓名:\n");
		scanf("%s", con->a[ret].name);

		printf("请输入新的联系人年龄:\n");
		scanf("%zd", &con->a[ret].age);

		printf("请输入新的联系人电话:\n");
		scanf("%s", con->a[ret].telnum);

		printf("请输入新的联系人性别:\n");
		scanf("%s", con->a[ret].gender);
		printf("修改成功!\n");
	}

}


void ContactShow(Contact* con)
{
	assert(con);
	if (con->size == 0)
	{
		printf("通讯录为空!\n");
		return;
	}
	else
	{
		printf("----------------------------------------------------------------------------------\n");
		printf("%-11s %-11s %-11s %-11s\n", "姓名", "年龄", "电话", "性别");
		for (int i = 0; i < con->size; i++)
		{
			printf("%-11s %-11zd %-11s %-11s\n", con->a[i].name, con->a[i].age, con->a[i].telnum, con->a[i].gender);
		}
		printf("----------------------------------------------------------------------------------\n");
	}
}


void ContactFind(Contact* con)
{
	assert(con);
	char find[MAX_NAME] = { 0 };
	printf("请输入要查询的联系人的姓名:\n");
	scanf("%s", find);
	int ret = FindIndex(con, find);
	if (ret < 0)
	{
		printf("您要查询的联系人不存在!\n");
		return;
	}
	else
	{
		printf("查询结果如下:\n");
		printf("%-11s %-11s %-11s %-11s\n", "姓名", "年龄", "电话", "性别");
		printf("%-11s %-11zd %-11s %-11s\n", con->a[ret].name, con->a[ret].age, con->a[ret].telnum, con->a[ret].gender);
	}
}


void ContactDestory(Contact* con)
{
	assert(con);
	con->size = con->capacity = 0;
	free(con->a);
	con->a = NULL;
}

主函数

主函数里也是包含一些函数定义的,包括菜单、加载文件、写入文件。

为了持久化保留数据,我们需要调用我们之前学习过的文件知识,将每次更新的数据写入文件中,每次启动程序前载入历史数据,每次程序终止前写入文件,这样就完成了通讯录。
关于文件知识,小裤儿之前发布过一篇文件管理的博客,介绍了文件管理函数等知识。

//interface.c

# define _CRT_SECURE_NO_WARNINGS 1
#include "Contact.h"

void menu()
{
	printf("******************通讯录*******************\n");
	printf("*******1.添加联系人     2.删除联系人*******\n");
	printf("*******3.修改联系人     4.查询联系人*******\n");
	printf("*******5.展示通讯录     0.退出通讯录*******\n");
	printf("*******************************************\n");
}

void SaveContact(Contact* con)
{
	FILE* pf = fopen("contact.txt", "wb");
	if (NULL == pf)
	{
		perror("fopen");
		return;
	}
	for (int i = 0; i < con->size; i++)
	{
		fwrite(con->a + i, sizeof(peoinfo), 1, pf);
	}
	fclose(pf);
	pf = NULL;
	printf("通讯录数据保存成功!\n");
}

void LoadContact(Contact* con)
{
	FILE* pf = fopen("contact.txt", "rb");
	if (NULL == pf)
	{
		perror("fopen");
		return;
	}
	peoinfo buff;
	while (fread(&buff, sizeof(peoinfo), 1, pf))
	{
		if (con->size == con->capacity)
		{
			int newcapacity = con->capacity == 0 ? 4 : con->capacity * 2;
			peoinfo* tmp = (peoinfo*)realloc(con->a, sizeof(peoinfo) * newcapacity);
			if (NULL == tmp)
			{
				printf("add error!REASON: realloc function failed!\n");
				exit(-1);
			}
			con->a = tmp;
			con->capacity = newcapacity;
		}
		con->a[con->size] = buff;
		con->size++;
	}
	fclose(pf);
	pf = NULL;
	printf("历史数据读取成功!\n");
}

int main()
{
	Contact con;
	ContactInit(&con);
	LoadContact(&con);
	int input = 0;
	do
	{
		menu();
		printf("请输入你想执行的操作:\n");
		scanf("%d", &input);
		switch (input)
		{
		case 1:ContactAdd(&con);
			break;
		case 2:ContactDel(&con);
			break;
		case 3:ContactModify(&con);
			break;
		case 4:ContactFind(&con);
			break;
		case 5:ContactShow(&con);
			break;
		case 0:printf("退出通讯录\n");
			break;
		default:
			printf("输入非法,请重新输入!\n");
			break;
		}
	} while (input);
	SaveContact(&con);
	ContactDestory(&con);
	return 0;
}

学好了顺序表后,通讯录的实现较为简单,代码很容易看懂,如果代码实现有难度,可能是顺序表并没有完全理解或者是知识点不够熟练,如果有问题,我很荣幸能在评论区和你一起讨论。


效果如下:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
如果觉得界面稍乱,可以通过增加换行、分隔线或清理屏幕解决。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【C++】C++中的list

一、介绍 官方给的 list的文档介绍 简单来说就是&#xff1a; list是可以在常数范围内在任意位置进行插入和删除的序列式容器&#xff0c;并且该容器可以前后双向迭代。list的底层是双向链表结构&#xff0c;双向链表中每个元素存储在互不相关的独立节点中&#xff0c;在节点中…

浅谈TCP(2):流量控制与拥塞控制

上文浅谈TCP&#xff08;1&#xff09;&#xff1a;状态机与重传机制介绍了TCP的状态机与重传机制。本文介绍流量控制&#xff08;Flow Control&#xff0c;简称流控&#xff09;与拥塞控制&#xff08;Congestion Control&#xff09;。TCP依此保障网络的QOS&#xff08;Quali…

【Leetcode每日一题】 递归 - 求根节点到叶节点数字之和(难度⭐⭐)(50)

1. 题目解析 题目链接&#xff1a;814. 二叉树剪枝 这个问题的理解其实相当简单&#xff0c;只需看一下示例&#xff0c;基本就能明白其含义了。 2.算法原理 想象一下&#xff0c;你有一堆层层叠叠的积木&#xff0c;你想从底部开始&#xff0c;把那些标记为0的积木拿走。如…

【QT+QGIS跨平台编译】056:【PDAL+Qt跨平台编译】(pdalcpp错误处理)

点击查看专栏目录 文章目录 一、报错信息:二、原因分析三、解决思路四、原版FileUtils.cpp五、修改后的FileUtils.cpp一、报错信息: ① exists is unavaiable: introduced in macOS 10.15 ② create_directory is unavaiable: introduced in macOS 10.15 ③ create_director…

BCLinux-for-Euler配置本地yum源

稍微吐槽一句…… 在这片土地上&#xff0c;国产化软件的大潮正在滚滚而来&#xff0c;虽然都不是真正意义上的国产化&#xff0c;但是至少壳是国产的~~~ 之前使用的Centos7的系统&#xff0c;现在都要求统一换成BCLinux-for-Euler。说实话换了之后不太适应&#xff0c;好多用习…

练习实践-TLS02-会话恢复的两种形式-Session ID/SessionTicket

参考来源&#xff1a; 书籍&#xff1a;深入浅出https-从原理到实战&#xff08;作者&#xff1a;虞卫东&#xff09; 抓包分析文件可下载&#xff0c;来自github上的作者上传资源 会话恢复机制的背景 当客户端和服务器端握手成功&#xff0c;建立了一个完整的 TLS 连接&…

刷题之Leetcode35题(超级详细)

35.搜索插入位置 力扣题目链接(opens new window)https://leetcode.cn/problems/search-insert-position/ 给定一个排序数组和一个目标值&#xff0c;在数组中找到目标值&#xff0c;并返回其索引。如果目标值不存在于数组中&#xff0c;返回它将会被按顺序插入的位置。 你可…

ChatGPT 与 OpenAI 的现代生成式 AI(下)

原文&#xff1a;Modern Generative AI with ChatGPT and OpenAI Models 译者&#xff1a;飞龙 协议&#xff1a;CC BY-NC-SA 4.0 七、通过 ChatGPT 掌握营销技巧 在本章中&#xff0c;我们将重点介绍营销人员如何利用 ChatGPT&#xff0c;在这一领域中查看 ChatGPT 的主要用例…

jvisualvm 使用教程

之前看过 jvisualvm&#xff0c;但是那个时候对 JVM 并不是很熟悉&#xff0c;后面看了下八股文&#xff0c;看了下 JVM 的相关知识之后&#xff0c;发现多了解点 JVM 的东西&#xff0c;对我们 CRUD 其实是有指导意义的&#xff0c;就比如我们通常会 new 一堆的没有用到的对象…

读所罗门的密码笔记10_寒武纪国家与城堡国家

1. DARPA 1.1. DARPA仍然是世界领先的尖端高科技研究推动者之一&#xff0c;资助研发人员开展各个领域的前沿研究&#xff0c;从自动驾驶汽车到植入式神经芯片&#xff0c;从复杂的系统分析&#xff08;比如分析气候变化&#xff09;到网络安全&#xff0c;无一…

31. 下一个排列 —— LeetCode (python) [PS: LeetCode 运行环境疑似出错]

# encoding utf-8 # 开发者&#xff1a;xxx # 开发时间&#xff1a; 20:26 # "Stay hungry&#xff0c;stay foolish."class Solution(object):def nextPermutation(self, nums):import itertoolsl len(nums)a tuple(nums)nums.sort()permutations_lst list(ite…

DDD 的四层领域模型是怎样的?包含哪些基础概念?

DDD的四层领域模型如下所示&#xff1a; 展现层&#xff1a;这一层负责向用户显示信息和解释用户命令&#xff0c;完成前端界面逻辑。并将用户请求传递给应用层。应用层&#xff1a;这一层是很薄的一层&#xff0c;负责协调领域层中的领域对象&#xff0c;组成具体应用场景。应…

JAVA JVM内存模型和GC分配和回收

Java 的JVM简介 JVM是&#xff08;Java Virtual Machine&#xff09;Java虚拟机的缩写。 JVM是一个虚构出来的计算机&#xff0c;是通过在实际的计算机上仿真模拟各种计算机功能来实现的。 ​ 在Java程序运行时&#xff0c;所有的.class类需要加载到JVM中才能执行代码逻辑。不…

Python环境下基于离散小波变换的信号降噪方法

Mallat创造了小波分析中的经典理论之一&#xff0c;即多分辨率分析的概念。后来&#xff0c;在Mallat与Meyer的共同努力之下&#xff0c;他们又在这一理论的基础上发明了离散小波变换的快速算法&#xff0c;这就是Mallat塔式算法&#xff0c;这种算法可以大量减少计算时间。在之…

解锁未来:大模型GPT的应用架构与创新实践

在人工智能的黄金时代&#xff0c;大模型如GPT&#xff08;Generative Pre-trained Transformer&#xff09;已成为技术创新和应用发展的前沿。它不仅重新定义了人机交互的方式&#xff0c;还在多个领域内展现出了巨大的应用潜力。本文将深入探讨大模型GPT的应用架构&#xff0…

深入解析:链游、DApp、公链、NFT与交易所开发的全景图

随着数字货币和区块链技术的迅速发展&#xff0c;链游开发、DApp开发、公链开发、NFT开发以及交易所开发等领域吸引了越来越多的关注。本文将以3000字的篇幅&#xff0c;对这些领域进行详细解析&#xff0c;探讨它们的意义、应用场景以及未来发展趋势。 链游开发&#xff08;Bl…

基于keepalived+gtid+双vip半同步主从复制的MySQL高性能集群

项目名称&#xff1a;基于keepalivedgtid双vip半同步主从复制的MySQL高性能集群 目录 项目名称&#xff1a;基于keepalivedgtid双vip半同步主从复制的MySQL高性能集群 项目规划图 1.配置4台MySQL服务器&#xff08;1台master&#xff0c;2台slave&#xff0c;1台backup&a…

光伏无人机:绿色能源与航空技术的融合创新

在可再生能源和无人机技术快速发展的背景下&#xff0c;光伏无人机作为一种新兴的绿色航空器&#xff0c;正逐渐展现出其独特的优势和广阔的应用前景。本文将深入探讨光伏无人机的原理、优势以及其在多个领域的应用&#xff0c;展望其未来的发展趋势。 一、光伏无人机的原理 光…

基于微信小程序的外卖管理系统的设计与实现(论文+源码)_kaic

摘 要 互联网发展至今&#xff0c;无论是其理论还是技术都已经成熟&#xff0c;而且它广泛参与在社会中的方方面面。它让信息都可以通过网络传播&#xff0c;搭配信息管理工具可以很好地为人们提供服务。针对高校教师成果信息管理混乱&#xff0c;出错率高&#xff0c;信息安全…

【VSCode】修改插件地址

不想放在原始C盘下面C:\Users\{用户}\.vscode\extensions为了后续存储空间考虑&#xff0c;想通过添加环境变量创建名为VSCODE_EXTENSIONS的环境变量&#xff0c;内容指向vs Code扩展所在目录即可 直接配置环境变量&#xff0c;不要在有空格的文件夹下面 变量名称&#xff1a;…