【初阶数据结构】通讯录项目(可用作课程设计)

news2024/9/20 6:30:36

文章目录

  • 概述
  • 1. 通讯录的效果
  • 2. SeqList.h
  • 3. Contact.h
  • 4. SeqList.c
  • 5. Contact.c
  • 6. test.c

概述

通讯录项目是基于顺序表这个数据结构来实现的。如果说数组是苍蝇小馆,顺序表是米其林的话,那么通讯录就是国宴。

换句话说,通讯录就是顺序表中存储结构体数据的。

那我在这里就给出所有的代码,具体细节这里就不再多说了,代码中都有注释。需要的可以自己复制粘贴。
哈哈

1. 通讯录的效果

添加数据
展示数据

修改数据
查找
删除数据
退出
至于功能6大家可以执行测试。

下面,我将分文件展示每个文件的所有代码,有需要的读者可以自行的拷贝。

文件

2. SeqList.h

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include"Contact.h"

typedef PeoInfo SLDataType;

typedef struct SeqList
{
	SLDataType* arr;
	int size; //有效的数据个数
	int capacity; //空间大小
}SL;

//打印顺序表中的数据
void SLPrint(SL s);

//顺序表的初始化
void SLInit(SL* ps);

//顺序表的销毁
void SLDestory(SL* ps);

//尾插
void SLPushBack(SL* ps, SLDataType x);

//头插
void SLPushFront(SL* ps, SLDataType x);

//尾删
void SLPopBack(SL* ps);

//头删
void SLPopFront(SL* ps);

//指定位置之前插入数据
void SLInsert(SL* ps, int pos, SLDataType x);

//删除指定位置的数据
void SLErase(SL* ps ,int pos);

//找到指定位置的数据
int SLFind(SL* ps, SLDataType x);

3. Contact.h

#include<string.h>

typedef struct PersonInfo
{
	char name[NAME_MAX]; //姓名
	char gender[GENDER_MAX]; //性别
	int age; //年龄
	char tel[TEL_MAX]; //电话
	char addr[ADDR_MAX]; //住址
}PeoInfo;

//核心:要用到顺序表的相关的方法,对通讯录的操作实际上就是对顺序表的操作
// 为了方便后面的操作,我们给顺序表起个别名为contact
//前置声明
//typedef SL contact;//这样写看似没有什么问题,但是你并编译之后就会发现一堆的报错
//原因在于,此操作为前置声明,就是在还未定义该结构之前,但是我要提前使用该声明就可以使用。
//适用场景为:多文件编写,头文件之间包含关系。
typedef struct SeqList contact;

//初始化通讯录
void InitContact(contact* con);
//添加通讯录数据
void AddContact(contact* con);
//删除通讯录数据
void DelContact(contact* con);
//展⽰通讯录数据
void ShowContact(contact* con);
//查找通讯录数据
void FindContact(contact* con);
//修改通讯录数据
void ModifyContact(contact* con);
//销毁通讯录数据
void DestroyContact(contact* con);
//保存通讯录数据到文件中
void SaveContact(contact* con);

4. SeqList.c

#define _CRT_SECURE_NO_WARNINGS	
#include"SeqList.h"

void SLInit(SL* ps)
{
	ps->arr = NULL;
	ps->size = ps->capacity = 0;
}

void SLDestory(SL* ps)
{
	if (ps->arr) //相当于ps->arr != NULL
	{
		free(ps->arr);
	}

	ps->arr = NULL;
	ps->size = ps->capacity = 0;
}

//void SLPrint(SL s)
//{
//	int i = 0;
//	for (i = 0; i < s.size; i++)
//	{
//		printf("%d ",s.arr[i]);
//	}
//	printf("\n");
//}

