当前位置: 首页 > news >正文

【项目】通讯录1(C语言)

【项目】—— 通讯录1(C语言)

通讯录是存储和管理我们的个人信息的程序应用。这里我们实现一个静态的通讯录(固定容量,无法扩容)

通讯录的功能

  1. 存储100个联系人的信息(姓名、性别、年龄、电话、地址)
  2. 添加联系人
  3. 删除联系人
  4. 修改联系人
  5. 根据姓名查寻联系人
  6. 根据姓名将联系人升序排序
  7. 展示所有联系人

目录

  • 一、通讯录的结构
  • 二、头文件
    • 1. 头文件引用
    • 2. 结构体声明
    • 3. 函数声明
  • 三、测试文件
  • 四、源文件
    • 1. 菜单
    • 2. 初始化
    • 3. 获取指定姓名的联系人下标
    • 4. 添加联系人
    • 5. 删除联系人
    • 6. 修改联系人
    • 7. 查询联系人
    • 8. 联系人排序
    • 9. 展示所有联系人
  • 五、程序演示
  • 六、完整代码

一、通讯录的结构

​ 通讯录由C语言实现,实现环境是VS2019编译程序,结构如下

  1. 头文件contact.h:引入头文件,并声明通讯录的数据类型和函数声明
  2. 源文件contact.c:实现通讯录各个功能的函数
  3. 测试文件test.c:写有main函数,启动程序并实现业务逻辑

二、头文件

1. 头文件引用

#pragma once			//防止头文件重复引用
#include <stdio.h>		//标准输入输出,具体作用懂得都懂
#include <assert.h>		//我们会对每个函数内部的一些变量进行断言,方便我们调试
#include <string.h>		//我们会对字符串进行操作
#include <Windows.h>	//我们会执行一些命令行

2. 结构体声明

//定义变量最大数量
#define MAX_INFO 100	//100个联系人
#define MAX_NAME 20		//姓名占20字符
#define MAX_SEX 10		//性别占10字符
#define MAX_TEL 20		//电话占20字符
#define MAX_ADDR 50		//地址占50字符

//个人信息
typedef struct PeoInfo
{
	char name[MAX_NAME];	 //姓名
	char sex[MAX_SEX];		 //性别
	int age;				//年龄
	char tel[MAX_TEL];		 //电话
	char addr[MAX_ADDR];	 //地址
} PeoInfo;

//通讯录
typedef struct Contact
{
	PeoInfo data[MAX_INFO];	 //联系人
	int count;				//联系人数量
} Contact;

3. 函数声明

void menu();					// 菜单
void init(Contact* pc);			 // 初始化
void add(Contact* pc);			 // 添加
void del(Contact* pc);			 // 删除
void search(const Contact* pc);	  // 查寻
void alter(Contact* pc);		 // 修改
void sort(Contact* pc);			 // 排序
void show(const Contact* pc);	 // 展示

三、测试文件

当我们声明完变量和函数时,不要着急去实现函数,而是先构思好逻辑业务,构思好后再实现函数,边实现边调试,才能将BUG消灭到最初的时候

int main()
{
	Contact con;
	init(&con);

	menu();

	int chose = 0;
	do
	{
		printf("请输入您要进行的操作序号>");

		scanf("%d", &chose);

		system("cls");		//此时有一个清屏,让黑乎乎的界面更加美观,清完之后打印菜单,方便用户操作
		menu();

		switch (chose)
		{
		case 0:
			printf("欢迎下次光临!\n");
			return 0;
			break;

		case 1:
			add(&con);	//添加联系人
			break;

		case 2:
			del(&con);	//删除联系人
			break;

		case 3:
			search(&con);	//查找联系人
			break;

		case 4:
			alter(&con);	//修改联系人
			break;

		case 5:
			show(&con);		//展示所有联系人
			break;

		case 6:
			sort(&con);		//对联系人排序
			break;

		default:
			printf("输入错误,请重新输入\n");
			break;
		}
		
	} while (0 != chose);
	
	return 0;
}

四、源文件

1. 菜单

用于提示用户操作信息,一套printf输出行云流水直接操作。

void menu()
{
	printf("========================================\n");
	printf("==------------------------------------==\n");
	printf("==------  1.add       2.del     ------==\n");
	printf("==------  3.search    4.alter   ------==\n");
	printf("==------  5.show      6.sort    ------==\n");
	printf("==------        0.exst          ------==\n");
	printf("==------------------------------------==\n");
	printf("========================================\n");
}

2. 初始化

初始化通讯录,将数据内存内容全置为0,联系人数量置为0

