C语言 通讯录管理 完整代码

news2024/12/23 9:57:56

这份代码,是我从网上找的。目前是能运行。我正在读。有些不懂的地方,等下再记录下来。
有些地方的命名,还需要重新写一下。

比如:

PersonInfo* info = &address_book->all_address[address_book->size];

应该改为:

PersonInfo* info = &(address_book->all_address[address_book->size]);

就是加上一个括号。更清晰一些。

效果图:

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

#define Max_SIZE 50 //定义通讯录的大小

typedef struct PersonInfo {
	char name[100];
	char phone[100];
}PersonInfo;

typedef struct AddressBook {
	PersonInfo all_address[Max_SIZE];
	int size;
}AddressBook;
//size 的含义是:
//数组 all_address 下标范围在 [0,size) 内的元素是有意义的
//                            [size, 200) 是我们没有用到的

//初始化
void init(AddressBook* address_book) {
	
	address_book->size = 0;
	//尽量少用 magic number(不明含义的数字)
	for (int i = 0; i < Max_SIZE; i++) {
		strcpy(address_book->all_address->name, " ");
		strcpy(address_book->all_address->phone, " ");
	}

}

int Menu(void) {
	
	printf("======================\n");
	printf("***     0.退出     ***\n");
	printf("***  1.新增联系人  ***\n");
	printf("***  2.删除联系人  ***\n");
	printf("***  3.查找联系人  ***\n");
	printf("***  4.修改联系人  ***\n");
	printf("***  5.打印联系人  ***\n");
	printf("***  6.清除联系人  ***\n");
	printf("***  7.排序联系人  ***\n");
	printf("======================\n");

	printf("请输入你的选择:");
	int choice;
	scanf("%d", &choice);

	return choice;
}

void AddPersonInfo(AddressBook* address_book) {
	
	printf("新增联系人\n");

	if (address_book->size >= Max_SIZE) {
		printf("通讯录已满,请先清除!\n");
		return;
		//虽然函数类型是 void 但是也是可以用 return 滴
	}
	PersonInfo* info = &address_book->all_address[address_book->size];
	
	printf("请输入联系人姓名:");
	scanf("%s", info->name);
	printf("请输入联系人电话:");
	scanf("%s", info->phone);

	address_book->size++;
}

void DelPersonInfo(AddressBook* address_book) {
	
	//删除的方法很多,可以根据姓名,电话,序号等等来删除,
	//这里我们就用我个人比较常用的 搜索名字的删除方法

	char search_name[100] = { 0 };

	printf("删除联系人\n");
	printf("请输入联系人姓名:");
	scanf("%s", search_name);

	int name_exist = FindName(address_book, search_name);
	
	//这里注意 FindName 返回值设定,要被删除的元素下标可能是 0,这种情况下会返回 0 
	if (name_exist == -1) {
		printf("该联系人不存在!\n");
		return;
	}

	//删除了相同姓名的第一个后,继续寻找改名字,如果找到了,重复上面的操作,如果没找到,退出循环
	//相同的姓名的情况比较复杂,在修改,查找,排序等等场景都会带来麻烦,
	//而且平时你的通讯录中难道会将两个相同姓名的人的备注写成一样的吗?
	//所以,我仅仅在删除功能中实现一种针对相同姓名的情况的设计思路,后面的其他功能默认没有重复姓名的情况。
	while (name_exist != -1) {
		
		//将 all_address 数组的最后一个元素赋值给要删除的元素,完成删除
		//结构体类型是可以直接赋值的
		address_book->all_address[name_exist] = address_book->all_address[address_book->size - 1];
		address_book->size--;
		name_exist = FindName(address_book, search_name);
	}

	printf("删除成功!\n");
	
}

int FindName(AddressBook* address_book, char search_name[100]) {
	
	for (int i = 0; i < address_book->size; i++) {
		//找到返回数组下标
		if (strcmp(address_book->all_address->name, search_name) == 0) {
			return i;
		}
	}
	//没有找到,返回 -1
	return -1;
}

