基于动态顺序表实现通讯录项目

news2024/11/18 14:28:59

 本文中,我们将使用顺序表的结构来完成通讯录的实现。

我们都知道,顺序表实际上就是一个数组。而使用顺序表来实现通讯录,其内核是将顺序表中存放的数据类型改为结构体,将联系人的信息存放到结构体中,通过对顺序表的操作来访问通讯录。

所以我们可以将通讯录理解为套壳的顺序表。

一、功能

(1)能够保存联系人的姓名、年龄、性别、电话、住址

(2)添加联系人信息

(3)删除联系人信息

(4)修改联系人信息

(5)查找联系人信息

(6)查看通讯录中所有联系人信息

(7)清空通讯录

(8)每次加载通讯录时自动载入历史通讯录,退出通讯录后自动保存通讯录信息

二、代码实现

实现通讯录我们要创建6个文件来实现不同的部分

  • SeqList.h:顺序表定义、头文件引用和顺序表接口函数的声明
  • SeqList.c:顺序表接口函数的实现
  • Contact.h:信息结构体的定义和通讯录函数的声明
  • Contact.c:通讯录函数的实现
  • test.c:界面设计和通讯录主函数实现
  • contact.txt:在同目录下创建,用来保存通讯录数据实现读档存档

(1) SeqList.h 

在实现通讯录函数的时候我们可以套用顺序表的接口函数减少工作量,但是并不是所有顺序表的函数都会用到。下面展示SeqList.h的代码:

#pragma once

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <Windows.h>
#include "Contact.h"

typedef Info SLDataType; //顺序表元素种类为存放个人信息的结构体

typedef struct SeqList
{
    SLDataType* a;
    size_t size;
    size_t capicity;
} SeqList;

// 顺序表初始化
void SeqListInit(SeqList* psl);
// 检查空间,如果满了,进行增容
void CheckCapacity(SeqList* psl);
// 顺序表尾插
void SeqListPushBack(SeqList* psl, SLDataType x);
// 顺序表删除pos位置的值
void SeqListErase(SeqList* psl, size_t pos);
// 顺序表销毁
void SeqListDestory(SeqList* psl);

(2) SeqList.c 

SeqList.c的代码如下:

#include "SeqList.h"

void SeqListDestory(SeqList* psl)
{
    assert(psl);
    free(psl->a);
    psl->a = NULL;
    psl->capicity = 0;
    psl->size = 0;
}

void SeqListInit(SeqList* psl)
{
    assert(psl);
    psl->a = (SLDataType*)malloc(sizeof(SLDataType) * 4);
    if (psl->a == NULL)
    {
        perror("malloc fail");
        return;
    }
    psl->size = 0;
    psl->capicity = 4;
}

void CheckCapacity(SeqList* psl)
{
    assert(psl);
    if (psl->size == psl->capicity)
    {
        SLDataType* tmp = (SLDataType*)realloc(psl->a, sizeof(SLDataType) * psl->capicity * 2);
        if (tmp == NULL)
        {
            perror("realloc fail");
            return;
        }
        psl->a = tmp;
        psl->capicity *= 2;
    }
}

void SeqListPushBack(SeqList* psl, SLDataType x)
{
    assert(psl);
    CheckCapacity(psl);
    psl->a[psl->size++] = x;
}

void SeqListErase(SeqList* psl, size_t pos)
{
    assert(psl);
    assert(0 <= pos && pos < psl->size);
    while (pos < psl->size - 1)
    {
        psl->a[pos] = psl->a[pos + 1];
        pos++;
    }
    psl->size--;
}

因为二者在前面的顺序表学习中已经写过了,所以直接cv即可

(3) test.c

在实现通讯录函数之前,我们先把通讯录界面和主函数搞定

创建好test.c后,先包含一下头文件

#include "SeqList.h"

再设计一下界面

#include "SeqList.h"

void Menu()
{
	printf("****************通讯录******************\n");
	printf("****** 1.添加联系人  2.删除联系人 ******\n");
	printf("****** 3.修改联系人  4.查找联系人 ******\n");
	printf("****** 5.查看通讯录  6.清空通讯录 ******\n");
	printf("****** 0.退出通讯录               ******\n");
	printf("****************************************\n");
}

主函数如下:

int main()
{
	contact con;
	InitContact(&con); //初始化通讯录
	LoadContact(&con); //加载历史通讯录
	int option = -1;
	do {
		Menu();
		printf("请选择:\n");
		scanf("%d", &option);
		system("cls"); //适当的清屏看起来更简洁
		switch (option)
		{
		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:
			//清空通讯录
			ClearContact(&con);
			break;
		case 0:
			//退出通讯录
			printf("通讯录退出中...\n");
			break;
		default:
			printf("非法操作,请重新输入\n");
			break;
		}
	} while (option);
	SaveContact(&con); //保存通讯录
	DestoryContact(&con); //销毁通讯录
	return 0;
}

