C语言实现通讯录--动态版

news2024/11/16 9:19:59

一、题目要求

实现一个通讯录,联系人的数量可多可少

二、解题思路

1.在静态版本的基础上改用动态的方法:
(1)默认能够存放三个人的信息
(2)不够的话,每次增加两个人的信息
2.其他功能不变

三、模块划分

建立三个文件:
test.c 用于测试通讯录的相关功能
contsct.c 通讯录的实现模块(用函数实现功能)
contact.h 声明(函数的声明)

四、代码实现

test.c

#define _CRT_SECURE_NO_WARNINGS 1
//C语言实现通讯录--动态版
/*
解题思路
1.在静态版本的基础上改用动态的方法:
(1)默认能够存放三个人的信息
(2)不够的话,每次增加两个人的信息
2.其他功能不变
*/
//菜单
#include "contact.h"
void menu() {
	printf("****************************************************\n");
	printf("**********1.add*********2.del***********************\n");
	printf("**********3.search******4.modify********************\n");
	printf("**********5.show********6.sort**********************\n");
	printf("**********0.exit************************************\n");
}
//通讯录功能用枚举方法列举出来,提高代码的可读性
/*
在主函数中的switch...case...语句中选择功能时,case 1,2,3...这样的选项不能让代码阅读者清晰地联想到各个数字代表实现什么功能
但是使用枚举,在case语句中用case 1代表增加联系人的时候就可写成case add
当枚举中的选项和菜单上的数字匹配上之后,在case语句中想实现哪个功能,写哪个选项就可以了
这样的话,case里面的选项和我们想实现的功能的意思就关联起来了
*/
enum Option {
	Exit,
	add,
	del,
	search,
	modify,
	show,
	sort
};
int main() {
	int input = 0;
	Contact con; //用结构体类型创建一个结构体变量
	//初始化通讯录
	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 show:
		{
			ShowContact(&con);
			break;
		}
		case sort:
		{
			SortContact(&con);
			break;
		}
		case Exit:
		{
			DestroyContact(&con);//销毁通讯录:整个通讯录都是动态开辟来的,退出时要释放掉
			printf("退出通讯录\n");
			break;
		}
		default:
		{
			printf("选择错误\n");
			break;
		}
		}
	} while (input);

	return 0;
}

contact.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "contact.h"

//初始化通讯录
void InitContact(Contact* pc) {
	pc->data = (PeoInfo*)malloc(DEFAULT_SZ * sizeof(PeoInfo));
	if (pc->data == NULL) {
		printf("通讯录初始化失败:%s\n", strerror(errno));
		return;
	}
	pc->sz = 0;
	pc->capacity = DEFAULT_SZ;
}
//检测容量的函数
//扩容成功,返回1
//扩容失败,返回0
void CheckCapacity(Contact* pc) {
	if (pc->sz == pc->capacity) { //有效信息个数等于容量的时候,需要扩容
		PeoInfo* ptr=(PeoInfo*)realloc(pc->data, (pc->capacity + INC_sz) * sizeof(PeoInfo));//将扩容后的地址交给新指针
		//判断扩容是否成功
		//扩容失败,打印错误信息,返回
		//扩容成功,将新指针交给pc->data维护,通讯录容量变动
		if (ptr == NULL) {
			printf("CheckCapacity:%s\n", strerror(errno));
			return 0;
		}
		else {
			pc->data = ptr;
			pc->capacity += INC_sz;
			printf("增容成功,当前容量:%d\n", pc->capacity);
			return 1;
		}
	}
	//如果通讯录未满,不进入上面的if语句,直接返回1
	return 1;
}

//增容
void AddContact(Contact* pc) {
	//对检测通讯录容量的函数的返回值进行判断
	if (0 == CheckCapacity) {
		printf("空间不够,扩容失败\n");
		return 0;
	}
	else {
		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");
	}
}

//销毁通讯录
void DestroyContact(Contact* pc) {
	free(pc->data);  
	pc->data = NULL;
	pc->capacity = 0;
	pc->sz = 0;
	printf("释放内存\n");
}

