用c语言实现通讯录

2024-06-01 15:12
文章标签 语言 实现 通讯录

本文主要是介绍用c语言实现通讯录,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

静态简易通讯录

代码:

功能模块展示:

设计思路:

动态简易通讯录(本质顺序表)

代码:

扩容模块展示:

设计思路:

文件版本通讯录

代码:

文件模块展示:

设计思路:


静态简易通讯录

代码:

//头文件内容#pragma once#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <stdlib.h>//声明一个枚举类型增加主程序代码(switch部分)可读性
enum method
{EXIT,ADD,DELETE,FIND,MODIFY,SHOW,DESTROY,SORT
};//定义标识符常量便于对数据大小修改
#define  MAX_NAME 20
#define  MAX_SEX 6
#define  MAX_TELEPHONE 12
#define  MAX_ADDRESS 20
#define  Max_PEOINFO 1000//定义一个联系人信息结构体类型
typedef struct PeoInfo
{char name[MAX_NAME];char sex[MAX_SEX];int age;char Telephone[MAX_TELEPHONE];char address[MAX_ADDRESS];
}PeoInfo;//创建一个联系人信息结构体数组和计数联系人个数的变量组成联系人结构体
typedef struct Contact
{PeoInfo data[Max_PEOINFO];int sz;
}Contact;//初始化通讯录
void InitContact(Contact* pc);//增加联系人函数
void AddContact(Contact* pc);//展示所有联系人函数
void ShowContact(Contact* pc);//删除联系人函数
void DeleteContact(Contact* pc);//查找联系人函数
void FindContact(Contact* pc);//修改联系人函数
void ModifyContact(Contact* pc);//清空联系人函数
void DestroyContact(Contact* pc);//对联系人排序函数
void SortContact(Contact* pc);//函数实现源文件内容//初始化函数
void InitContact(Contact* pc)
{assert(pc);//利用库函数将整个数组所有元素初始化为0memset(pc->data, 0, sizeof(pc->data));//通讯录没有联系人pc->sz = 0;
}//增加联系人函数
void AddContact(Contact* pc)
{assert(pc);//通讯录已满情况if (pc->sz == Max_PEOINFO){printf("通讯录已满\n");return;}//通讯录未满情况printf("请输入联系人的姓名:>");scanf("%s", pc->data[pc->sz].name);printf("请输入联系人的性别:>");scanf("%s", pc->data[pc->sz].sex);printf("请输入联系人的年龄:>");scanf("%d", &(pc->data[pc->sz].age));printf("请输入联系人的电话:>");scanf("%s", pc->data[pc->sz].Telephone);printf("请输入联系人的地址:>");scanf("%s", pc->data[pc->sz].address);//每增加一个联系人,计数变量加1pc->sz = pc->sz + 1;printf("增加联系人成功\n");
}//为了便于局部调试程序,先实现显示函数
//显示所有联系人
void ShowContact(Contact* pc)
{assert(pc);int i = 0;//打印内容左对齐printf("%-20s\t%-6s\t%-4s\t%-12s\t%-20s\n", "姓名", "性别", "年龄", "电话", "地址");for (i = 0; i < pc->sz; i++){printf("%-20s\t%-6s\t%-4d\t%-12s\t%-20s\n",pc->data[i].name,pc->data[i].sex,pc->data[i].age,pc->data[i].Telephone,pc->data[i].address);}
}//删除联系人时我们需要知道联系人在数组中的位置(以名字删除联系人)
//名字检索函数(不需要在头文件中声明)
//此函数无法在有同名联系人时精确找到联系人
int ModifyName(char* str, Contact* pc)
{assert(pc && str);int i = 0;//遍历已经存储了联系人的数组元素寻找第一个名字相符的联系人并返回下标for (i = 0; i < pc->sz; i++){if (0 == strcmp(str, pc->data[i].name))return i;}//找不到return -1;
}//删除指定联系人
//此函数无法在有同名联系人时精确删除联系人
void DeleteContact(Contact* pc)
{assert(pc);//以名字查找指定联系人char name[MAX_NAME] = { 0 };printf("请输入要删除的联系人的名字\n");scanf("%s", name);int num = ModifyName(name, pc);//找到了if (num != -1){int i = 0;for (i = num; i < pc->sz; i++){memcpy(pc->data + i, pc->data + (i + 1), sizeof(PeoInfo));}//删除后计数变量减1pc->sz = pc->sz - 1;printf("删除成功\n");}//没找到elseprintf("删除失败,找不到指定联系人\n");
}//查找指定联系人
//此函数无法在有同名联系人时精确查找联系人
void FindContact(Contact* pc)
{assert(pc);//以名字查找指定联系人char name[MAX_NAME] = { 0 };printf("请输入要查找的联系人的名字\n");scanf("%s", name);//调用上面定义的名字检索函数int num = ModifyName(name, pc);//找到了打印此联系人信息if (num != -1){printf("%-20s\t%-6s\t%-4s\t%-12s\t%-20s\n", "姓名", "性别", "年龄", "电话", "地址");printf("%-20s\t%-6s\t%-4d\t%-12s\t%-20s\n",pc->data[num].name,pc->data[num].sex,pc->data[num].age,pc->data[num].Telephone,pc->data[num].address);}//找不到elseprintf("找不到指定联系人\n");
}//修改指定联系人
void ModifyContact(Contact* pc)
{assert(pc);//以名字查找指定联系人char name[MAX_NAME] = { 0 };printf("请输入要修改的联系人的名字\n");scanf("%s", name);//调用名字检索函数int num = ModifyName(name, pc);//找到后重新输入此联系人信息if (num != -1){printf("请输入新的姓名\n");scanf("%s", pc->data[num].name);printf("请输入新的性别\n");scanf("%s", pc->data[num].sex);printf("请输入新的年龄\n");scanf("%d", &(pc->data[num].age));printf("请输入新的电话\n");scanf("%s", pc->data[num].Telephone);printf("请输入新的地址\n");scanf("%s", pc->data[num].address);printf("修改联系人成功\n");}//找不到elseprintf("找不到指定联系人\n");
}//清空所有联系人
void DestroyContact(Contact* pc)
{assert(pc);//调用初始化函数将联系人结构体初始化InitContact(pc);printf("联系人已清空\n");
}//拓展功能
//以名字对所有联系人升序排序
void SortContact(Contact* pc)
{assert(pc);int i = 0;//选择排序for (i = 0; i < pc->sz -  1; i++){int j = i;for (j = i; j < pc->sz; j++){if (strcmp(pc->data[i].name, pc->data[j].name) > 0){PeoInfo tmp;memcpy(&tmp, pc->data[i].name, sizeof(PeoInfo));memcpy(pc->data[i].name, pc->data[j].name, sizeof(PeoInfo));memcpy(pc->data[j].name, &tmp, sizeof(PeoInfo));}}}printf("排序完成\n");
}//主程序源文件内容//菜单
void menu()
{printf("****** 1.ADD      2.DELETE ********\n");printf("****** 3.FIND     4.MODIFY ********\n");printf("****** 5.SHOW     6.DESTROY********\n");printf("****** 7.SORT     0.EXIT   ********\n");
}void test()
{//定义一个通讯录结构体变量Contact con;//初始化InitContact(&con);enum method input = 0;do{menu();printf("请选择你的操作\n");scanf("%d", &input);switch (input){case ADD:AddContact(&con);break;case DELETE:DeleteContact(&con);break;case FIND:FindContact(&con);break;case MODIFY:ModifyContact(&con);break;case SHOW:ShowContact(&con);break;case DESTROY:DestroyContact(&con);break;case SORT:SortContact(&con);break;case EXIT:printf("程序已退出\n");break;default:printf("输入错误,请重新输入:>\n");break;}} while (input);
}
int main()
{test();return 0;
}