(4) Contact.h

界面和主函数都搞定后,我们开始完成通讯录函数并逐个填空到主函数中

下面是Contact.h的代码

#pragma once

#define NAME_MAX 100
#define GENDER_MAX 10
#define TEL_MAX 11
#define ADDR_MAX 100

struct SqeList; 
//因为这里不能声明SeqList.h,不然会造成嵌套声明,所以就单独声明一下顺序表

typedef struct SeqList contact;
//要实现的是通讯录,所以得把顺序表换个名,但换汤不换药

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

void InitContact(contact* pcon);//初始化通讯录

void DestoryContact(contact* pcon);//销毁通讯录

int FindByName(contact* pcon, char* name);//通过姓名查找联系人

void AddContact(contact* pcon);//添加联系人

void DelContact(contact* pcon);//删除联系人

void ModifyContact(contact* pcon);//修改联系人信息

void FindContact(contact* pcon);//查找联系人

void ShowContact(contact* pcon);//展示联系人列表

void ClearContact(contact* pcon);//清空通讯录

void SaveContact(contact* pcon);//保存通讯录

void LoadContact(contact* pcon);//载入历史通讯录

(5) Contact.c

接下来我们展示Contact.c的完整代码

#include "SeqList.h"

void InitContact(contact* pcon)//初始化通讯录
{
	SeqListInit(pcon);
}

void DestoryContact(contact* pcon)//销毁通讯录
{
	SeqListDestory(pcon);
}

int FindByName(contact* pcon, char* name)//通过姓名查找联系人
{
	for (size_t i = 0; i < pcon->size; i++)
	{
		if (strcmp(name, pcon->a[i].name) == 0)
		{
			return i;
		}
	}
	return -1;
}