void FindPersonInfo(AddressBook* address_book) {

	char search_name[100] = { 0 };

	//搜索人的方式也很多,我们这里用搜索名字的方法
	printf("更新联系人\n");
	printf("请输入人名:");
	scanf("%s", search_name);

	for (int i = 0; i < address_book->size; i++) {
		PersonInfo* info = &address_book->all_address[i];// 创建一个 PersonInfo 类型的变量简化程序,不然下面的姓名访问就太长了
		if (strcmp(info->name, search_name) == 0) {
			printf("[%d] %s  %s\n", i, info->name, info->phone);
		}
	}
	

}

void ModifyPersonInfo(AddressBook* address_book) {
	
	char search_name[100] = { 0 };
	int isjump = 1;

	printf("删除联系人\n");
	printf("请输入联系人姓名:");
	scanf("%s", search_name);

	int name_exist = FindName(address_book, search_name);

	if (name_exist == -1) {
		printf("该联系人不存在!\n");
		return;
	}
	
	//优化以下用户的体验
	printf("请输入新的姓名,输入 0 跳过:");
	scanf("%d", &isjump);
	if (isjump) {
		scanf("%s", address_book->all_address[name_exist].name);
	}
	printf("请输入新的电话,输入 0 跳过:");
	scanf("%d", &isjump);
	if (isjump) {
		scanf("%s", address_book->all_address[name_exist].phone);
	}

	printf("更新成功!\n");

}

void PrintPersonInfo(AddressBook* address_book) {
	
	PersonInfo* info;

	if (address_book->size == 0) {
		printf("当前没有联系人!\n");
		return;
	}

	printf("所有联系人信息如下:\n");
	
	for (int i = 0; i < address_book->size; i++) {
		info = &address_book->all_address[i];
		printf("[%2d]%4s  %s\n", i, info->name, info->phone);
	}
}

void ClearPersonInfo(AddressBook* address_book) {
	
	//清除所有信息是一种 危险的行为,我们最好让用户确认一次
	//相比你应该在自己的手机上回复过出厂设置,系统应该会让你确认不止一次!
	int is_continue = 0;

	printf("清除所有联系人,你确定吗?输入 0 继续: ");
	scanf("%d", &is_continue);
	if(is_continue == 0) {
		//将 size 置为 0 即可,不过你也可以将数组的每个元素都进行重置
		address_book->size = 0;
	}
	printf("清除完成!\n");
}

void SortPersonInfo(AddressBook* address_book) {

	printf("排序通讯录\n");

	for (int i = 0; i < address_book->size - 1; i++) {
		for (int j = 0; j < address_book->size - 1 - i; j++) {
			PersonInfo* info = &address_book->all_address[j];
			PersonInfo* info_next = &address_book->all_address[j + 1];
			//简单的用 strcmp 进行排序,不过排序的行为感觉是“未定义”的,
			//看着有规律,但再多试试会发现很多情况并没有规律。
			//也还有很多可以排血的函数。比如:strcoll,wcsscoll,wcscmp 这些只要你能弄懂,我想你也可以用。
			//或者有其他更好的实现办法,但这并不是我们在这里的重点。
			if (strcmp(info->name, info_next) > 0) {
				PersonInfo tmp;
				tmp = *info;
				*info = *info_next;
				*info_next = tmp;
			}
		}
	}
	printf("排序成功!\n");
}

int main(int argc, char* argv[]) {
	
	AddressBook address_book;
	
	//声明一个函数指针类型
	typedef void (*Func)(AddressBook*);
	Func func_table[] = {
		NULL,
		AddPersonInfo,
		DelPersonInfo,
		FindPersonInfo,
		ModifyPersonInfo,
		PrintPersonInfo,
		ClearPersonInfo,
		SortPersonInfo,
	};
	//或者你也可以这么做:
	//声明一个函数类型:
	//typedef void (Func)(AddressBook*);
	//我们用的是指针数组,数组类型必须是指针类型,所以应该加上 * 
	//Func* func_table[] = {
	//NULL,
	//AddPersonInfo,
	//DelPersonInfo,
	//FindPersonInfo,
	//ModifyPersonInfo,
	//PrintPersonInfo,
	//ClearPersonInfo,
	//SortPersonInfo,
	//}; 
	
	init(&address_book);

	
	while (1) {
		int choice = Menu();
		
		if (choice < 0 || choice > 7) {
			printf("输入错误!\n");
			continue;
		}

		if (choice == 0) {
			printf("再见!\n");
			break;
		}
		
		func_table[choice](&address_book);

	}

	return 0;
}

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

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