//显示联系人信息
void ShowContact(Contact* pc) {
	int i = 0;
	//打印标题
	//在%后面加上负号表示左对齐的方式,在%s的s前面加上数字可以限制打印出来最多几个字节
	printf("%-10s %-4s %-5s %-12s %-30s\n", "姓名", "年龄", "性别", "电话", "地址");
	for (i = 0; i < pc->sz; i++) {
		printf("%-10s %-4d %-5s %-12s %-30s\n", pc->data[i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].tele, pc->data[i].addr);
	}
}
//实际上,删查改联系人都需要先在通讯录中查找
//为了减少代码的冗余度,可以封装一个查找的函数FindByName
//封装的这个函数前面加static,这个函数只能在自己所在的.c文件中使用,其他的源文件看不见该函数,对它加以保护
//根据名字在通讯录中查找下标的函数
static int FindByName(const 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;
	//找不到直接返回-1
	/*
	不要写成
	if(i==pc->sz){
		return -1;
	}
	因为写成这样,if进去,条件成立才有返回,不成立无返回
	编译器在编译时发现这样的代码考虑不周全,有些情况是存在返回值的,就会发出警告
	所以,严谨的情况下,直接返回既清晰又严谨
	*/
}


//删除联系人函数
void DelContact(Contact* pc) {
	if (pc->sz == 0) {
		printf("通讯录为空,无法删除\n");
		return;
	}
	//1.根据要删除的人的名字找到在通讯录中的下标
	char name[MAX_NAME] = { 0 };
	printf("请输入要删除的人的名字:");
	scanf("%s", name);
	int pos = FindByName(pc, name);
	if (pos == -1) {
		printf("要删除的人不存在\n");
		return;
	}
	//2.删除pos位置上的数据
	int i = 0;
	for (i = pos; i < pc->sz; i++) {
		pc->data[i] = pc->data[i + 1];//从pos下标处开始覆盖
	}
	pc->sz--;
	printf("删除成功\n");
}
//查找联系人 
void SearchContact(const Contact* pc) {//查找不需要修改通讯录,使用const加以保护,防止被修改
	char name[MAX_NAME] = { 0 };
	printf("请输入要查找的人的名字:");
	scanf("%s", name);
	int pos = FindByName(pc, name);
	if (pos == -1) {
		printf("要查找的人不存在\n");
		return;
	}
	//找到的话直接打印这个联系人的信息
	printf("%-10s %-4s %-5s %-12s %-30s\n", "姓名", "年龄", "性别", "电话", "地址");
	printf("%-10s %-4d %-5s %-12s %-30s\n", pc->data[pos].name, pc->data[pos].age, pc->data[pos].sex, pc->data[pos].tele, pc->data[pos].addr);
}
//修改联系人
void ModifyContact(Contact* pc) {
	char name[MAX_NAME] = { 0 };
	printf("请输入要修改的人的名字:");
	scanf("%s", name);
	int pos = FindByName(pc, name);
	if (pos == -1) {
		printf("要修改的人不存在\n");
		return;
	}
	//修改:把要修改人下标为pos的信息全都再录入一遍
	printf("请输入名字:");
	scanf("%s", pc->data[pos].name);
	printf("请输入年龄:");
	scanf("%d", &(pc->data[pos].age));
	printf("请输入性别:");
	scanf("%s", pc->data[pos].sex);
	printf("请输入电话:");
	scanf("%s", pc->data[pos].tele);
	printf("请输入地址:");
	scanf("%s", pc->data[pos].addr);

	printf("修改成功\n");
}
//排序联系人
//使用qsort进行排序,要自定义一个排序方法
int cmp_by_name(const void* e1, const void* e2) {//e1,e2指针各自指向一个人的信息
	return strcmp(((PeoInfo*)e1)->name, ((PeoInfo*)e2)->name);
}
void SortContact(Contact* pc) {
	//按照名字来排序
	qsort(pc->data, pc->sz, sizeof(PeoInfo), cmp_by_name);
	printf("排序成功\n");
	//调用显示联系人函数ShowContact,自动打印一下排序后的结果
	ShowContact(pc);
}

contact.h

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

#define MAX 100
#define MAX_NAME 20
#define MAX_SEX 5
#define MAX_TELE 12
#define MAX_ADDR 30

#define DEFAULT_SZ 3 //默认是3个
#define INC_sz 2  //扩容每次增加2个

//结构体存放每个联系人的信息
typedef struct PeoInfo { //typedef:给已定义的变量类型起个别名,这里的作用是给struct Peoinfo起个别名PeoInfo
	char name[MAX_NAME];
	int age;
	char sex[MAX_SEX];
	char tele[MAX_TELE];
	char addr[MAX_ADDR];
}PeoInfo;
//结构体存放通讯录
typedef struct Contact {
	PeoInfo *data; //data指向存放数据的空间
	int sz;        //sz记录通讯录中的有效信息个数
	int capacity; //通讯录当前的容量
}Contact, * pContact;//*pContact意思是将结构体指针struct Contact*重命名为pContact

