通讯录(C语言版)

news2024/11/20 7:03:38

用c语言实现一个通讯录

功能:.添加、删除、查找、更改、显示、排序联系人

内存存储方式:结构体数组

1.打印菜单,各个功能分别用函数实现,将函数声明放在头文件中。

2.定义联系人信息,将联系人信息与count(用来记录当前通讯录人数),capacity(记录最大容量)。一起定义到结构体中,完成联系人的创建:

//定义联系人
typedef struct PenInfo {
	char name[20];
	int age;
	char sex[10];
	char tele[12];
	char addr[30];
}PenInfo;

typedef struct Contact {
	PenInfo* data;
	int count;
	int capacity;//设置我通讯录的最大容量
}Contact;

3.创建联系人,并用malloc或calloc函数向内存堆区开辟内存,在退出时记得释放内存,将count初始化为0

int Initcontact(Contact* pc) {
	assert(pc);
	pc->data =(PenInfo*) calloc(3,3 * sizeof(PenInfo));//为data开辟三个空间
	if (pc->data == NULL) {
		printf("%s", strerror(errno));
		return 1;
	}
	pc->count = 0;
	pc->capacity = 3;//设置最大容量为3

	//从文件中读取联系人内容
	LoadContact(pc);
	return 0;
}

4.添加联系人,当联系人容量达到最大容量时,增容,然后进行联系人的信息输入:

void AddCapacity(Contact *pc) {
	assert(pc);
	if (pc->count == pc->capacity) {
		pc->capacity +=2;
		//printf("增容成功\n");
	}
	return;
}

void Addcontact(Contact* pc){
	assert(pc);
	//增容
	AddCapacity(pc);
	//添加联系人
	printf("请输入联系人名字:>");
	scanf("%s", pc->data[pc->count].name);
	printf("请输入联系人年龄:>");
	scanf("%d", &(pc->data[pc->count].age));
	printf("请输入联系人性别:>");
	scanf("%s", pc->data[pc->count].sex);
	printf("请输入联系人电话:>");
	scanf("%s", pc->data[pc->count].tele);
	printf("请输入联系人地址:>");
	scanf("%s", pc->data[pc->count].addr);

	pc->count++;

	printf("添加成功\n");
}

5. 显示联系人(记得格式化)通过for循环标准输出:

void Showcontact(const Contact* pc) {
	assert(pc);
	if (pc->count == 0) {
		printf("还没添加联系人\n");
		return;
	}
	printf("%-20s\t%-3s\t%-10s\t%-12s\t%-30s\n", "名字", "年龄", "性别", "电话", "地址");
	printf("-----------------------------------------------------------------------------\n");
	for (int i = 0; i < pc->count; i++) {
		
		printf("%-20s\t%-5d\t%-10s\t%-12s\t%-30s", pc->data[i].name,
			pc->data[i].age,
			pc->data[i].sex,
			pc->data[i].tele,
			pc->data[i].addr);
		printf("\n");
		printf("-----------------------------------------------------------------------------\n");
	}
}

6.当查找、删除、更改时都需要进行查找,所以直接封装一个查找函数(找到了返回下标)

//查找联系人
static int Findcontact(Contact* pc, char* name) {
	assert(pc);
	for (int i = 0; i < pc->count; i++) {
		if (strcmp(name, pc->data[i].name) == 0) {
			return i;
		}
	}
	return -1;
}

7.查找联系人

void Searchcontact(Contact* pc) {
	assert(pc);
	char name[20] = { 0 };
	printf("请输入要查找的联系人名字:>");
	scanf("%s", name);
	//查找
	int pos = Findcontact(pc, name);
	//删除
	if (pos == -1) {
		printf("没有该联系人\n");
		return;
	}
	else {
		printf("找到了\n");
		printf("%-20s\t%-3s\t%-10s\t%-12s\t%-30s\n", "名字", "年龄", "性别", "电话", "地址");
		printf("-----------------------------------------------------------------------------\n");

		printf("%-20s\t%-5d\t%-10s\t%-12s\t%-30s", pc->data[pos].name,
			pc->data[pos].age,
			pc->data[pos].sex,
			pc->data[pos].tele,
			pc->data[pos].addr);
		printf("\n");
		printf("-----------------------------------------------------------------------------\n");
	}

}

 8.删除联系人,删除后,由于是顺序表存储,将后面的数据向前一个结点覆盖,且count--