相关文章

C#实现数据采集系统-实现功能介绍

系统介绍 我们这里主要使用C#( .Net 6)来实现一个数据采集系统&#xff0c;从0到1搭建数据采集系统&#xff0c;从系统分析&#xff0c;功能拆解&#xff0c;到一一实现 数据采集 数据采集是企业信息化和数字化转型过程中的关键环节&#xff0c;它涉及到从生产设备、传感器…

Microsoft Visual C++ 2010 Express 使用

Microsoft Visual C 2010 Express 使用 Microsoft Visual C 2010 Express&#xff08;简称VC 2010 Express&#xff09;是一款免费的集成开发环境&#xff08;IDE&#xff09;&#xff0c;专为C和C语言的开发者设计。 安装 下载|本站链接【VC2010简体中文版】的安装包并解压…

2024年新手卖家该如何做好亚马逊运营?

随着电子商务的蓬勃发展&#xff0c;越来越多的新手卖家选择在亚马逊这一国际电商巨头平台上开展业务。然而&#xff0c;想要在竞争激烈的市场中脱颖而出&#xff0c;新手卖家需要精心规划并执行有效的运营策略。以下是为2024年新手卖家提供的关于如何做好亚马逊运营的一些建议…

C#学习-刘铁猛

文章目录 1.委托委托的具体使用-魔板方法回调方法【好莱坞方法】&#xff1a;通过委托类型的参数&#xff0c;传入主调方法的被调用方法&#xff0c;主调方法可以根据自己的逻辑决定调用这个方法还是不调用这个方法。【演员只用接听电话&#xff0c;如果通过&#xff0c;导演会…

刷题笔记 739. 每日温度 (单调栈),215. 数组中的第K个最大元素(堆),347.前 K 个高频元素

739. 每日温度 &#xff08;单调栈&#xff09;. - 备战技术面试&#xff1f;力扣提供海量技术面试资源&#xff0c;帮助你高效提升编程技能,轻松拿下世界 IT 名企 Dream Offer。https://leetcode.cn/problems/daily-temperatures/description/?envTypestudy-plan-v2&envI…

Fast Planner规划算法(一)—— Fast Planner前端

本系列文章用于回顾学习记录Fast-Planner规划算法的相关内容&#xff0c;【本系列博客写于2023年9月&#xff0c;共包含四篇文章&#xff0c;现在进行补发第一篇&#xff0c;其余几篇文章将在近期补发】 一、Fast Planner前端 Fast Planner的轨迹规划部分一共分为三个模块&…

Haproxy服务

目录 一.haproxy介绍 1.主要特点和功能 2.haproxy 调度算法 3.haproxy 与nginx 和lvs的区别 二.安装 haproxy 服务 1. yum安装 2.第三方rpm 安装 3.编译安装haproxy 三.配置文件详解 1.官方地址配置文件官方帮助文档 2.HAProxy 的配置文件haproxy.cfg由两大部分组成&…

React+TypeScript 组件库开发全攻略:集成Storybook可视化与Jest测试,一键发布至npm

平时我除了业务需求&#xff0c;偶尔会投入到UI组件的开发中&#xff0c;大多数时候只会负责自己业务场景相关或者一小部分公共组件&#xff0c;极少有从创建项目、集成可视化、测试到发布的整个过程的操作&#xff0c;这篇文章就是记录组件开发全流程&#xff0c;UI组件在此仅…

RabbitMQ学习实践二:MQ的实现

文章是本人在学习springboot实现消息队列功能时所经历的过程的记录&#xff0c;仅供参考&#xff0c;如有侵权请随时指出。 参考文章地址&#xff1a; RabbitMQ安装与入门_rabbitmq win11配置-CSDN博客 RabbitMQ入门到实战一篇文章就够了-CSDN博客 RabbitMQ系列&#xff08…

