C语言——通讯录的实现

news2024/12/25 9:01:03

      前面的文章介绍了C语言中的 指针、自定义类型等模块,这篇文章将通过编写实现通讯录的代码对这些模块进行应用和进一步加深理解:

目录

1. 通讯录主要功能设计:

2.  通讯录的实现——主页面:

 3. 通讯录的实现——保存个人信息:

4. 通讯录功能实现:

4.1 添加个人信息:

4.2 查看个人信息:

4.3 删除个人信息:

4.4 查找指定联系人:

4.5 修改联系人的个人信息:

4.6 按照名字排序信息:


1. 通讯录主要功能设计:

    首先,设置想让通讯录达成的功能,例如:

2.  通讯录的实现——主页面:

在实现通讯录各项具体的功能之前,首先应给出一个页面,便于使用者选择自己需要的功能,代码如下:

void menu()
{
	printf("*************************\n");
	printf("*****     0.exit    *****\n");//退出
	printf("*****     1.add     *****\n");//添加联系人信息
	printf("*****     2.del     *****\n");//删除联系人信息
	printf("*****     3.search  *****\n");//查找联系人信息
	printf("*****     4.modify  *****\n");//改变联系人信息
	printf("*****     5.show    *****\n");//展示联系人信息
	printf("*****     6.sort    *****\n");//对联系人进行排序
}

void test()
{
	int input = 0;
	do
	{
		menu();
		printf("请选择:>");
		scanf("%d ", &input);
		switch (input)
		{
		case 1:
		    break;
		case 2:
			break;
		case 3:
			break;
		case 4:
			break;
		case 5:
			break;
		case 6:
			break;
		case 0:
			break;
		default:
			break;

		}
	} while (input);
}

但是,在switch选择语句中,使用不同的数字来划分不同的情况,未免有些太不直观,所以,为了让功能更加直观,可以按照菜单上不同功能对应的数字,用枚举解决这一问题:

enum OPTION
{
    exit,
    add,
    del,
    search,
    modify,
    show,
    sort
};

此时,主页面的代码可以根据枚举进行修改,来变得更直观:

void test()
{
	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:
			break;
		default:
			break;
		}
	} while (input);
}

运行效果如下:

 3. 通讯录的实现——保存个人信息:

对于上面所列出的信息中,它们的数据类型各不相同,对于不同类型的信息的整合,可以采用结构体的方式进行实现:

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

上面给出的结构体中,包含了功能设计时,所设计的保存联系人姓名,年龄,性别,电话,住址这几个信息。

对于上面用于存储个人信息的数组的大小,也可以采取类似上面相同的方法,用#define进行定义。即:

#define NAME_NUM 20
#define SEX_NUM  5
#define TELE_NUM 15
#define ADD_NUM  20

typedef struct PeoInfo//用于保存个人信息的结构体
{
    char name[NAME_NUM];
    int age;
    char sex[SEX_NUM];
    char tele[TELE_NUM];
    char add[ADD_NUM];
}PeoInfo;

上面的结构体只能存放一个人的信息,为了可以存放多人信息,可以通过创建一个结构体数组的方法来实现。并且,为了随时更改存储人数的数量,可以采用define将数量改为一个可以随时进行更改的常变量:

#define MAX_NUM 100;
PeoInfo arr[MAX_NUM];

在设置了存储最大人数后,需要将装有个人信息的结构体与编号联系起来,所以,可以再创建一个结构体,用于保存存储个人信息的结构体数组和一个用于计数的变量:

 typedef struct contact
{
    PeoInfo arr[MAX_NUM];
    int sz = 0;
}contact;

 再解决了上面的问题后,需要对通讯录进行初始化的工作,可以通过memset函数对通讯录进行初始化,并将这一过程封装在一个初始化函数中:

4. 通讯录功能实现:

4.1 添加个人信息:

 在通讯录中添加个人信息时,需要注意,如果通讯录中用于计数的变量sz达到了所设置存储数量的最大值,应给出存储已满的信息,当sz没有到达存储数据的最大值时,可以继续存储数据:

这里,封装一个添加个人信息的函数,并将函数设置在主页面switch语句中添加的部分:

void ADDcontact(contact* pc)
{
	if (pc->sz == 100)
	{
		printf("通讯录已满");
		return;
	}
	printf("请输入名字:");
	scanf("%s", (pc->arr[pc->sz]));
	printf("请输入年龄:");
	scanf("%d", &(pc->arr[pc->sz]));
	printf("请输入性别:");
	scanf("%s", (pc->arr[pc->sz]));
	printf("请输入电话号码:");
	scanf("%s", (pc->arr[pc->sz]));
	printf("请输入地址:");
	scanf("%s", &(pc->arr[pc->sz]));
	pc->sz++;
	printf("添加联系人成功");
}

4.2 查看个人信息:

上面输入了个人信息后,这些信息就被保存在结构体中,想要查看个人信息,就需要将这些信息打印出来:

void ShowContact(contact* pc)
{
	int i = 0;
	printf("%-20s\t%-4s\t%-5s\t%-20s\t%-20s\t\n",
		"姓名",
		"年龄",
		"性别",
		"电话号码",
		"家庭住址");
	for (i = 0; i < pc->sz; i++)
	{
		printf("%-20s\t%-4d\t%-5s\t%-20s\t%-20s\t",
			pc->arr[i].name,
			pc->arr[i].age,
			pc->arr[i].sex,
			pc->arr[i].tele,
			pc->arr[i].add);
		printf("\n");
	}
}

4.3 删除个人信息:

想要删除某个人的个人信息,第一步就是要先找到这个人的个人信息,所以,可以先创建一个字符数组,用于输入某个想要删除的人的名字,下面再与结构体中已经有的信息中的姓名,用strcmp函数进行比对,如果strcmp函数的返回值是0,则记录下此时信息在结构体中的编号:

void DelContact(contact* pc)
{
	if (pc->sz == 0)
	{
		printf("通讯录为空,无法删除");
	}
	//先找到想要删除的人所在通讯录的编号:
	char name1[NAME_NUM] = { 0 };
	printf("请输入想要删除的人的名字:");
	scanf("%s", name1);
	int i = 0;
	int del = 0;
	for (i = 0; i < pc->sz; i++)
	{
		if (strcmp(name1, pc->arr[i].name) == 0)
		{
			del = i;
			break;
		}
	

}

在找到了想要删除的信息所在的位置后,第二步就是删除相关的信息,总体代码如下:

void DelContact(contact* pc)
{
	if (pc->sz == 0)
	{
		printf("通讯录为空,无法删除");
	}
	//先找到想要删除的人所在通讯录的编号:
	char name1[NAME_NUM] = { 0 };
	printf("请输入想要删除的人的名字:");
	scanf("%s", name1);
	int i = 0;
	int del = 0;
	int flag = 0;
	for (i = 0; i < pc->sz; i++)
	{
		if (strcmp(name1, pc->arr[i].name) == 0)
		{
			del = i;
			flag = 1;
			break;
		}
		if (flag == 0)
		{
			printf("不存在用户,删除失败");
			return;
		}
	}
	//删除联系人的信息
	for (i = del; i < pc->sz - 1; i++)
	{
		pc->arr[i] = pc->arr[i + 1];
	}
	pc->sz--;
	printf("成功删除联系人\n");

}

在寻找信息时,记录了想要删除的人的信息所在结构体中的位置。

对于整个删除过程,应该是首先添加个人信息,如果其中信息添加错了才会进行删除,假设添加信息阶段一共添加了20人的信息,想要删除的人的信息在结构体数组中的编号为8。

此时,在删除信息的代码中,应该从编号为8进行遍历,并且用编号为9的信息覆盖编号为8的信息,然后,循环继续进行,让编号为10的信息覆盖编号为9的信息,所以,按照这个步骤,最后应该是编号为19的信息覆盖编号为18的信息,也就是循环11次。所以i的范围应该满足:i <= sz-1(19)并且 i >=del。

当覆盖完毕后,此时可以理解为,从编号为del开始的范围所对应的内容都集体向前移动一位,所以,末尾即sz对应的内容不能被查询,所以sz--

在删除某个个人信息时,分了两步,第一步时先通过输入想要删除的人的姓名,找到他在结构体中所对应的编号,但是,不光对于删除信息,在下面的查找信息,改变信息都需要找到这个编号,所以,为了简化代码,应该将寻找个人信息对应的编号这一步骤封装成一个函数。

int del = Findbyname(pc, name1);
	if (del == -1)
	{
		printf("用户不存在");
	}

经过函数封装后,代码为:

void DelContact(contact* pc)
{
	if (pc->sz == 0)
	{
		printf("通讯录为空,无法删除");
	}
	//先找到想要删除的人所在通讯录的编号:
	char name1[NAME_NUM] = { 0 };
	printf("请输入想要删除的人的名字:");
	scanf("%s", name1);
	int i = 0;

	int del = Findbyname(pc, name1);
	if (del == -1)
	{
		printf("用户不存在\n");
		return;
	}
	//删除联系人的信息
	for (i = del; i < pc->sz - 1; i++)
	{
		pc->arr[i] = pc->arr[i + 1];
	}
	pc->sz--;
	printf("成功删除联系人\n");

}

封装的函数:

int Findbyname(contact* pc, char *name1)
{
	int i = 0;
	int del = 0;
	for (i = 0; i < pc->sz; i++)
	{
		if (strcmp(name1, pc->arr[i].name) == 0)
		{
			return i;
		}
	}
	return -1;
}

4.4 查找指定联系人:

步骤与删除某人的个人信息,类似,先找到,再打印出来即可:

void SearchContact(const contact* pc)
{
	char name2[20];
	scanf("%s", &name2);
	int pos = Findbyname(pc, name2);
	if (pos == 0)
	{
		printf("找不到相关信息\n");
	}
	else
	{
		int i = 0;
		printf("%-20s\t%-4s\t%-5s\t%-20s\t%-20s\t\n",
			"姓名",
			"年龄",
			"性别",
			"电话号码",
			"家庭住址");

		printf("%-20s\t%-4d\t%-5s\t%-20s\t%-20s\t",
			pc->arr[pos].name,
			pc->arr[pos].age,
			pc->arr[pos].sex,
			pc->arr[pos].tele,
			pc->arr[pos].add);
	}
}

4.5 修改联系人的个人信息:

与删除相同,首先要找到需要修改的人在结构体中的编号,再进行重新输入即可:

void ModifyContact(contact* pc)
{
	char name3[20];
	printf("输入想要修改的信息的人名:");
	scanf("%s", name3);
	int ret = Findbyname(pc, name3);
	if (ret == 0)
	{
		printf("不存在此人,修改失败");
		return;
	}
	else
	{
		printf("请输入姓名:");
		scanf("%s", pc->arr[ret].name);
		printf("请输入年龄:");
		scanf("%s", &(pc->arr[ret].age));
		printf("请输入性别:");
		scanf("%s", pc->arr[ret].sex);
		printf("请输入电话:");
		scanf("%s", pc->arr[ret].tele);
		printf("请输入住址:");
		scanf("%s", pc->arr[ret].add);
		printf("修改成功\n");
	}
}

4.6 按照名字排序信息:

对于不同种类的信息的排序,就需要用到之前介绍过的函数qsort,具体如何使用qsort可以在(qsort对不同数据类型的排序、及模拟qsort函数实现_爱写代码的粉毛护理的博客-CSDN博客)进行理解。

int compare_stu_name(const void* str1, const void* str2)
{
	return(strcmp(((PeoInfo*)str1)->name, ((PeoInfo*)str2)->name));
}

//根据名字排序:
void SortContact(contact* pc)
{
	int sz1 = sizeof(pc->arr) / sizeof(pc->arr[0]);
	qsort(pc->arr, sz1, sizeof(pc->arr[0]), compare_stu_name);
	int i = 0;
	for (i = 0; i < pc->sz;)
	{
		if (pc->arr[i].age == 0)
		{
			i++;
		}
		else
		{
			printf("%-20s\t%-4s\t%-5s\t%-20s\t%-20s\t\n",
				"姓名",
				"年龄",
				"性别",
				"电话号码",
				"家庭住址");

			printf("%-20s\t%-4d\t%-5s\t%-20s\t%-20s\t",
				pc->arr[i].name,
				pc->arr[i].age,
				pc->arr[i].sex,
				pc->arr[i].tele,
				pc->arr[i].add);
			printf("\n");
			i++;
		}
	}
}

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

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

相关文章

CS 144 Lab Three-- the TCP sender

CS 144 Lab Three -- the TCP sender TCPSender 功能如何检测丢包TCPSender 要求TCPSender 状态转换图TCPSender 实现测试 对应课程视频: 【计算机网络】 斯坦福大学CS144课程 Lab Three 对应的PDF: Lab Checkpoint 3: the TCP sender TCPSender 功能 TCP Sender 负责将数据以…

27 Deep Belief Network

文章目录 27 Deep Belief Network——深度信念网络27.1 DBN是什么&#xff1f;27.2 为什么要使用DBN27.2.1 DBN的思想是怎么来的&#xff1f;27.2.2 RBM的叠加可以提高ELBO 27.3 训练方式 27 Deep Belief Network——深度信念网络 27.1 DBN是什么&#xff1f; DBN(Deep Belie…

【机器学习】分类算法 - KNN算法(K-近邻算法)KNeighborsClassifier

「作者主页」&#xff1a;士别三日wyx 「作者简介」&#xff1a;CSDN top100、阿里云博客专家、华为云享专家、网络安全领域优质创作者 「推荐专栏」&#xff1a;零基础快速入门人工智能《机器学习入门到精通》 K-近邻算法 1、什么是K-近邻算法&#xff1f;2、K-近邻算法API3、…

FastDFS与Springboot集成

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

139、仿真-基于51单片机一氧化碳(CO)气体检测仿真设计(程序+Proteus仿真+配套资料等)

毕设帮助、开题指导、技术解答(有偿)见文未 目录 一、设计功能 二、Proteus仿真图​编辑 三、程序源码 资料包括&#xff1a; 需要完整的资料可以点击下面的名片加下我&#xff0c;找我要资源压缩包的百度网盘下载地址及提取码。 方案选择 单片机的选择 方案一&#xff1…

【K8S系列】深入解析k8s网络插件—Calico

序言 做一件事并不难&#xff0c;难的是在于坚持。坚持一下也不难&#xff0c;难的是坚持到底。 文章标记颜色说明&#xff1a; 黄色&#xff1a;重要标题红色&#xff1a;用来标记结论绿色&#xff1a;用来标记论点蓝色&#xff1a;用来标记论点 Kubernetes (k8s) 是一个容器编…

视频理解多模态大模型(大模型基础、微调、视频理解基础)

转眼就要博0了&#xff0c;导师开始让我看视频理解多模态方向的内容&#xff0c;重新一遍打基础吧&#xff0c;从Python&#xff0c;到NLP&#xff0c;再到视频理解&#xff0c;最后加上凸优化&#xff0c;一步一步来&#xff0c;疯学一个暑假。写这个博客作为我的笔记以及好文…

代码随想录算法训练营第55天|392 115

392 双指针法很简单 class Solution { public:bool isSubsequence(string s, string t) {int i0;for (int j0; j<t.size() && i<s.size(); j) {if (t[j]s[i]) {i;}}return is.size();} }; 用动态规划来写的话 逻辑其实跟1143 1035是一样的 最后返回看dp[s.size…

Vue element el-input输入框 实现 ’空格+enter’组合键:换行,enter:发送,使用keydown和keyup键盘事件来实现

需求 输入框 &#xff0c;输入内容后 &#xff0c;按enter空格键 换行&#xff0c;按enter键 发送调取接口 思路 jquery的也分为三个过程&#xff0c;在事件名称上有所不同 1、某个键盘的键被松开&#xff1a;keyup 2、某个键被按下&#xff1a;keydown 3、某个键盘的键被按…

基于查找表(lookup table,LUT)方法反演植被参数

LUT指显示查找表&#xff08;Look-Up-Table)&#xff0c;本质上就是一个RAM。它把数据事先写入RAM后&#xff0c;每当输入一个信号就等于输入一个地址进行查表&#xff0c;找出地址对应的内容&#xff0c;然后输出。 LUT的应用范围比较广泛&#xff0c;例如&#xff1a;LUT(Lo…

机器学习:Self-supervised Learning for Speech and image

review : self-supervised learning for text Self-supervised learning for speech 使用Speech版本的bert能比较好的作用于语音任务上&#xff0c;如果没有self-supervised的话&#xff0c;别的模型可能需要上万小时的数据。 Superb ytb课程&#xff1a;MpsVE60iRLM工具&…

vulnhub打靶--lampiao

目录 vulnhub--lampiao1.扫描主机端口&#xff0c;发现1898端口部署web2.打开robots.txt发现CHANGELOG.txt文件3.发现drupal更新日志&#xff0c;drupal这个版本有公开exp。利用msf打下4.执行uname -a 或者上传漏洞suggest脚本&#xff0c;可以发现有脏牛提权5.上传脚本到目标&…

2023年7月19日,锁升级,网络编程

锁升级 锁的四种状态&#xff1a;无锁、偏向锁、轻量级锁、重量级锁&#xff08;JDK1.6&#xff09; 无锁&#xff1a;操作数据时不会上锁 偏向锁&#xff1a;会偏向于第一个访问锁的线程&#xff0c; 如果在运行过程中&#xff0c;只有一个线程访问加锁的资源&#xff0c;不存…

JavaWeb+Vue分离项目实现增删改查

文章目录 前言数据库后端代码util 代码listener 代码filter 代码po 代码dao 层增删改查代码service 层增删改查代码controller 层增删改查代码 前端代码查询操作删除功能增加功能修改方法路由传参修改会话存储修改 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&…

Java037——多线程

当涉及到计算机操作系统中的并发执行时&#xff0c;进程和线程是两个核心概念。 一、程序(program) 程序(program)是为完成特定任务、用某种语言编写的一组指令的集合。即指一 段静态的代码&#xff0c;静态对象。 二、进程&#xff08;Process&#xff09; 进程&#xff0…

MD5数据加密方法

什么场景需要使用数据加密呢&#xff1f;比如秘密数据传输、用户密码加密存储等等 数据传输可使用密钥对的方式进行加密解密&#xff0c;使用签名方式验证数据是否可靠&#xff0c;而密码加密存储可使用MD5等一些算法对数据进行单向加密 一、MD5单向加密 1、百度说法&#x…

【基础统计学】带重叠差分置信区间的检验

一、说明 对于统计模式识别&#xff0c;需要从基本的检验入手进行学习掌握&#xff0c;本篇是对统计中存在问题的探讨&#xff1a;如果两个分布有重叠该怎么做。具体的统计学原理&#xff0c;将在本人专栏中系统阐述。 二、几个重要概念 2.1 什么是假设检验 假设检验是一种统计…

第二节 C++ 数据类型

文章目录 1. 概述1.1 数据类型的重要作用 (了解) 2. 数据类型2.1 什么是进制 ?2.1.1 存储单位 2.2 整数类型2.2.1 整数类型使用2.2.2 超出范围2.2.3 关键字 sizeof 2.3 实型(浮点型)2.3.1 setprecision()函数2.3.2 科学计数 (了解即可) 2.4 字符型2.4.1 字符型定义2.4.2 ASCII…

树-用Java托举

再讲完前面几个数据结构后&#xff0c;下面&#xff0c;我们开始对树进行一个讲解分析 树 引言 树是一种重要的数据结构&#xff0c;在计算机科学中有着广泛的应用。树是由节点和边组 成的非线性数据结构&#xff0c;具有层次结构和递归定义的特点。每个节点可以有多个子 节点…

【英杰送书第三期】Spring 解决依赖版本不一致报错 | 文末送书

Yan-英杰的主 悟已往之不谏 知来者之可追 C程序员&#xff0c;2024届电子信息研究生 目录 问题描述 报错信息如下 报错描述 解决方法 总结 【粉丝福利】 【文末送书】 目录&#xff1a; 本书特色&#xff1a; 问题描述 报错信息如下 Description:An attempt…