void SLCheckCapacity(SL* ps)
{
	if (ps->capacity == ps->size)
	{
		//空间不够用,扩容
		SL* tmp = NULL;
		int newscapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
		tmp = (SL*)realloc(ps->arr, newscapacity * sizeof(SLDataType));

		if (tmp == NULL)
		{
			perror("realloc fail");
			exit(EXIT_FAILURE);
		}

		//扩容成功
		ps->arr = tmp;
		ps->capacity = newscapacity;
	}
}

void SLPushBack(SL* ps, SLDataType x)
{
	assert(ps);
	//在这之前得先判断,可用空间与有效数据个数之间的关系
	SLCheckCapacity(ps);

	ps->arr[ps->size++] = x;
}


void SLPushFront(SL* ps, SLDataType x)
{
	assert(ps);

	SLCheckCapacity(ps);

	//第一步:要把所有的数据都往后挪动一位
	int i = 0;
	for (i = ps->size; i > 0; i--)
	{
		ps->arr[i] = ps->arr[i - 1];
	}
	//第二步:将数据插入到头部
	ps->arr[0] = x;
	//第三步:更新有效数据的个数
	ps->size++;
}


void SLPopBack(SL* ps)
{
	assert(ps);
	assert(ps -> arr);

	//这里通过ps->size的关系就可以直接控制,不再访问这个数据,也就是删除了
	ps->size--;
}


void SLPopFront(SL* ps)
{
	assert(ps);
	assert(ps->arr);

	int i = 0;
	//用后一个数据覆盖前一个数据,从第一个数据开始
	for (i = 0; i < ps->size-1; i++)
	{
		ps->arr[i] = ps->arr[i + 1];
	}
	//更新有效数据个数
	ps->size--;
}

void SLInsert(SL* ps, int pos, SLDataType x)
{
	assert(ps);

	SLCheckCapacity(ps);

	int i = 0;
	for (i = ps->size; i > pos; i--)
	{
		ps->arr[i] = ps->arr[i - 1];
	}

	ps->arr[pos] = x;

	ps->size++;
}


void SLErase(SL* ps, int pos)
{
	assert(ps);
	assert(ps->arr);

	int i = 0;
	for (i = pos; i < ps->size - 1; i++)
	{
		ps->arr[i] = ps->arr[i + 1];
	}

	ps->size--;
}

5. Contact.c

#define _CRT_SECURE_NO_WARNINGS	
#include"SeqList.h"
#include"Contact.h"

void InitContact(contact* con)
{
	SLInit(con);
}

void AddContact(contact* con) //尾插
{
	assert(con);
	PeoInfo pefo;

	printf("请输入姓名:\n");
	scanf("%s",pefo.name);

	printf("请输入性别:\n");
	scanf("%s", pefo.gender);

	printf("请输入年龄:\n");
	scanf("%d", &pefo.age);

	printf("请输入电话:\n");
	scanf("%s", pefo.tel);

	printf("请输入住址:\n");
	scanf("%s", pefo.addr);

	//复用顺序表的方法
	SLPushBack(con,pefo);
	printf("数据已经成功添加!\n");
}

int Find(contact* con,PeoInfo pefo)
{
	int i = 0;
	for (i = 0; i < con->size; i++)
	{
		if (!strcmp(con->arr[i].tel, pefo.tel))
		{
			return i;
		}
	}

	return -1;
}

void DelContact(contact* con)
{
	assert(con);
	PeoInfo pefo;
	printf("请输入想要删除联系人的电话:\n");
	scanf("%s",pefo.tel);

	int find = Find(con, pefo);

	if (find < 0)
	{
		//没有找到
		printf("要删除的数据已经不存在\n");
		return;
	}

	//找到了
	SLErase(con,find);
	printf("数据已经删除\n");
}


void ShowContact(contact* con)
{
	printf("姓名\t性别\t年龄\t电话\t住址\n");

	for (int i = 0; i < con->size; i++)
	{
		printf("%s\t", con->arr[i].name); //姓名

		printf("%s\t", con->arr[i].gender); //性别

		printf("%d\t", con->arr[i].age); //年龄

		printf("%s\t", con->arr[i].tel); //电话

		printf("%s\t", con->arr[i].addr); //住址

		printf("\n");
	}

}