AI跟踪报道第48期-新加坡内哥谈技术-本周AI新闻:Open AI 和 Mistral的小型模型

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

华为路由器SSH登录实验

概念 SSH全称安全外壳&#xff08;Secure Shell&#xff09;协议&#xff0c;这个协议的目的就是为了取代缺乏机密性保障的远程管理协议&#xff0c;SSH基于TCP协议的加密通道&#xff0c;让客户端使用服务器的RSA公钥来验证SSHv2服务器的身份。 创建密钥对 在充当SSH服务器的…

UE4-获得角色控制权的两种方法

方法一&#xff1a; 方法二&#xff1a; 注意此方法不能有多个玩家出生点&#xff0c;如果有多个玩家出生点&#xff0c;会随机的选择一个玩家出生点进行生成。

C++的map和set介绍

系列文章目录 二叉树搜索树 map和set习题 文章目录 系列文章目录前言一、关联式容器键值对二、树形结构的关联式容器2.1 set2.1.1 set的介绍2.1.3 set的使用删除节点find的不同效率count举例lower_bound 和 upper_bound 2.2 multiset2.2.1 区别&#xff1a;find查找erase删除e…

Deepin系统,中盛科技温湿度模块读温度纯c程序(备份)

#include <stdio.h> #include <fcntl.h> #include <unistd.h> #include <termios.h>int main() {int fd;struct termios options;// 打开串口设备fd open("/dev/ttyMP0", O_RDWR | O_NOCTTY|O_NDELAY); //O_NDELAY:打开设备不阻塞//O_NOCTT…

http请求网址或网页的全流程

客户端通过浏览器请求网址或网页资源的步骤如下&#xff1a; http请求网址或网页的全流程 1.首先&#xff0c;浏览器做的第一步就是解析 URL 得到里面的参数2.浏览器封装 HTTP 请求报文3.DNS 域名解析获取 IP 地址4. 建立 TCP 连接5.浏览器发送请求6.负责传输的 IP 协议7.使用 …

基于Llama Index构建RAG应用(Datawhale AI 夏令营)

前言 Hello&#xff0c;大家好&#xff0c;我是GISer Liu&#x1f601;&#xff0c;一名热爱AI技术的GIS开发者&#xff0c;本文参与活动是2024 DataWhale AI夏令营&#xff1b;&#x1f632; 在本文中作者将通过&#xff1a; Gradio、Streamlit和LlamaIndex介绍 LlamaIndex 构…

【初阶数据结构】5.栈和队列

文章目录 1.栈1.1 概念与结构1.2 栈的实现2.队列2.1 概念与结构2.2 队列的实现3.栈和队列算法题3.1 有效的括号3.2 用队列实现栈3.3 用栈实现队列3.4 设计循环队列 1.栈 1.1 概念与结构 栈&#xff1a;一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操…

从零开始实现大语言模型(八):Layer Normalization

1. 前言 Layer Normalization是深度学习实践中已经被证明非常有效的一种解决梯度消失或梯度爆炸问题,以提升神经网络训练效率及稳定性的方法。OpenAI的GPT系列大语言模型使用Layer Normalization对多头注意力模块,前馈神经网络模块以及最后的输出层的输入张量做变换,使shap…

android13 默认输入法配置分析rom默认配置修改分析

总纲 android13 rom 开发总纲说明 目录 1.前言 2.解决方法 3.方法分析 3.1方法1 3.2方法2 4.彩蛋 1.前言 Android13上需要预装中文输入法, 但是直接预装输入法的话,会出现默认使能的问题,点击TextEdit输入框, 弹出的是默认英文输入法LatinIME, 而不是谷歌拼音输入…

解决GoLand添加GOROOT提示The selected directory is not a valid home for Go Sdk的问题

现象 解决 在Go安装路径下找到zversion.go文件&#xff0c;我的在D:\Program Files\Go1.21.1\src\runtime\internal\sys下面 打开文件&#xff0c;添加如下内容&#xff1a; const TheVersion go1.21.1保存后再重新添加GOROOT即可