功能模块展示:

增加功能:

删除功能:

查找功能:

修改功能:

拓展功能:

设计思路:

要实现一个简易版静态通讯录,无非是在实现增删查改的基础上进行进一步的功能拓展,因此设计的重点是在增删查改的功能实现上,静态版本存储通讯录内容的是定长数组,因此要实现这些功能,我们需要围绕数组下标和已经存储的联系人个数作为文章。

只要知道已经存储的联系人个数,增加联系人就会变得轻而易举。而删除,查找,修改联系人时都必须先找到要操作的联系人,因此我们需要先实现一个检索联系人接口供它们调用,此接口实现的越精确,删查改就会越精确。

为了方便对数组下标进行操作,将计数联系人个数的变量和记录联系人信息的数组都作为通讯录结构体的成员,计数变量从0开始,每增加一个联系人就加1,删除减1,这样我们就会得到通讯录的实时大小从而可以非常容易的操作通讯录,实现通讯录的功能也就变的非常简单。

动态简易通讯录(本质顺序表)

代码:

动态版本的代码只需在静态版本上稍作修改即可。

//头文件增加和修改的内容//初始容量
#define  INIT_SZ 3
//每次扩容增加容量
#define  ADD_SZ 2//修改后通讯录结构体
typedef struct Contact
{//PeoInfo data[Max_PEOINFO];//用结构体指针代替结构体数组PeoInfo* data;int sz;//增加一个记录通讯录容量的变量int capacity;
}Contact;//函数实现源文件增加和修改的内容//动态版本初始化函数
void InitContact(Contact* pc)
{assert(pc);//先开辟INIT_SZ个空间pc->data = (PeoInfo*)malloc(INIT_SZ * sizeof(PeoInfo));//开辟失败if (pc->data == NULL){perror("InitContact");return;}pc->sz = 0;//记录容量pc->capacity = INIT_SZ;
}//增加联系人时需要先检查容量是否已满,若满则增加容量
//空间动态增长(无需在头文件中声明)
int mallocContact(Contact* pc)
{assert(pc);//已满if (pc->sz == pc->capacity){//扩容PeoInfo* ptr = (PeoInfo*)realloc(pc->data, (pc->capacity + ADD_SZ) * sizeof(PeoInfo));//扩容失败if (ptr == NULL){perror("mallocContact");return 0;}//扩容成功else{pc->data = ptr;pc->capacity += ADD_SZ;printf("扩容成功\n");return 1;}}//未满return 1;
}//动态版本增加函数
void AddContact(Contact* pc)
{assert(pc);//扩容失败if (0 == mallocContact(pc)){return;}//未满或扩容成功printf("请输入联系人的姓名\n");scanf("%s", pc->data[pc->sz].name);printf("请输入联系人的性别\n");scanf("%s", pc->data[pc->sz].sex);printf("请输入联系人的年龄\n");scanf("%d", &(pc->data[pc->sz].age));printf("请输入联系人的电话\n");scanf("%s", pc->data[pc->sz].Telephone);printf("请输入联系人的地址\n");scanf("%s", pc->data[pc->sz].address);pc->sz = pc->sz + 1;printf("增加联系人成功\n");}//动态版本清空函数
void DestroyContact(Contact* pc)
{assert(pc);free(pc->data);pc->data = NULL;pc->sz = 0;pc->capacity = 0;printf("联系人已清空\n");
}

扩容模块展示:

设计思路:

静态版本的通讯录十分死板,需要存储的数据少了就会存在空间浪费,多了又会不够,因此衍生出动态版本来解决这一问题,当存储空间不够时就向内存申请新的空间来增加容量,更加灵活。

为了实现实时向内存申请空间,需要一个变量用来记录通讯录结构体的容量,当存储的联系人个数等于容量时就需要进行扩容,同时由于通讯录的大小是动态变化的,因此用结构体指针替代结构体数组来维护存储空间。

由于每次扩容后的存储空间依然是连续的,因此在没有发生访问越界时可以像操作数组一样操作指针,静态版本的大多数代码都无需修改。

文件版本通讯录

代码:

在动态版本上稍作修改。

//函数实现源文件增加和修改的内容//容量检查函数声明
int mallocContact(Contact* pc);//初始化时需要先读取文件contact.dat的内容到data中去
void LoadContact(Contact* pc)
{//打开文件FILE* pf = fopen("contact.dat", "rb");//若路径下没有此文件,则打开文件失败if (pf == NULL){perror("LoadContact");return;}PeoInfo tmp = { 0 };//读文件while (fread(&tmp, sizeof(PeoInfo), 1, pf)){//扩容判断if (0 == mallocContact(pc))return;pc->data[pc->sz] = tmp;//每读取一个计数变量加1pc->sz++;}//关闭文件fclose(pf);pf = NULL;
}//动态版本初始化函数
void InitContact(Contact* pc)
{assert(pc);pc->data = (PeoInfo*)malloc(INIT_SZ * sizeof(PeoInfo));if (pc->data == NULL){perror("InitContact");return;}pc->sz = 0;pc->capacity = INIT_SZ;//载入文件内容LoadContact(pc);
}//将通讯录信息以二进制形式保存到contact.dat文件中
void SaveContact(Contact* 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(PeoInfo), 1, pf);}//关闭文件fclose(pf);pf == NULL;printf("通讯录内容已保存到contact.dat文件中\n");
}//主程序源文件修改内容case EXIT://在退出程序时将内存中的信息保存到文件中去SaveContact(&con);printf("程序已退出\n");break;

