C语言小项目——通讯录高阶(文件管理版)

news2024/11/26 0:29:08

通讯录初阶: 点这里
通讯录中阶: 点这里

  • 文件管理版本改进之处
    • 通讯录初始化
    • 退出通讯录并保存
  • 完整代码
    • contact.h
    • contact.c
    • test.c

文件管理版本改进之处

通讯录初始化

contact.c
在这里插入图片描述

退出通讯录并保存

test.c
在这里插入图片描述

contact.c
在这里插入图片描述

contact.h
在这里插入图片描述

完整代码

contact.h

#pragma once

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

#define MAX_CONTACT 100
#define MAX_NAME 20
#define MAX_SEX 5
#define MAX_TELE 12
#define MAX_ADDR 30
//动态版本
#define DEFAULT_SIZE 3
#define INC_SIZE 2

enum OPTION
{
	EXIT0,
	ADD,
	DEL,
	SEARCH,
	MODIFY,
	SHOW,
	SORT
};

enum Peo
{
	EXIT1,
	NAME,
	AGE,
	SEX,
	TELE,
	ADDR
};

//一个人信息的结构体
typedef struct People
{
	char name[MAX_NAME];
	int age;
	char sex[MAX_SEX];
	char tele[MAX_TELE];
	char addr[MAX_ADDR];
}Peo;

//存放大量人信息的通讯录
// 静态版本
//typedef struct Contact
//{
//	Peo data[MAX_CONTACT];
//	int sz;
//}Con;
//动态版本
//最初容量设置为3,当放满之后每次动态开辟2个容量
typedef struct Contact
{
	Peo* data;//指向存放数据的空间
	int sz;//记录当前通讯录有效元素的个数
	int capacity;//通讯录当前最大容量
}Con;

//初始化通讯录
void InitContact(Con* pc);
//给通讯录添加联系人
void AddContact(Con* pc);
//显示通讯录信息
void ShowContact(const Con* pc);
//删除指定联系人
void DelContact(Con* pc);
//查找指定联系人
void SearchContact(const Con* pc);
//修改指定联系人的信息
void ModifyContact(Con* pc);
//按照指定方式排序
void SortContact(Con* pc);
//文件版本
//把通讯录保存到文件中
void SaveContact(Con* pc);
//动态版本
//销毁通讯录
void DestroyContact(Con* pc);

contact.c

#define _CRT_SECURE_NO_WARNINGS 1

#include"contact.h"

//初始化通讯录——————————————————————————————————————————————————————————
//静态版本
//void InitContact(Con* pc)
//{
//	assert(pc);
//
//	//循环初始化也可
//	//int i = 0;
//	//for (i = 0; i < MAX_CONTACT; i++)
//	//{
//	//	strcpy(pc->data[i].name, "0");
//	//	pc->data[i].age = 0;
//	//	strcpy(pc->data[i].sex, "0");
//	//	strcpy(pc->data[i].tele, "0");
//	//	strcpy(pc->data[i].addr, "0");
//	//}
//	//pc->sz = 0;
//
//	//初始化结构体数组最简单的方法
//	memset(pc->data, 0, sizeof(pc->data));
//	pc->sz = 0;
//}

//动态版本
//void InitContact(Con* pc)
//{
//	assert(pc);
//
//	pc->data = (Peo*)malloc(DEFAULT_SIZE * sizeof(Peo));
//	if (pc->data == NULL)
//	{
//		perror(InitContact);
//		return;
//	}
//	pc->sz = 0;
//	pc->capacity = DEFAULT_SIZE;
//}

//文件版本
static int CheckCapacity(Con* pc)
{
	if (pc->sz == pc->capacity)
	{
		Peo* ptr = realloc(pc->data, (pc->capacity + INC_SIZE) * sizeof(Peo));
		if (ptr == NULL)
		{
			perror("CheakCapacity");
			return 0;
		}
		else
		{
			pc->data = ptr;
			pc->capacity += INC_SIZE;
			return 1;
		}
	}
	return 1;
}