void Delcontact(Contact* pc) {
	assert(pc);
	char name[20] = { 0 };
	printf("请输入要删除的联系人名字:>");
	scanf("%s", name);
	//查找
	int pos = Findcontact(pc, name);
	//删除
	if (pos == -1) {
		printf("没有该联系人\n");
		return;
	}
	for (int i = pos; i < pc->count + 1; i++) {//count+1防止溢出
		pc->data[i] = pc->data[i + 1];
	}
	pc->count--;
	printf("删除成功\n");

}

9.修改联系人,将信息覆盖即可:

void Modifycontact(Contact* pc) {
	assert(pc);
	char name[20] = { 0 };
	printf("请输入要修改的联系人的名字:>");
	scanf("%s", name);
	//查找
	int pos = Findcontact(pc, name);
	//删除
	if (pos == -1) {
		printf("没有该联系人\n");
		return;
	}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");
		printf("修改成功\n");
		}
}

10.排序,分为年龄和姓名,都用库函数qsort(默认升序)实现,年龄进行时稍微复杂,细节如下:

//按姓名排序函数
int Sort_by_name(const void* e1, const void* e2) {
	return strcmp(((PenInfo*)e1)->name, ((PenInfo*)e2)->name);
}
//按年龄排序
int Sort_by_age(const void* e1, const void* e2) {
	if (((PenInfo*)e1)->age < ((PenInfo*)e2)->age) {
		return -1;
	}
	if (((PenInfo*)e1)->age > ((PenInfo*)e2)->age) {
		return 1;
	}
	if (((PenInfo*)e1)->age == ((PenInfo*)e2)->age) {
		return 0;
	}
}

void Sortcontact(Contact* pc) {
	assert(pc);
	int chiose;
	printf("(1.按姓名排序 2.按年龄排序):>");
	scanf("%d", &chiose);
	if (chiose == 1) {
		qsort(pc->data,pc->count,sizeof(PenInfo), Sort_by_name);
		printf("排序成功\n");
	}
	else if (chiose == 2) {
		qsort(pc->data, pc->count, sizeof(PenInfo), Sort_by_age);
		printf("排序成功\n");
	}
	else {
		printf("无效输入\n");
		return;
	}
}

11.保存联系人到相对路径“contact.txt”中,通过二进制进行输入输出,退出时保存,打开时读取。

void SaveContact(Contact* pc) {
	FILE* pfWrite = fopen("contact.txt", "wb");
	if (pfWrite == NULL) {
		perror("SaveContact");
		return;
	}
	//用二进制的形式写入文件
	for (int i = 0; i <= pc->count; i++) {
		fwrite(pc->data+i, sizeof(PenInfo), 1, pfWrite);
	}
	//关闭文件
	fclose(pfWrite);
	pfWrite = NULL;
}

void LoadContact(Contact* pc) {
	assert(pc);
	FILE* pfRead = fopen("contact.txt", "rb");
	if (pfRead == NULL) {
		//perror("LoadContact");
		return;
	}
	while (fread(&(pc->data[pc->count]), sizeof(PenInfo), 1, pfRead) == 1) {
		//判断是否空间不足
		AddCapacity(pc);
		pc->count++;
	}
	fclose(pfRead);
	pfRead = NULL;
}

12.测试代码:

#define _CRT_SECURE_NO_WARNINGS

#include "contact.h"

//创建菜单
void menu() {
	printf("------------My ContactBook------------\n");
	printf("-----------1.Add linkman  ------------\n");
	printf("-----------2.Del linkman  ------------\n");
	printf("-----------3.Show linkman ------------\n");
	printf("-----------4.Search linkman ----------\n");
	printf("-----------5.Modify linkman ----------\n");
	printf("-----------6.Sort linkman -----------\n");
	printf("-----------0.Exit menu  -------------\n");

}
int main() {    
	int input = 0;
	//创建联系人
	Contact con;
	//初始化通讯录
	Initcontact(&con);
	do {
		menu();
		printf("请选择对应功能的编号:>");
		scanf("%d", &input);
		switch (input) {
		case 1:         
			Addcontact(&con);
			break;
		case 2:
			Delcontact(&con);
			break;
		case 3:
			Showcontact(&con);
			break;
		case 4:
			Searchcontact(&con);
			break;
		case 5:
			Modifycontact(&con);
			break;
		case 6:
			Sortcontact(&con);
			break;
		case 0:
			SaveContact(&con);
			DestoryContact(&con);
			printf("退出通讯录\n");
			break;
		default :
			printf("选择错误\n");
			break;
		}
	} while (input);
	return 0;
}