//初始化
void init(Contact* pc)
{
	assert(pc != NULL);

	pc->count = 0;
	memset(pc, 0, sizeof(pc));	//将Contact内存设置为0
    
    //以下操作千万不要解除封印,不然会被开除的[狗头]
	/* 
	* //假装加载数据,显得有逼格
	* printf("正在加载通讯录......\n");
	* Sleep(5000);
	* printf("加载完毕,开始使用吧!!!\n");
	*/
}

3. 获取指定姓名的联系人下标

该函数会在查找、删除、修改联系人中使用,所以封装在一个函数,减少代码冗余

遍历查找联系人,并返回其下标,若是联系人不存在则返回-1

int getIndexByName(Contact* pc, const char* name)
{
	int i = 0;
	for (i = 0; i < pc->count; i++)
	{
		if (strcmp(pc->data[i].name, name) == 0)
		{
			return i;
		}
	}
	return -1;
}

4. 添加联系人

先判断通讯录满了,则不进行操作,提示“通讯录已满”,否则依次录入联系人信息

void add(Contact* pc)
{
	assert(pc != NULL);
	if (pc->count >= MAX_INFO)
	{
		printf("通讯录已满\n");
		return;
	}

	printf("请输入姓名>");
	scanf("%s", pc->data[pc->count].name);

	printf("请输入性别>");
	scanf("%s", pc->data[pc->count].sex);

	printf("请输入年龄>");
	scanf("%d", &(pc->data[pc->count].age));

	printf("请输入电话>");
	scanf("%s", pc->data[pc->count].tel);

	printf("请输入地址>");
	scanf("%s", pc->data[pc->count].addr);

	pc->count++;

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

5. 删除联系人

判断联系人是否为空,若是不为空,则查找指定姓名的联系人下标,并用后面的联系人覆盖掉他的信息,联系人的数量减一,若是该联系人不存在,则给出提示。

void del(Contact* pc)
{
	assert(pc != NULL);

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

	char name[20] = { 0 };

	printf("请输入删除信息的姓名>");
	scanf("%s", name);

	int i = getIndexByName(pc, name);

	if (i != -1)
	{
		for (i; i < pc->count - 1; i++)
		{
			memcpy(&(pc->data[i]), &(pc->data[i + 1]), sizeof(PeoInfo));
		}
		pc->count--;
		printf("删除成功\n");
	}
	else
	{
		printf("查无此人\n");
	}
}

6. 修改联系人

void alter(Contact* pc)
{
	assert(pc != NULL);
	if (pc->count == 0)
	{
		printf("通讯录为空\n");
		return;
	}

	char name[20] = { 0 };
	printf("请输入被修改联系人的姓名>");
	scanf("%s", name);

	int i = getIndexByName(pc, name);

	if (i != -1)
	{
		printf("请输入姓名>");
		scanf("%s", pc->data[i].name);

		printf("请输入性别>");
		scanf("%s", pc->data[i].sex);

		printf("请输入年龄>");
		scanf("%d", &(pc->data[i].age));

		printf("请输入电话>");
		scanf("%s", pc->data[i].tel);

		printf("请输入地址>");
		scanf("%s", pc->data[i].addr);

		printf("修改成功\n");
	}
	else
	{
		printf("查无此人\n");
	}
}

7. 查询联系人

根据姓名查询该联系人的所有信息

void search(const Contact* pc)
{
	assert(pc != NULL);

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

	char name[20] = { 0 };
	printf("请输入姓名>");
	scanf("%s", name);

	int i = getIndexByName(pc, name);
	if (i != -1)
	{
		printf("%-20s\t%-10s\t%-10s\t%-20s\t%-20s\n",
			"姓名", "性别", "年龄", "电话", "地址");
		printf("%-20s\t%-10s\t%-10d\t%-20s\t%-20s\n",
			pc->data[i].name, pc->data[i].sex, pc->data[i].age, pc->data[i].tel, pc->data[i].addr);
	}
	else
	{
		printf("查无此人\n");
	}
}

8. 联系人排序

我们调用库函数qsort帮助我们完成排序,在使用前我们先要实现两个联系人的比较规则,我们使用联系人姓名的升序作为排序规则

//比较规则
int cmp_info(const void* e1, const void* e2)
{
	return strcmp(((PeoInfo*)e1)->name, ((PeoInfo*)e2)->name);
}
 
// 排序
void sort(Contact* pc)
{
	assert(pc != NULL);

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

	qsort(pc->data, pc->count, sizeof(PeoInfo), cmp_info);
	printf("排序成功\n");
}

9. 展示所有联系人

利用printf函数中的字宽限制展示的字符串长度,并使其左对齐,每个字段用制表符隔开,每个联系人信息占一行

void show(const Contact* pc)
{
	assert(pc != NULL);

	printf("%-20s\t%-10s\t%-10s\t%-20s\t%-20s\n",
		"姓名", "性别", "年龄", "电话", "地址");
	int i = 0;
	for (i = 0; i < pc->count; i++)
	{
		printf("%-20s\t%-10s\t%-10d\t%-20s\t%-20s\n",
			pc->data[i].name, pc->data[i].sex, pc->data[i].age, pc->data[i].tel, pc->data[i].addr);
	}
}

五、程序演示

  1. 启动程序时我们需要输入操作

1

  1. 增加联系人时,我们输入操作1,再依次输入信息即可

2

  1. 删除联系人时,我们输入操作2,再输入要删除的联系人姓名,若是联系人存在,则删除成功

3

  1. 查找联系人时,我们输入操作3,再输入查找联系人的姓名,若是联系人存在,则显示他的所有信息

4

  1. 修改联系人时,输入操作4,再输入修改联系人的姓名,依次输入联系人信息,则修改成功

5

  1. 展示所有联系人时,输入操作5即可

6

  1. 将联系人排序时,输入操作6,然后我们再输入5查看排序结果

7

8

  1. 退出时我们输入操作0即可

9

六、完整代码

代码存储于gitee中:点击查看完整代码

相关文章:

  • 一年赚一百万的思路—别做大多数的傻瓜
  • Java基于JSP+Servlet的宠物养护网站
  • 【spring】一文读懂SpringIOC和AOP
  • 在Adult数据集上使用pandas进行独热编码,之后部署Logistic Reggresion模型
  • Dubbo分组聚合
  • 前端HTML5 +CSS3 3. HMTL基础 3 表单标签
  • 2022.9.1 SAP RFC
  • Dubbo初次使用(广播形式)
  • JSP汽车维修服务管理系统myeclipse开发SqlServer数据库bs框架java编程web网页结构
  • 【算法合集】学习算法第六天(贪心篇)
  • Nginx之正则表达式、location匹配简介及rewrite重写
  • 一文简单入门Node.js
  • 剑指offer专项 97-100笔记
  • Dubbo各种协议
  • 前端HTML5 +CSS3 2. HTML标签学习
  • (三)从jvm层面了解线程的启动和停止
  • canvas 高仿 Apple Watch 表盘
  • docker容器内的网络抓包
  • ES6 ...操作符
  • Meteor的表单提交:Form
  • Python3爬取英雄联盟英雄皮肤大图
  • Solarized Scheme
  • Spring声明式事务管理之一:五大属性分析
  • Sublime text 3 3103 注册码
  • Synchronized 关键字使用、底层原理、JDK1.6 之后的底层优化以及 和ReenTrantLock 的对比...
  • 给第三方使用接口的 URL 签名实现
  • 给新手的新浪微博 SDK 集成教程【一】
  • 计算机常识 - 收藏集 - 掘金
  • 前端存储 - localStorage
  • 设计模式 开闭原则
  • 通过npm或yarn自动生成vue组件
  • 我这样减少了26.5M Java内存!
  • 用Canvas画一棵二叉树
  • 怎么把视频里的音乐提取出来
  • - 转 Ext2.0 form使用实例
  • CMake 入门1/5:基于阿里云 ECS搭建体验环境
  • 如何在 Intellij IDEA 更高效地将应用部署到容器服务 Kubernetes ...
  • ​​​​​​​sokit v1.3抓手机应用socket数据包: Socket是传输控制层协议,WebSocket是应用层协议。
  • #{}和${}的区别?
  • #我与Java虚拟机的故事#连载02:“小蓝”陪伴的日日夜夜
  • (+4)2.2UML建模图
  • (03)光刻——半导体电路的绘制
  • (2)(2.10) LTM telemetry
  • (3)llvm ir转换过程
  • (aiohttp-asyncio-FFmpeg-Docker-SRS)实现异步摄像头转码服务器
  • (博弈 sg入门)kiki's game -- hdu -- 2147
  • (附源码)SSM环卫人员管理平台 计算机毕设36412
  • (数位dp) 算法竞赛入门到进阶 书本题集
  • (四)Controller接口控制器详解(三)
  • (一)80c52学习之旅-起始篇
  • (转)Android学习笔记 --- android任务栈和启动模式
  • (转)ObjectiveC 深浅拷贝学习
  • . ./ bash dash source 这五种执行shell脚本方式 区别
  • .NET Standard / dotnet-core / net472 —— .NET 究竟应该如何大小写?
  • .NET(C#、VB)APP开发——Smobiler平台控件介绍:Bluetooth组件