void AddContact(contact* pcon)//添加联系人
{
	CheckCapacity(pcon);

	printf("请输入姓名:\n");
	scanf("%s", pcon->a[pcon->size].name);
	printf("请输入年龄:\n");
	scanf("%d", &(pcon->a[pcon->size].age));
	printf("请输入性别:\n");
	scanf("%s", pcon->a[pcon->size].gender);
	printf("请输入电话:\n");
	scanf("%s", pcon->a[pcon->size].telephone);
	printf("请输入住址:\n");
	scanf("%s", pcon->a[pcon->size].address);

	pcon->size++;

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

void DelContact(contact* pcon)//删除联系人
{
	char name[100];
	printf("请输入要删除的联系人:\n");
	scanf("%s", name);

	int index = FindByName(pcon, name);
	if (index == -1)
	{
		printf("要删除的用户不存在!\n");
		return;
	}
	SeqListErase(pcon, index);

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

void ModifyContact(contact* pcon)//修改联系人信息
{
	char name[100];
	printf("请输入要修改的联系人:\n");
	scanf("%s", name);

	int index = FindByName(pcon, name);
	if (index == -1)
	{
		printf("要修改的用户不存在!\n");
		return;
	}

	printf("请输入修改后的姓名:\n");
	scanf("%s", pcon->a[index].name);
	printf("请输入修改后的年龄:\n");
	scanf("%d", &(pcon->a[index].age));
	printf("请输入修改后的性别:\n");
	scanf("%s", pcon->a[index].gender);
	printf("请输入修改后的电话:\n");
	scanf("%s", pcon->a[index].telephone);
	printf("请输入修改后的住址:\n");
	scanf("%s", pcon->a[index].address);

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

void FindContact(contact* pcon)//查找联系人
{
	char name[100];
	printf("请输入要查找的联系人:\n");
	scanf("%s", name);

	int index = FindByName(pcon, name);
	if (index == -1)
	{
		printf("要查找的用户不存在!\n");
		return;
	}

	system("cls");

	printf("查找成功!\n");
	printf("姓名:%s\n", pcon->a[index].name);
	printf("年龄:%d\n", pcon->a[index].age);
	printf("性别:%s\n", pcon->a[index].gender);
	printf("电话:%s\n", pcon->a[index].telephone);
	printf("住址:%s\n", pcon->a[index].address);
}

void ShowContact(contact* pcon)//展示联系人列表
{
	if (pcon->size == 0)
	{
		printf("通讯录为空!\n");
		return;
	}
	printf("姓名 年龄 性别 电话 地址\n");
	for (size_t i = 0; i < pcon->size; i++)
	{
		printf("%s %d %s %s %s\n",
			pcon->a[i].name,
			pcon->a[i].age,
			pcon->a[i].gender,
			pcon->a[i].telephone,
			pcon->a[i].address);
	}
}

void ClearContact(contact* pcon)//清空通讯录
{
	pcon->size = 0;
	printf("通讯录清空成功!\n");
}

void SaveContact(contact* pcon)//保存通讯录
{
	FILE* pf = fopen("contact.txt", "wb");
	if (pf == NULL)
	{
		perror("fopen fail");
		return;
	}
	for (size_t i = 0; i < pcon->size; i++)
	{
		fwrite(pcon->a + i, sizeof(Info), 1, pf);
	}
	printf("通讯录数据保存成功!\n");
	fclose(pf);
}

void LoadContact(contact* pcon)//载入历史通讯录
{
	FILE* pf = fopen("contact.txt", "rb");
	if (pf == NULL)
	{
		perror("fopen fail");
		return;
	}
	Info info;
	while (fread(&info, sizeof(Info), 1, pf))
	{
		SeqListPushBack(pcon, info);
	}
	printf("通讯录数据载入成功!\n");
	fclose(pf);
}

三、测试

(1)添加联系人

选择功能

 输入联系人信息

我们查看通讯录检查一下是否真的添加成功

按照同样的步骤再添加一个联系人试试

(2)删除联系人

选择功能

输入要删除的联系人姓名

检查一下

确实删除了

(3)修改联系人

选择功能

输入要修改的联系人姓名

输入修改后的信息 

修改成功,我们检查一下

(4)查找联系人

选择功能,输入要查找的联系人姓名

(5)清空通讯录

我们试着多添加几个联系人

现在通讯录中有5个联系人,我们选择清空通讯录

再查看通讯录

(6)通讯录读档和存档

向通讯录中添加几个联系人

选择退出通讯录

 重新打开程序,选择查看通讯录,发现之前的联系人仍在通讯录中

完.

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

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

相关文章

GO 中高效 int 转换 string 的方法与高性能源码剖析

文章目录 使用 strconv.Itoa使用 fmt.Sprintf使用 strconv.FormatIntFormatInt 深入剖析1. 快速路径处理小整数2. formatBits 函数的高效实现 结论 Go 语言 中&#xff0c;将整数&#xff08;int&#xff09;转换为字符串&#xff08;string&#xff09;是一项常见的操作。 本文…

数据库-数据库分类

数据库可以分为关系型数据库和非关系型数据库&#xff0c;常见的数据库如下 关系型数据库 关系型数据库是一种采用关系模型来组织数据的数据库&#xff0c;它以行和列的形式存储数据&#xff0c;以便于用户理解。关系型数据库中的数据以二维表的形式组织&#xff0c;被称为表…

从零开始c++精讲:第三篇——内存管理

文章目录 一、C/C内存分布二、C语言中动态内存管理方式:malloc/calloc/realloc/free三、C中动态内存管理四、operator new与operator delete函数4.1 operator new与operator delete函数&#xff08;重点&#xff09; 五、new和delete的实现原理5.1内置类型5.2 自定义类型 六、定…

C++总结笔记

1. 简介 1、面向对象程序设计 面向对象的四大特性 1&#xff09;封装 2&#xff09;继承 3&#xff09;多态 4&#xff09;抽象 2、标准库 标准C由三个部分组成 1&#xff09;核心语言&#xff1a;提供了所有的构件块 2&#xff09;C标准库&#xff1a;提供了大量的函…

web蓝桥杯真题--11、蓝桥知识网

介绍 蓝桥为了帮助大家学习&#xff0c;开发了一个知识汇总网站&#xff0c;现在想设计一个简单美观的首页。本题请根据要求来完成一个首页布局。 准备 开始答题前&#xff0c;需要先打开本题的项目代码文件夹&#xff0c;目录结构如下&#xff1a; ├── css │ └──…

浅谈ARP协议

ARP是 address resolution protocol的缩写&#xff0c;意思是地址解析协议&#xff0c;处于OSI七层模型的网络层&#xff0c;它的作用是根据Ip地址找到mac地址&#xff0c;实际上我们需要访问某一个ip时&#xff0c;是要先找到它的mac地址&#xff0c;也就是物理地址才行的&…

Windows系统下使用docker-compose安装mysql8和mysql5.7

windows环境搭建专栏&#x1f517;点击跳转 win系统环境搭建&#xff08;十四&#xff09;——Windows系统下使用docker安装mysql8和mysql5.7 文章目录 win系统环境搭建&#xff08;十四&#xff09;——Windows系统下使用docker安装mysql8和mysql5.7MySQL81.新建文件夹2.创建…

C++播放音乐:使用EGE图形库

——开胃菜&#xff0c;闲话篓子一大片 最近&#xff0c;我发现ege图形库不是个正经的图形库—— 那天&#xff0c;我又在打趣儿地翻代码时&#xff0c;无意间看到了这个&#xff1a; 图形库&#xff1f;&#xff01;你哪来的音乐&#xff08;Music&#xff09;呢&#xff1f…

【蓝桥备赛】求阶乘

题目链接 求阶乘 个人想法 之前做过计算阶乘结果后面有几个0的题目&#xff0c;这里看到本题之后&#xff0c;很快就有思路了。想要得到阶乘结果有几个0&#xff0c;首先尾数后面的0&#xff0c;最小肯定是因为因子中存在10。然后&#xff0c;10如何得来呢&#xff1f; 2 * …

【LeetCode】141. 环形链表

leetcode题目链接 141. 环形链表 #include <stdio.h> #include <stdbool.h>struct ListNode {int val;struct ListNode* next; }; typedef struct ListNode ListNode;bool hasCycle(ListNode* head) {ListNode* slow head, * fast head;while (fast &&…

SpringBoot 3.1.7 集成Mybatis

一、介绍 Mybatis的中文官网并没找到与SpringBoot最新的集成的教程&#xff0c;有的都是老式的配置方法&#xff0c;所以记录一下怎么我是怎么集成SpringBoot 3.1.7 集成Mybatis 的方法 有条件的可以打开源网站 https://github.com/mybatis/spring-boot-starter 没有条件的我…

一款满足基层医疗机构各类业务需要的:健康云HIS系统源码,功能包括病患问诊、电子病历、开药发药、住院管理、护理文书、病案管理等功能。

一款满足基层医疗机构各类业务需要的健康云HIS系统。该系统能帮助基层医疗机构完成日常各类业务&#xff0c;提供病患挂号支持、病患问诊、电子病历、开药发药、会员管理、护理文书、病案管理、统计查询、医生站和护士站等一系列常规功能&#xff0c;能与公卫、PACS等各类外部系…

C++-类和对象(3)

1. 再谈构造函数 1.1 构造函数体赋值 我们在创建一个对象时&#xff0c;编译器会调用该对象的构造函数对该对象的成员进行初始化。 class Date { public:Date(int year, int month, int day){_year year;_month month;_day day;} private:int _year;int _month;int _day…

通过代理如何调通openai的api

调通openai的api 一、前提二、通过curl调通openai的api三、通过python调通openai的api 一、前提 会魔法上网本地运行代理软件&#xff0c;知道端口号&#xff08;如1081&#xff09;。 127.0.0.1:1081二、通过curl调通openai的api 如果在国外&#xff0c;没有qiang&#xff…

AWS 专题学习 P7 (FSx、SQS、SNS)

文章目录 Amazon FSx – 概述Amazon FSx for LustreFSx Lustre - 文件系统部署选项 Amazon FSx for NetApp ONTAPAmazon FSx for OpenZFSHybrid Cloud 存储AWS 存储云原生选项AWS 存储网关Amazon S3 File GatewayAmazon FSx File GatewayVolume GatewayTape GatewayStorage Gat…

设计一个Key-Value缓存去存储最近的Web Server查询的结果

1: 定义Use Case和约束 Use Cases 我们可以定义如下 Scope: User 发送一个 search request, 缓存命中成功返回DataUser 发送一个 search request, 缓存未命中&#xff0c;未成功返回DataService 有高可用 约束和假设 状态假设 Traffic 分布不是均匀的 热度高的查询总是被…

HarmonyOS鸿蒙学习基础篇 - 什么是HarmonyOS

概述 HarmonyOS是华为开发的一款面向未来的全场景分布式智慧操作系统&#xff0c;将逐步覆盖18N全场景终端设备&#xff1b; 对消费者而言 HarmonyOS用一个‘统一的软件系统’ 从根本上解决消费者面对大量智能终端体验割裂的问题&#xff0c;为消费者带来同意便利安全的智慧化全…

使用 Python 创造你自己的计算机游戏(游戏编程快速上手)第四版:第十五章到第十八章

十五、反转棋游戏 原文&#xff1a;inventwithpython.com/invent4thed/chapter15.html 译者&#xff1a;飞龙 协议&#xff1a;CC BY-NC-SA 4.0 在本章中&#xff0c;我们将制作反转棋&#xff0c;也称为黑白棋或奥赛罗。这个双人棋盘游戏是在网格上进行的&#xff0c;因此我们…

【Qt5】QString的成员函数trimmed

2024年1月19日&#xff0c;周五下午 QString 的 trimmed 方法是用于移除字符串两端的空白字符&#xff08;空格、制表符、换行符等&#xff09;的方法。它返回一个新的字符串&#xff0c;该字符串是原始字符串去除两端空白后的结果。 下面是一个简单的示例&#xff1a; #incl…

【Linux 内核源码分析】堆内存管理

堆 堆是一种动态分配内存的数据结构&#xff0c;用于存储和管理动态分配的对象。它是一块连续的内存空间&#xff0c;用于存储程序运行时动态申请的内存。 堆可以被看作是一个由各个内存块组成的堆栈&#xff0c;其中每个内存块都有一个地址指针&#xff0c;指向下一个内存块…