测试结果:

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

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

相关文章

云渲染是什么?云渲染怎么用?

云渲染的出现为影视动画、建筑设计、游戏开发等领域提供了很大的便利&#xff0c;为公司或者个人节约了大量的渲染部分时间&#xff0c;大大的提高了工作效率。哪什么是云渲染&#xff1f;云渲染怎么用呢&#xff1f;我们一起来看看。 云渲染是什么&#xff1f; 云渲染是一种…

高级深入--day30

Scrapy Shell Scrapy终端是一个交互终端,我们可以在未启动spider的情况下尝试及调试代码,也可以用来测试XPath或CSS表达式,查看他们的工作方式,方便我们爬取的网页中提取的数据。 如果安装了 IPython ,Scrapy终端将使用 IPython (替代标准Python终端)。 IPython 终端与其…

QDir实践

现在有多个文件&#xff0c;路径为&#xff1a; a\xxx\kmd_config\c.json 其中xxx是变量 startcalc,,,,,, 目标&#xff1a; 访问每一个json文件 实例&#xff1a; QString app_path QApplication::applicationDirPath() "/app";QDir dir(app_path);QStringLi…

NewStarCTF2023公开赛道-压缩包们

题目提示是压缩包 用010editor打开&#xff0c;不见PK头&#xff0c;补上50 4B 03 04 14 00 00 00 将文件改成.zip后缀&#xff0c;打开&#xff0c;解压出flag.zip 尝试解压&#xff0c;报错 发现一串base64编码 SSBsaWtlIHNpeC1kaWdpdCBudW1iZXJzIGJlY2F1c2UgdGhleSBhcmUgd…

【LeetCode刷题笔记】二分查找

1539. 第 k 个缺失的正整数 解题思路&#xff1a; 1. 二分 &#xff0c;一个严格升序 正整数 数组在没有数字缺失的情况下满足&#xff1a; nums[i] i 1 &#xff0c;如果有缺失&#xff0c;则每个 下标 i 上的数字前面缺失的正整数个数为&#xff1a; nums[i] - (i 1) &am…

ROS 摄像头标定-camera_calibration

摄像头这种精密仪器对光学器件的要求较高&#xff0c;由于摄像头内部与外部的一些原因&#xff0c;生成的物体图像往往会发生畸变&#xff0c;为了避免数据源造成的误差&#xff0c;需要针对摄像头的参数进行标定。 ROS官方提供了用于双目和单目摄像头标定的功能包—camera_cal…

单链表---结构体实现

定义 链表称为线性表的链式存储&#xff0c;顺序表逻辑上相邻的数据&#xff0c;存储位置也相邻。链表逻辑上相邻的数据&#xff0c;存储位置是随机分布在内存的各个位置上的。 故 对于每一个结点&#xff0c;定义的结构体是&#xff1a; typedef struct _LinkNode {int d…

存档&改造【06】Apex-Fancy-Tree-Select花式树的使用误删页数据还原(根据时间节点导出导入)

之前一直想实现厂区-区域-产线之间的级联选取&#xff0c;于是导入插件Apex-Fancy-Tree-Select花式树 存档&#xff06;改造【03】Apex-Fancy-Tree-Select花式树的导入-CSDN博客 现在则是在Oracle Apex中的应用 花式书级联列表展示厂区-区域-产线 想要实现的效果 由厂区>…

Shopee活动报错怎么办?Shopee活动类型怎么选择?-站斧浏览器

有时候&#xff0c;在同步虾皮活动的过程中&#xff0c;您可能会遇到一些问题或报错信息。遇到这种情况要怎么办&#xff0c;Shopee活动类型怎么选择&#xff1f; Shopee活动报错怎么办&#xff1f; 下面是几种常见的问题及其解决方法&#xff1a; 1、网络连接问题&#xff…

05 | @Query 解决了什么问题?什么时候应该选择它?