void FindContact(contact* con)
{
	PeoInfo pefo;
	printf("请输入要查找通讯人的电话:\n");
	scanf("%s",pefo.tel);

	int find = Find(con, pefo);

	if (find < 0)
	{
		printf("要查找的联系人数据不存在\n");
		return;
	}
	//找到了
	printf("姓名\t性别\t年龄\t电话\t住址\n");

	printf("%s\t", con->arr[find].name); //姓名

	printf("%s\t", con->arr[find].gender); //性别

	printf("%d\t", con->arr[find].age); //年龄

	printf("%s\t", con->arr[find].tel); //电话

	printf("%s\t", con->arr[find].addr); //住址

	printf("\n");
	
}


void ModifyContact(contact* con)
{
	assert(con);
	PeoInfo pefo;
	printf("请输入要修改联系人的姓名:\n");
	scanf("%s",pefo.name);

	int i = 0;
	for (i = 0; i < con->size; i++)
	{
		if (!strcmp(con->arr[i].name, pefo.name))
		{
			//匹配
			printf("请输入姓名:\n");
			scanf("%s", con->arr[i].name);

			printf("请输入性别:\n");
			scanf("%s", con->arr[i].gender);

			printf("请输入年龄:\n");
			scanf("%d", &con->arr[i].age);

			printf("请输入电话:\n");
			scanf("%s", con->arr[i].tel);

			printf("请输入住址:\n");
			scanf("%s", con->arr[i].addr);

			break;
		}

	}

	if (i == con->size)
	{
		printf("被修改的数据不存在\n");
	}
	
}


void DestroyContact(contact* con)
{
	assert(con);
	SLDestory(&con);
}


void SaveContact(contact* con)
{
	assert(con);
	int i = 0;
	//打开文件
	FILE* fp = fopen("contact.txt","w");
	if (fp == NULL)
	{
		perror("fopen fail");
		exit(1);
	}

	//写文件
	fprintf(fp,"姓名\t性别\t年龄\t电话\t住址\n");
	for (i = 0; i < con->size; i++)
	{
		fprintf(fp,"%s\t%s\t%d\t%s\t%s\n",
									con->arr[i].name,
									con->arr[i].gender, 
									con->arr[i].age, 
									con->arr[i].tel, 
									con->arr[i].addr );
	}

	printf("数据已经安全存储\n");
	//关闭文件
	fclose(fp);
	fp = NULL;
}

6. test.c

#include"SeqList.h"
void meun()
{
	printf("*********************************************\n");
	printf("****************   通讯录   *****************\n");
	printf("******* 1.添加联系人   2.删除联系人 *********\n");
	printf("******* 3.修改联系人   4.查找联系人 *********\n");
	printf("******* 5.展示通讯录   6.保存数据   *********\n");
	printf("*******           0.退出            *********\n");
	printf("*********************************************\n");
	

}

int main()
{
	int input = 0;
	contact con;
	InitContact(&con);
	do 
	{
		meun();

		printf("请输入你的操作:\n");
		scanf("%d", &input);

		switch (input)
		{
		case 1:
			AddContact(&con);
			break;
		case 2:
			DelContact(&con);
			break;
		case 3:
			ModifyContact(&con);
			break;
		case 4:
			FindContact(&con);
			break;
		case 5:
			ShowContact(&con);
			break;
		case 6:
			SaveContact(&con);
			break;
		case 0:
			printf("程序已安全退出!\n");
			break;
		default:
			printf("输入错误,请重新输入\n");
			break;
		}
	} while (input);


	return 0;
}

以上就是本次通讯录的全部代码了,如果又不理解的地方,可以在评论区提问。