static void LoadContact(Con* pc)
{
	//打开文件
	FILE* pf = fopen("contact.dat", "rb");
	if (pf == NULL)
	{
		perror("LoadContact");
		return;
	}
	//读文件
	Peo tmp = { 0 };
	while (fread(&tmp, sizeof(Peo), 1, pf))
	{
		if (0 == CheckCapacity(pc))
		{
			return;
		}
		pc->data[pc->sz] = tmp;
		pc->sz++;
	}
	//关闭文件
	fclose(pf);
	pf = NULL;
}

void InitContact(Con* pc)
{
	assert(pc);

	pc->data = (Peo*)malloc(DEFAULT_SIZE * sizeof(Peo));
	if (pc->data == NULL)
	{
		perror(InitContact);
		return;
	}
	pc->sz = 0;
	pc->capacity = DEFAULT_SIZE;

	//文件中保存的信息加载到通讯录中
	LoadContact(pc);
}

//给通讯录添加联系人——————————————————————————————————————————————————————
//void AddContact(Con* pc)
//{
//	assert(pc);
//
//	if (pc->sz == MAX_CONTACT)
//	{
//		printf("通讯录已满,无法添加\n");
//		return;
//	}
//
//	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 AddContact(Con* pc)
{
	assert(pc);

	if (0 == CheckCapacity(pc))
	{
		return;
	}

	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 ShowContact(const Con* pc)
{
	assert(pc);

	printf("%-20s\t%-4s\t%-5s\t%-12s\t%-30s\n", "名字", "年龄", "性别", "电话", "地址");
	int i = 0;//如果后面需要i的值,就不能定义在for循环的初始化部分,因为出了循环就被销毁
	for (i = 0; i < pc->sz; i++)
	{
		printf("%-20s\t%-4d\t%-5s\t%-12s\t%-30s\n",
			pc->data[i].name,
			pc->data[i].age,
			pc->data[i].sex,
			pc->data[i].tele,
			pc->data[i].addr);
	}
}

//删除指定联系人——————————————————————————————————————————————————————————
static int FindByName(const Con* 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;
}

void DelContact(Con* pc)
{
	assert(pc);

	if (pc->sz == 0)
	{
		printf("通讯录为空\n");
		return;
	}

	char name[MAX_NAME] = { 0 };
	printf("请输入要删除的人的名字:>");
	scanf("%s", name);
	int pos = FindByName(pc, name);
	if (pos == -1)
	{
		printf("要删除的人不存在\n");
		return;
	}
	//删除方法一:从后向前一个个覆盖
	//for (i = pos; i < pc->sz - 1; i++)
	//{
	//	pc->data[i] = pc->data[i + 1];
	//}
	//pc->sz--;

	//删除方法二:memmove,和方法一相同
	//memmove(&(pc->data[pos]), &(pc->data[pos + 1]), ((pc->sz) - pos - 1) * (sizeof(pc->data[0])));
	//pc->sz--;

	//删除方法三:将要删除的和最后一个交换,然后sz--
	Peo tmp = pc->data[pos];
	pc->data[pos] = pc->data[pc->sz - 1];
	pc->data[pc->sz - 1] = tmp;
	pc->sz--;

	printf("删除联系人成功\n");
}

//查找指定联系人————————————————————————————————————————————————————————————
void SearchContact(const Con* pc)
{
	assert(pc);

	//学习c++之后可以用函数重载实现用任何信息都能进行检索
	char name[MAX_NAME] = { 0 };
	printf("请输入要查找人的名字:>");
	scanf("%s", name);
	int pos = FindByName(pc, name);
	if (pos == -1)
	{
		printf("要查找的人不存在\n");
	}
	else
	{
		printf("%-20s\t%-4s\t%-5s\t%-12s\t%-30s\n", "名字", "年龄", "性别", "电话", "地址");
		printf("%-20s\t%-4d\t%-5s\t%-12s\t%-30s\n",
			pc->data[pos].name,
			pc->data[pos].age,
			pc->data[pos].sex,
			pc->data[pos].tele,
			pc->data[pos].addr);
	}
}

//修改指定联系人的信息——————————————————————————————————————————————————————
void ModifyContact(Con* pc)
{
	assert(pc);

	char name[MAX_NAME] = { 0 };
	printf("请输入要修改人的名字:>");
	scanf("%s", name);
	int pos = FindByName(pc, name);
	if (pos == -1)
	{
		printf("要修改的人不存在");
	}
	else
	{
		//一股脑修改全部信息
		//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");

		//结合switch指定修改某个信息
		int input = 0;
		do
		{
			printf("0.EXIT1 1.NAME 2.AGE 3.SEX 4.TELE 5.ADDR\n");
			printf("请选择要修改的信息or选择0退出修改:>");
			scanf("%d", &input);
			switch (input)
			{
			case NAME:
				printf("请输入修改后的名字:>");
				scanf("%s", pc->data[pos].name);
				break;
			case AGE:
				printf("请输入修改后的年龄:>");
				scanf("%d", &(pc->data[pos].age));
				break;
			case SEX:
				printf("请输入修改后的性别:>");
				scanf("%s", pc->data[pos].sex);
				break;
			case TELE:
				printf("请输入修改后的电话:>");
				scanf("%s", pc->data[pos].tele);
				break;
			case ADDR:
				printf("请输入修改后的地址:>");
				scanf("%s", pc->data[pos].addr);
				break;
			case EXIT1:
				break;
			default:
				printf("选择错误,重新选择\n");
				break;
			}
		} while (input);

		printf("修改成功\n");
	}
}

//按照指定方式排序——————————————————————————————————————————————————————————————

int flag = 0;//qsort和Cmp函数已经固定好参数,要想体现升序和降序,只能定义全局变量,然后在函数里调用

static int CmpCharArr(const void* p1, const void* p2)
{
	return flag * (strcmp((*(Peo*)p1).name, (*(Peo*)p2).name));
}

static int CmpInt(const void* p1, const void* p2)
{
	return flag * (((*(Peo*)p1).age) - ((*(Peo*)p2).age));
}

void SortContact(Con* pc)
{
	assert(pc);

	int input = 0;
	do
	{
		printf("0.EXIT1 1.NAME 2.AGE 3.SEX 4.TELE 5.ADDR\n");
		printf("请选择要按照哪种方式排序or选择0退出排序:>");
		scanf("%d", &input);
		if (input != 0)
		{
			printf("升序选择1,降序选择-1:>");
			while (flag != 1 && flag != -1)
			{
				scanf("%d", &flag);
				if (flag != 1 && flag != -1)
				{
					printf("输入错误,请重新输入\n");
				}
			}
		}
		switch (input)
		{
		case NAME:
			qsort(pc, pc->sz, sizeof(pc->data[0]), CmpCharArr);
			printf("排序成功\n");
			break;
		case AGE:
			qsort(pc, pc->sz, sizeof(pc->data[0]), CmpInt);
			printf("排序成功\n");
			break;
		case SEX:
			qsort(pc, pc->sz, sizeof(pc->data[0]), CmpCharArr);
			printf("排序成功\n");
			break;
		case TELE:
			qsort(pc, pc->sz, sizeof(pc->data[0]), CmpCharArr);
			printf("排序成功\n");
			break;
		case ADDR:
			qsort(pc, pc->sz, sizeof(pc->data[0]), CmpCharArr);
			printf("排序成功\n");
			break;
		case EXIT1:
			break;
		default:
			printf("选择错误,重新选择\n");
			break;
		}
	} while (input);
}

//文件版本
void SaveContact(Con* 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(Peo), 1, pf);
	}

	//关闭文件
	fclose(pf);
	pf = NULL;
}