上个课时我们介绍了 Query Define Method 的语法&#xff0c;这一课时来介绍一下 Query 注解的语法是什么样的。我们通过快速体验 Query 的方法、JpaQueryLookupStrategy 关键源码剖析、Query 的基本用法、Query 之 Projections 应用返回指定 DTO、Query 动态查询解决方法&…

网工笔记整理:策略工具Filter-policy的使用

一、概述 Filter-Policy&#xff08;过滤-策略&#xff09;是一个很常用的路由信息过滤工具&#xff0c;能够对接收、发布、引入的路由进行过滤&#xff0c;可应用于IS-IS、OSPF、BGP等协议。 Filter-policy在距离矢量路由协议中的应用 filter-policy import&#xff1a;不发…

Python学习基础笔记六十五——布尔值

布尔对象&#xff1a; Python中有一种对象类型称之为布尔对象&#xff08;英文叫bool&#xff09;。 布尔对象只有两种取值&#xff0c;True和False。对应的是真和假&#xff0c;或者说是和否。True对应的是&#xff0c;False对应的是否。 我觉得这句话是一个关键&#xff1a…

04 | 如何利用 Repository 中的方法返回值解决实际问题?

上一课时&#xff0c;我们着重讲了方法名和参数的使用方法&#xff0c;这一课时我们来看下Repository 支持的返回结果有哪些&#xff0c;以及 DTO 类型的返回结果如何自定义&#xff0c;及其在实际工作场景中我们如何做。通过本课时的学习&#xff0c;你将了解到 Repository 的…

Ansible概述以及模块

目录 一、Ansible概述 1、Ansible是什么 2、Ansible的作用 3、Ansible的特性 4、Ansible的工作机制 5、Ansible的特点 二、Ansible安装部署 1、管理端安装ansible 2、配置主机清单 3、配置密钥对验证 三、Absible命令行模块 1、command模块 2、shell模块 3、cron …

Jackson+Feign反序列化问题排查

概述 本文记录在使用Spring Cloud微服务开发时遇到的一个反序列化问题&#xff0c;RPC/HTTP框架使用的是Feign&#xff0c;JSON序列化反序列化工具是Jackson。 问题 测试环境的ELK告警日志如下&#xff1a; - [43f42bf7] 500 Server Error for HTTP POST "/api/open/d…

一篇文章让你了解“JWT“

一.JWT简介 1.概念 JWT (JSON Web Token) 是一种用于在网络上安全传输信息的开放标准&#xff08;RFC 7519&#xff09;。它是一种紧凑且自包含的方式&#xff0c;用于在不同组件之间传递信息&#xff0c;通常用于身份验证和授权目的。JWT 是以 JSON 格式编码的令牌&#xff…

Shell后门脚本

说明&#xff1a;请在云服务器中执行&#xff0c;执行脚本后会发生 1、创建${create_user}用户并赋予sudo权限2、获取公网IP地址和SSH端口3、将用户公网IPSSH端口信息发送给${mail_from}变量 #!/bin/bash # 收件人邮箱 mail_fromxxxxx.com sshd_port$(grep "^Port"…

AI低代码维格云甘特视图怎么用?

甘特视图,以日期为横轴展示任务持续时长和先后顺序,简称甘特图。 项目管理过程中,合理分配任务和资源至关重要,使用甘特图,妥当解决以下场景: 想知道整个项目的周期多长,哪些任务对项目的周期影响最大; 想知道每个任务的时间有多长,任务的优先级和依赖关系是什么; 想…

VUE3页面截取部署后的二级目录地址

用vue3开发了一个项目&#xff0c;只能部署在根目录&#xff0c;不能加二级目录&#xff0c;后来网上找了解决方案&#xff0c;在vite.config.ts中增加base: ./,配置解决问题&#xff0c;参考下图&#xff1a; 但部署后要获取部署的二级目录地址切遇到问题&#xff0c;后来想了…

SQL如何导入数据以及第一次上机作业

如何导入excel数据 首先得学会导入数据 使用excel格式不需要改成其它格式&#xff08;如csv&#xff0c;txt&#xff09;&#xff0c;因为你改了到时候还是会报错&#xff08;实践过使用Sum统计总数一直说我数据格式有问题&#xff09; 首先右键TSGL数据库->任务->导入数…