//初始化通讯录--传址
void InitContact(Contact* pc);
//销毁通讯录
void DestroyContact(Contact* pc);
//增加指定联系人
void AddContact(Contact* pc);
//删除指定联系人
void DelContact(Contact* pc);
/*
传址可以写成void ...Contact(pContact pc);
这里通过pContact定义出来的指针也是结构体指针
*/
//显示联系人信息
void ShowContact(Contact* pc);
//查找联系人 
void SearchContact(const Contact* pc);
//修改联系人
void ModifyContact(Contact* pc);
//排序联系人
void SortContact(Contact* pc);

五、运行结果

在这里插入图片描述

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

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

相关文章

学习自动化测试该怎么学?6个步骤轻松拿捏

自动化测试作为脱离手工测试的基本核心内容&#xff0c;其重要性不言而喻了&#xff0c;而且我们来看近期大厂的一些招聘信息显示&#xff0c;基本上自动化测试是必备前提&#xff0c;没有这个基本就不用谈后面的问题了&#xff0c;下面我们通过联想集团的一个软件测试工程师的…

【C#】async和await 续

前言 在文章《async和await》中&#xff0c;我们观察到了一下客观的规律&#xff0c;但是没有讲到本质&#xff0c;而且还遗留了一个问题: 这篇文章中&#xff0c;我们继续看看这个问题如何解决! 我们再看看之前写的代码&#xff1a; static public void TestWait2() {var t…

VR党建主题数字互动虚拟展馆软件开启党建铸魂育人新篇章

当今时代新媒体技术的发展对大学生的学习、生活等产生着深远的影响。高校作为党建育人的重要场所&#xff0c;充分借助VR技术的强大优势&#xff0c;合理运用到育人工作中&#xff0c;能够不断丰富教育内容。VR智慧党建展厅展馆结合VR技术营造的虚拟现实空间&#xff0c;将党的…

layui手机端上传文件时返回404 Not Found的解决方案(client_body_temp权限设置)

关于 1.client_body_temp的作用 client_body_temp是一个指令指定保存客户端请求体临时文件的目录路径&#xff0c;以及是否进行缓存的配置指令。 在Web服务器中&#xff0c;当客户端向服务器发送请求时&#xff0c;请求体中包含了请求的主体部分&#xff0c;比如表单数据、上…

基于flask徐州市天气信息可视化分析系统【纯干货分享,附源码04600】

摘 要 信息化社会内需要与之针对性的信息获取途径&#xff0c;但是途径的扩展基本上为人们所努力的方向&#xff0c;由于站在的角度存在偏差&#xff0c;人们经常能够获得不同类型信息&#xff0c;这也是技术最为难以攻克的课题。针对天气信息等问题&#xff0c;对天气信息进行…

【网络通信】一文读懂TCP/IP基础,IP、端口、网关、web、超媒体

TCP/IP贯穿在我们学习计算机的生涯中&#xff0c;但TCP/IP终究是个什么玩意儿&#xff1f;在了解他之前我们先看一段历史&#xff1a; 在网络发展初期&#xff0c;许多研究机构、计算机厂商和公司都开始大力发展计算机网络。自ARPANET出现之后&#xff0c;许多商品化的网络系统…

实现二叉排序树

一&#xff1a;二叉树和二叉搜索树 二叉树中的节点最多只能有两个子节点&#xff1a;一个是左侧子节点&#xff0c;另一个是右侧子节点。这个定义有助于我们写出更高效地在树中插入、查找和删除节点的算法&#xff0c;二叉树在计算机科学中的应用非常广泛。 **二叉搜索树&…

Consul的容器服务更新与发现

Consul的容器服务更新与发现 一&#xff1a;Docker consul的容器服务更新与发现&#xff08;1&#xff09;什么是服务注册与发现&#xff08;2&#xff09;什么是consulconsul提供的一些关键特性&#xff1a; 二&#xff1a;consul 部署consul服务器1. 建立 Consul 服务2. 查看…

一文带你全面理解向量数据库

近些年来&#xff0c;向量数据库引起业界的广泛关注&#xff0c;一个相关事实是许多向量数据库初创公司在短期内就筹集到数百万美元的资金。 你很可能已经听说过向量数据库&#xff0c;但也许直到现在才真正关心向量数据库——至少&#xff0c;我想这就是你现在阅读本文的原因…