//动态版本
void DestroyContact(Con* pc)
{
	free(pc->data);
	pc->data = NULL;
	pc->capacity = pc->sz = 0;
}

test.c

#define _CRT_SECURE_NO_WARNINGS 1

#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");
	printf("********************************\n");
}

void test()
{
	int input = 0;
	Con 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:
			//c++要是有函数重载会好写很多
			SortContact(&con);
			break;
		case EXIT0:
			//文件版本
			SaveContact(&con);
			//动态版本
			DestroyContact(&con);
			printf("退出通讯录\n");
			break;
		default:
			printf("选择错误,重新选择\n");
			break;
		}
	} while (input);
}

int main()
{
	test();
	return 0;
}


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

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

相关文章

缕析条分Scroll属性 | 京东云技术团队

最近有项目需要使用js原生开发滑动组件&#xff0c;频繁要用到dom元素的各种属性&#xff0c;其中以各种类型的height和top属性居多&#xff0c;名字相近&#xff0c;含义也很容易搞混。因此特地总结归纳了一下常用的知识点&#xff0c;在文末我们来挑战实现一个简易的移动端Sc…

Window下编译ffmpeg

Window下编译ffmpeg 下载MSYS2编译ffmpeg运行 下载MSYS2 MSYS2是一个是工具和库的集合&#xff0c;它能够方便的在windows上编译、安装和运行程序。ffmpeg可以通过这个软件来编译。 从MSYS2官网下载MSYS2并安装。 运行MSYS2终端&#xff0c;在终端中输入命令&#xff0c;安装…