文件模块展示:

设计思路:

无论是静态版本还是动态版本,联系人信息都是存储在内存中的,一旦程序退出运行,这些信息也会随之消失,为了长久存储这些信息,衍生出了文件版本的通讯录,即利用文件操作函数将存储在内存中的信息存储到文件中长久保存。

我们只需要在动态版本的基础上增加一个读取文件函数和写入文件函数,在程序开始时先将文件中的信息读取到内存中,在程序退出时再将内存中的数据写回文件中即可。

这篇关于用c语言实现通讯录的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1021354

相关文章

使用Python和OpenCV库实现实时颜色识别系统

《使用Python和OpenCV库实现实时颜色识别系统》:本文主要介绍使用Python和OpenCV库实现的实时颜色识别系统,这个系统能够通过摄像头捕捉视频流,并在视频中指定区域内识别主要颜色(红... 目录一、引言二、系统概述三、代码解析1. 导入库2. 颜色识别函数3. 主程序循环四、HSV色彩空间详解

PostgreSQL中MVCC 机制的实现

《PostgreSQL中MVCC机制的实现》本文主要介绍了PostgreSQL中MVCC机制的实现,通过多版本数据存储、快照隔离和事务ID管理实现高并发读写,具有一定的参考价值,感兴趣的可以了解一下... 目录一 MVCC 基本原理python1.1 MVCC 核心概念1.2 与传统锁机制对比二 Postg

SpringBoot整合Flowable实现工作流的详细流程

《SpringBoot整合Flowable实现工作流的详细流程》Flowable是一个使用Java编写的轻量级业务流程引擎,Flowable流程引擎可用于部署BPMN2.0流程定义,创建这些流程定义的... 目录1、流程引擎介绍2、创建项目3、画流程图4、开发接口4.1 Java 类梳理4.2 查看流程图4

C++中零拷贝的多种实现方式

《C++中零拷贝的多种实现方式》本文主要介绍了C++中零拷贝的实现示例,旨在在减少数据在内存中的不必要复制,从而提高程序性能、降低内存使用并减少CPU消耗,零拷贝技术通过多种方式实现,下面就来了解一下... 目录一、C++中零拷贝技术的核心概念二、std::string_view 简介三、std::stri

C++高效内存池实现减少动态分配开销的解决方案

《C++高效内存池实现减少动态分配开销的解决方案》C++动态内存分配存在系统调用开销、碎片化和锁竞争等性能问题,内存池通过预分配、分块管理和缓存复用解决这些问题,下面就来了解一下... 目录一、C++内存分配的性能挑战二、内存池技术的核心原理三、主流内存池实现:TCMalloc与Jemalloc1. TCM

OpenCV实现实时颜色检测的示例

《OpenCV实现实时颜色检测的示例》本文主要介绍了OpenCV实现实时颜色检测的示例,通过HSV色彩空间转换和色调范围判断实现红黄绿蓝颜色检测,包含视频捕捉、区域标记、颜色分析等功能,具有一定的参考... 目录一、引言二、系统概述三、代码解析1. 导入库2. 颜色识别函数3. 主程序循环四、HSV色彩空间

Python实现精准提取 PDF中的文本,表格与图片

《Python实现精准提取PDF中的文本,表格与图片》在实际的系统开发中,处理PDF文件不仅限于读取整页文本,还有提取文档中的表格数据,图片或特定区域的内容,下面我们来看看如何使用Python实... 目录安装 python 库提取 PDF 文本内容:获取整页文本与指定区域内容获取页面上的所有文本内容获取

基于Python实现一个Windows Tree命令工具

《基于Python实现一个WindowsTree命令工具》今天想要在Windows平台的CMD命令终端窗口中使用像Linux下的tree命令,打印一下目录结构层级树,然而还真有tree命令,但是发现... 目录引言实现代码使用说明可用选项示例用法功能特点添加到环境变量方法一:创建批处理文件并添加到PATH1

Java使用HttpClient实现图片下载与本地保存功能

《Java使用HttpClient实现图片下载与本地保存功能》在当今数字化时代,网络资源的获取与处理已成为软件开发中的常见需求,其中,图片作为网络上最常见的资源之一,其下载与保存功能在许多应用场景中都... 目录引言一、Apache HttpClient简介二、技术栈与环境准备三、实现图片下载与保存功能1.

canal实现mysql数据同步的详细过程

《canal实现mysql数据同步的详细过程》:本文主要介绍canal实现mysql数据同步的详细过程,本文通过实例图文相结合给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的... 目录1、canal下载2、mysql同步用户创建和授权3、canal admin安装和启动4、canal