美国过境签证的办理流程和注意事项

美国过境签证是一种临时签证&#xff0c;允许你在前往其他国家的途中经过美国。这对于很多旅行者来说是一个便捷的选择&#xff0c;但在申请和办理过程中也需要注意一些要点。 首先&#xff0c;申请美国过境签证需要前往美国驻中国大使馆或领事馆递交申请。以下是办理美国过境签…

四磺酸酞菁锌,61586-86-5,Zn(II) Phthalocyanine tetrasulfonic acid,广泛用于染色

资料编辑|陕西新研博美生物科技有限公司小编MISSwu​ 四磺酸酞菁锌试剂 | 基础知识概述&#xff08;部分&#xff09;: 中文名称&#xff1a;四磺酸酞菁锌 英文名称&#xff1a;Zn(II) Phthalocyanine tetrasulfonic acid CAS号&#xff1a;61586-86-5 分子式&#xff1a;C32H…

图数据库实践 - 如何将图数据库应用于网络安全

网络化办公为企业创造便捷的同时&#xff0c;也带来了数据泄露的威胁。根据IBM Security最新发布的年度《数据泄露成本报告》显示&#xff0c;2023全球数据泄露的平均成本达到445万美元&#xff0c;创该报告有史以来以来最高记录&#xff0c;也较过去3年均值增长了15%。同一时期…

2.3 HLSL常用函数

一、函数介绍 函数图像参考网站&#xff1a;Graphtoy 1.基本数学运算 函数 含义 示例图 min(a,b) 返回a、b中较小的数值 mul(a,b) 两数相乘用于矩阵计算 max(a,b) 返回a、b中较大的数值 abs(a) 返回a的绝对值 round(x) 返回与x最近的整数 sqrt(x) 返回x的…

QT【day4】

chat_QT服务器端&#xff1a; //.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include<QTcpServer> //服务器类 #include<QTcpSocket> //客户端类 #include<QMessageBox> //对话框类 #include<QList> //链表容器 #inc…

美团/华为/字节/滴滴等大厂真实面试面经

一、美团测试开发面经 一面&#xff0c;1小时 自我介绍 自已觉得最好的项目&#xff1f;主要做了什么&#xff1f;遇到的最大困难&#xff1f; 浏览器输入网址后发生了什么&#xff1f; 三次握手和四次挥手 http和https的区别 https的加密过程 知道哪些排序算法 快排的…

现在入行软测=49年入国军?三句话,让面试官再掏2K

还有一个月就步入金九银十&#xff0c;很多软测人吐槽因为疫情&#xff0c;公司都在裁员&#xff0c;别说跳槽涨薪&#xff0c;能保住现在的工作就不错了。 但也有那么一批人&#xff0c;凭借自己口才与实力拿到年薪近50W的offer。面试是初见1小时就要相互了解优缺点的过程&am…

工作10年的老码农手把手教你如何3分钟看懂IT技术管理!速收藏!

老陈是谁&#xff1f; 一个码龄十年的老码农&#xff0c;从刚毕业开始被代码折磨的死去活来&#xff0c;到公司里“被迫”成为多线技术栈的“工程师”&#xff0c;这几年又从IT技术转向做IT管理。 基本可以说从一个坑跳到了另一个坑&#xff0c;虽然坑多水深&#xff0c;但是…

【Golang】Golang进阶系列教程--Golang中文件目录操作的实现

文章目录 一、文件二、文件目录三、文件目录操作3.1、读取文件3.1.1、方法一 (file.Read())3.1.2、方法二 (bufio读取文件)3.1.3、方法三 (ioutil 读取方法) 3.2、写入文件3.2.1、方法一3.2.2、方法二3.2.3、方法三 (ioutil写入文件) 3.3、复制文件3.3.1、方法一3.3.2、方法二 …

AI人工智能未来在哪里?2023年新兴产业人工智能有哪些就业前景?

AI人工智能未来在哪里&#xff1f;2023年新兴产业人工智能有哪些就业前景&#xff1f; 随着科技的不断发展&#xff0c;人工智能技术也在不断地进步。在数字化时代&#xff0c;人工智能技术已经渗透到了我们生活的各个方面。2023年为止中国产业80%已经实现半自动化&#xff0c;…

element 级联 父传子

html代码例子 父组件 <el-cascaderstyle"width: 100%"change"unitIdChange":options"unitOptions"filterablev-model"formInline.unitId":props"unitProps"/></el-form-item>//改变级联传值到这个组件里面<r…