JVM运行时数据区——Java虚拟机栈

每个线程在运行时都会创建一个Java虚拟机栈&#xff0c;也是线程私有的&#xff0c;其内部包含一个个的栈帧&#xff0c;先进后出&#xff0c;对应着一个个方法的调用&#xff0c;运行完则弹出&#xff0c;所以不存在垃圾回收的问题&#xff0c;如果线程所需要的栈深度大于此线…

什么是芯片组,南桥与北桥芯片的作用与区别

主板是连接计算机所有部件的PCB。在老式计算机中&#xff0c;所有芯片都分布在主板上。在现代计算机中&#xff0c;芯片数量减少并集中在特定位置。因此&#xff0c;将多个芯片组合起来形成一个芯片。这种可以替代大量芯片的芯片称为芯片组。主板上有一个芯片组。芯片组处理CPU…

docker在linux下简单部署项目

springboot项目docke部署 1.手动部署 1. 编写dockerfile文件 2. 将jar包和docker文件放到服务器上 执行mvn clean package docker:build 3.执行docker images查询是否存在镜像 4.启动方式放在下面写 2.通过gitlab ci/cd方式实现自动化部署 3.创建一个.gitlab-ci.yml 文件 3…

匿名内部类/Lambda Java和Kotlin谁会导致内存泄漏?

前言 内存泄漏是程序界永恒的话题&#xff0c;对于Android开发来说尤为重要&#xff0c;想让你的App表现得更优雅&#xff0c;了解并治理内存泄漏问题势在必行。 通过本篇文章&#xff0c;你将了解到&#xff1a; 何为内存泄漏?Android 常见内存泄漏场景Java匿名内部类会导致…

Vue3警告提示(Alert)

可自定义设置以下属性&#xff1a; 警告提示内容&#xff08;message&#xff09;&#xff0c;类型&#xff1a;string | slot&#xff0c;默认&#xff1a;‘’警告提示的辅助性文字介绍&#xff08;description&#xff09;&#xff0c;类型&#xff1a;string | slot&#…

14 - 堆栈 - 小顶堆

前面我们学习了线性结构的栈, 今天我们来学习一种非线性结构-堆 堆的定义 堆是一种非线性结构,可以把堆看作一棵二叉树, 堆的存储可以使用数组来存放! 堆的分类 堆可以分为大顶堆和小顶堆。 大顶堆: 每个结点的值都大于或等于其左右孩子结点的值。 小顶堆: 每个结点的值…

目标检测——yolo系列算法

目录 yolo算法yolo算法思想yolo的网络结构网络输入网络输出7x7网格30维向量 yolo模型的训练训练样本的构建损失函数模型训练 模型预测yolo总结 yoloV2预测更准确(better)batch normalization使用高分辨率图像微调分类模型采样Anchor Boxes聚类提取anchor尺度边框位置的预测细粒…

设计模式之单例模式的实现形式、弊端以及可替代的解决方案。

你好&#xff0c;我是爱养猫的程序员雪球&#xff0c;今天与你分享设计模式之单例模式。 单例模式是指一个类只允许创建一个对象&#xff08;或实例&#xff09;的模式。它在很多应用场景中具有重要作用&#xff0c;例如处理资源访问冲突&#xff08;如日志文件写入&#xff09…