最后,觉得本文写的不错的话,别忘了给偶点赞哦!
哈哈

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

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

相关文章

pycharm windows/mac 指定多版本python

一、背景 工作中经常会使用不同版本的包&#xff0c;如同时需要tf2和tf1&#xff0c;比较新的tf2需要更高的python版本才能安装&#xff0c;而像tf1.5 需要低版本的python 才能安装&#xff08;如 python3.6&#xff09;,所以需要同时安装多个版本。 二、安装多版本python py…

会员系统开发,检测按钮位置,按钮坐标,弹出指定位置对话框-SAAS 本地化及未来之窗行业应用跨平台架构

一 获取元素坐标 var 按钮_obj document.querySelector(#未来之窗玄武id);var 按钮_rect 按钮_obj.getBoundingClientRect()console.log(按钮_rect);输出结果 bottom : 35 height : 21 left : 219.921875 right : 339.921875 top : 14 width : 120 x : 219.921875 y…

R语言统计分析——组间差异的非参数检验

参考资料&#xff1a;R语言实战【第2版】 如果数据无法满足t检验或ANOVA的参数假设&#xff0c;可以转而使用非参数检验。举例来说&#xff0c;若结果变量在本质上就严重偏倚或呈现有序关系&#xff0c;那么可以考虑非参数检验。 1、两组的比较 若两组数据独立&#xff0c;可以…

大厂进阶五:React源码解析之Diff算法

本文主要针对React源码进行解析&#xff0c;内容有&#xff1a; 1、Diff算法原理、两次遍历 一、Diff源码解析 以下是关于 React Diff 算法的详细解析及实例&#xff1a; 1、React Diff 算法的基本概念和重要性 1.1 概念 React Diff 算法是 React 用于比较虚拟 DOM 树之间…

初识C++ · 类型转换

目录 前言&#xff1a; 1 C中的类型转换 1.1 static_cast 1.2 reinterpret_cast 1.3 const_cast 1.4 dynamic_cast 前言&#xff1a; C可以说是恨死了隐式类型转换&#xff0c;你可能会疑问了&#xff0c;为什么&#xff1f;不是单参数隐式类型转换为自定义类型的时候人…

苹果笔记本电脑可以玩steam游戏吗 MacBook支持玩steam游戏吗 在Steam上玩黑神话悟空3A大作 苹果Mac怎么下载steam

游戏是生活的润滑剂&#xff0c;越来越多的用户开始关注Mac平台上可玩的游戏。幸运的是&#xff0c;Steam作为最大的数字发行平台之一&#xff0c;提供了大量适用于Mac操作系统的游戏。无论你是喜欢策略、冒险还是射击类游戏&#xff0c;都能在Steam上找到适合自己Mac设备玩耍的…

ESP32CAM人工智能教学18

ESP32CAM人工智能教学18 获取数据并显示 如果我们给ESP32Cam外挂一些传感器&#xff08;比如温湿度传感器、超声波测距传感器、红外人体传感器等&#xff09;&#xff0c;我们怎么把ESP32Cam捕获到的数据&#xff0c;传递到客户端的浏览器&#xff0c;并在网页index.html中显示…

WordPress网站速度优化

提升网站速度对用户体验和搜索引擎排名至关重要。无论你是新手博主&#xff0c;还是经验丰富的网站开发人员&#xff0c;要想优化WordPress网站&#xff0c;需要长时间的努力和坚持。以下是按入门、中级和专家级别介绍的12个实用方法&#xff0c;帮助你提升WordPress网站的整体…

zabbix监控进程,日志,主从状态和主从延迟

自定义监控进程 使用httpd服务为例&#xff0c;监控httpd的进程 在zabbix-agent上安装httpd yum -y install httpd 重启httpd systemctl restart httpd systemtctl enable httpd 查看httpd的进程 [rootzabbix-agent ~]# ps -ef | grep httpd root 2407458 1 0 16:…

soapui调用接口参数传递嵌套xml,多层CDATA表达形式验证

1.环境信息 开发工具&#xff1a;idea 接口测试工具&#xff1a;soapui 编程语言&#xff1a;java 项目环境&#xff1a;jdk1.8 webservice&#xff1a;jdk自带的jws 处理xml&#xff1a;jdk自带的jaxb 2.涉及代码 package org.example.webdemo;import javax.jws.WebMethod; i…

Python,Spire.Doc模块,处理word、docx文件,极致丝滑

Python处理word文件&#xff0c;一般都是推荐的Python-docx&#xff0c;但是只写出一个&#xff0c;一句话的文件&#xff0c;也没有什么样式&#xff0c;就是36K。 再打开word在另存一下&#xff0c;就可以到7-8k&#xff0c;我想一定是python-docx的问题&#xff0c;但一直没…

汽车免拆诊断案例 | DAF(达富)汽油尾气处理液故障警示

故障现象 距离我上次在货卡上工作已经有一段时间了&#xff0c;让它们在道路上保持安全行驶是非常重要的。因此&#xff0c;当故障警示灯亮起时&#xff0c;我们需要迅速找到问题方向以及排除故障。 车辆的仪表板亮起多个故障灯以及警示灯&#xff0c;我们需要用解码器查找触…

数据分析与应用:微信-情人节红包流向探索分析

目录 0 需求描述 1 红包发送方用户的基本信息缺失率有多高?(即有多少红包发送方用户无法在用户基本信息表中匹配? 2 哪一组红包金额的拒收率最高? 3、最受二线城市欢迎的红包金额为?(即发出次数最多) 4 北上广深 4 大城市中,哪座城市的男性用户发出的 520 红包比例…

《密码编码学与网络安全原理与实践》第十四章第十五章密钥管理和用户认证

密钥管理与分发 密钥分发管理 传统上&#xff0c;对称加密被用于实现消息的保密性&#xff08;confidentiality&#xff09; 面临的攻击&#xff1a;局域网内监听、搭线窃听 传输媒介&#xff1a;线缆(双绞线、同轴电缆、光纤) (电磁波干扰)、微波链路、卫星信道 保密通信…

windows11-ubuntu-可爱的截图-启动时按F2可以选简体中文

windows11-ubuntu-可爱的截图-启动时按F2可以选简体中文

c++ 46 const

const伪命题 可以间接修改

Java-自定义注解中成员变量是Class<?>

在Java中,自定义注解可以包含各种类型的成员变量,包括 Class<?> 类型。这种类型的成员变量 通常用于表示某个类的类型信息。下面我将详细介绍如何定义一个包含 Class<?> 类型成员变量的 自定义注解,并给出一些示例代码。 1. 定义自定义注解 定义一个自定义…

jmeter使用while控制器时防止死循环

while 控制器&#xff1a;当前条件为true会一直循环&#xff0c;直到条件为false时退出循环 如果环境出现问题&#xff0c;可能导致死循环&#xff0c;需要进行设置 本次结合计时器进行组合配置&#xff0c;防止死循环 配置while控制器 条件&#xff1a;${__jexl3("${i…

libnl教程(2):发送请求

文章目录 前言示例示例代码构造请求创建套接字发送请求 简化示例 前言 前置阅读要求&#xff1a;libnl教程(1):订阅内核的netlink广播通知 本文介绍&#xff0c;libnl如何向内核发送请求。这包含三个部分&#xff1a;构建请求&#xff1b;创建套接字&#xff1b;发送请求。 …

milvus helm k8s开启监控

https://milvus.io/docs/monitor.md 文章写的很清晰 &#xff0c;我这边做一下个人补充&#xff0c;初版可能只是配置&#xff0c;具体的grafana 监控报表后期补一下。 架构如下&#xff1a; values.yaml 配置 enabled: true 改为true metrics:enabled: trueserviceMonitor:…