生信分析案例 Python简明教程 | 视频12

开源生信 Python教程 生信专用简明 Python 文字和视频教程 源码在&#xff1a;https://github.com/Tong-Chen/Bioinfo_course_python 目录 背景介绍 编程开篇为什么学习Python如何安装Python如何运行Python命令和脚本使用什么编辑器写Python脚本Python程序事例Python基本语法 数…

安徽华云安荣获合肥市大数据企业认定

日前&#xff0c;合肥市数据资源局公布了2023年度合肥市大数据企业认定名单&#xff0c;华云安子公司安徽华云安科技有限公司&#xff08;以下简称安徽华云安&#xff09;被成功认定为合肥市大数据企业。 据悉&#xff0c;合肥市大数据企业是合肥市为扶持和鼓励大数据企业发展&…

Android 自定义带箭头对话框背景

简介 自定义drawable&#xff0c;带箭头对话框背景&#xff0c;三角形矩形组合。应用于对话框背景、提示语背景等。 可设置箭头显示方向、箭头大小、箭头导圆角尺寸、矩形尺寸、矩形导圆角尺寸、背景颜色、drawable padding值&#xff08;影响宿主控件padding&#xff09;。 …

欧姆龙以太网模块如何设置ip连接 Kepware opc步骤

在数字化和自动化的今天&#xff0c;PLC在工业控制领域的作用日益重要。然而&#xff0c;PLC通讯口的有限资源成为了困扰工程师们的问题。为了解决这一问题&#xff0c;捷米特推出了JM-ETH-CP转以太网模块&#xff0c;让即插即用的以太网通讯成为可能&#xff0c;不仅有效利用了…

排序算法之冒泡排序详解-python版

冒泡排序&#xff1a;通过比较2个相邻元素之间的大小&#xff0c;交换元素顺序&#xff0c;从而达到排序目的。 从百度百科摘抄下来的冒泡排序原理如下&#xff1a; 比较相邻的元素。如果第一个比第二个大&#xff0c;就交换他们两个。 对每一对相邻元素做同样的工作&#xf…

ComboBox基本用法

作用&#xff1a;是一个下拉框&#xff0c;用于以下拉列表的方式展示数据。 常用属性&#xff1a; 常用事件&#xff1a; 下拉列表框内容选择变化时触发 后台代码示范&#xff1a; private void comboBox1_SelectedIndexChanged(object sender, EventArgs e){//获取被选中的…

怎样优雅地增删查改(七):按用户查询

文章目录 实现使用测试 实现 定义按用户查询&#xff08;IUserOrientedFilter&#xff09;接口 public interface IUserOrientedFilter {public string EntityUserIdIdiom { get; }Guid? UserId { get; set; } }EntityUserIdIdiom&#xff1a;语义上的UserId&#xff0c;用于…

使用Pandas简化数据探索性分析

大家好&#xff0c;本文将探讨数据探索性分析的两个基本方面&#xff1a;数据集形状和空值。我们将深入了解Pandas如何简化这些任务&#xff0c;重点关注需要同时分析多个表格的情况。使用的库是pandas和tabulate。 数据集形状 要检索单个表格的形状&#xff0c;可以使用.sh…

「小摹AI」赋能原型设计 开放内测申请

「小摹AI」智能原型助手发布啦&#xff01; 4大AI应用能力&#xff1a;智能原型|智能文本|智能翻译|智能填充 释放原型设计的无限潜能 摹客AI - 让设计更具创造力http://www.mockplus.cn/ai/?hmsrwencsdnAI 智能原型 催生创新&#xff0c;开启原型设计新境界 根据描述&…

equals与Hashcde的区别

1、equals与hashCode的区别 equals与hashcode这两个方法都是从Object类中继承过来的。 hashCode()&#xff1a;计算出对象实例的哈希地址&#xff0c;并且返回该地址&#xff0c;称哈希函数&#xff0c;又称散列表。 equals()&#xff1a;反映的是对象的内存地址或者对象的内…