用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;

文件模块展示:

设计思路:

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

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

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

JAVA开发 PDF文件生成表格,表格根据内容自动调整高度

1、展示效果 2、相关功能实现 JAVA开发 使用Apache PDFBox库生成PDF文件&#xff0c;绘制表格 3、实现代码 import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDPage; import org.apache.pdfbox.pdmodel.PDPageContentStream; import org.ap…

傲星一个在线工具箱源码附搭建教程

傲星工具箱源码是一款功能强大的在线工具箱程序&#xff0c;您可以通过安装扩展来增强其功能。同时&#xff0c;该程序还提供了插件模板的功能&#xff0c;让您可以将其作为网页导航使用。 1.PHP版本需不低于7.2.5。 2.Mysql版本需不低于5.7。 3.需要安装fileinfo扩展。 4.…

Python | 使用Matplotlib生成子图的示例

数据可视化在分析和解释数据的过程中起着举足轻重的作用。Python中的Matplotlib库提供了一个强大的工具包&#xff0c;用于制作各种图表和图表。一个突出的功能是它能够在单个图中生成子图&#xff0c;为以组织良好和结构化的方式呈现数据提供了有价值的工具。使用子图可以同时…

北京崇文门中医医院贾英才:中医传承的践行者

贾英才&#xff0c;一位在北京崇文门中医医院出诊的杰出中医执业医师&#xff0c;在中医领域深耕近三十载&#xff0c;以其精湛的医术和独特的诊疗验方体系&#xff0c;赢得了广大患者的信赖与认可。 贾英才自幼便深受家学熏陶&#xff0c;中医的种子早早在他心中扎根。成长于中…

2024 年 Python 基于 Kimi 智能助手 Moonshot Ai 模型搭建微信机器人(更新中)

注册 Kimi 开放平台 Kimi&#xff1a;https://www.moonshot.cn/ Kimi智能助手是北京月之暗面科技有限公司&#xff08;Moonshot AI&#xff09;于2023年10月9日推出的一款人工智能助手&#xff0c;主要为用户提供高效、便捷的信息服务。它具备多项强大功能&#xff0c;包括多…

深入理解计算机系统 CSAPP 家庭作业6.35

第一步先求(S,E,B,m) 题目说共C128个字节,块大小B为16个字节,那就是分为八组:0,1,2,3,4,5,6,7.然后每组存4个int 每个4字节 CB*E*S .B16 ,直接映射的E就是1,所以S8 (S,E,B,m)(8,1,16,7) C128M128s3b4t0 sizeof(int)0100地址(二进制)COCIsrc[0][0]00000000000000组0src[0][1…

上市公司-社会责任报告、ESG报告文本(2006-2023年)

上市公司社会责任报告是企业对外公布的一份关于其社会责任实践和成果的详细文件&#xff0c;涵盖环境保护、社会贡献和公司治理等方面的表现。通常包含公司在减少环境影响、提升社会福祉、维护员工权益、促进社区发展以及确保透明和道德的管理实践等方面的信息和数据。有助于了…

linux 线程

文章目录 1.线程概念线程优点线程缺点 2.Linux线程和进程3. Linux线程控制线程创建---pthread_create线程等待---pthread_join线程退出线程分离---pthread_detach 1.线程概念 进程内核数据结构 进程代码和数据 我们的代码在进程中&#xff0c;全部都是串行调用的 进程创建&am…

入侵检测系统(IDS)

入侵检测 入侵检测&#xff08;Intrusion Detection&#xff09;是指发现或确定入侵行为存在或出现的动作&#xff0c;也就是发现、跟踪并记录计算机系统或计算机网络中的非授权行为&#xff0c;或发现并调查系统中可能为视图入侵或病毒感染所带来的异常活动。 入侵检测系统 …

upload-labs第十三关教程

upload-labs第十三关教程 第十三关一、源代码分析代码审计 二、绕过分析1&#xff09;0x00绕过a.上传eval.pngb.使用burpsuite进行拦截修改之前&#xff1a;修改之后&#xff1a;进入hex模块&#xff1a; c.放包上传成功&#xff1a; d.使用中国蚁剑进行连接 2&#xff09;%00绕…

20240619在飞凌OK3588-C的LINUX系统启动的时候拉高3个GPIO口141-111-120【方法一】

20240619在飞凌OK3588-C的LINUX系统启动的时候拉高3个GPIO口141-111-120【方法一】 2024/6/19 16:12 缘起&#xff1a;在凌OK3588-C的LINUX R4系统启动的时候&#xff0c;需要拉高GPIO4_B5、GPIO3_B7和GPIO3_D0。 修改rcS&#xff0c;在系统启动的时候&#xff0c;即可拉高。 通…

极具吸引力的小程序 UI 风格

极具吸引力的小程序 UI 风格

002.Linux CentOS7 安装

我 的 个 人 主 页&#xff1a;&#x1f449;&#x1f449; 失心疯的个人主页 &#x1f448;&#x1f448; 入 门 教 程 推 荐 &#xff1a;&#x1f449;&#x1f449; Python零基础入门教程合集 &#x1f448;&#x1f448; 虚 拟 环 境 搭 建 &#xff1a;&#x1f449;&…

湖北文理学院2024年成人高等继续教育招生简章

湖北文理学院&#xff0c;作为一所历史悠久、底蕴深厚的学府&#xff0c;始终致力于为社会各界培养具备高素质、专业技能和创新精神的优秀人才。在成人高等继续教育领域&#xff0c;湖北文理学院更是凭借其卓越的教学质量和丰富的教育资源&#xff0c;吸引了众多有志于提升自身…

ThinkPHP5大学生社会实践管理系统

有需要请加文章底部Q哦 可远程调试 ThinkPHP5大学生社会实践管理系统 一 介绍 大学生社会实践管理系统基于ThinkPHP5框架开发&#xff0c;数据库mysql&#xff0c;前端bootstrap。系统角色分为用户和管理员。 技术栈&#xff1a;ThinkPHP5mysqlbootstrapphpstudyvscode 二 功…

Gobject tutorial 七

The GObject base class GObject是一个fundamental classed instantiatable type,它的功能如下&#xff1a; 内存管理构建/销毁实例set/get属性方法信号 /*** GObjectClass:* g_type_class: the parent class* constructor: the constructor function is called by g_object…

基于单片机的智能窗户控制系统的设计

摘 要&#xff1a; 根据单片机技术和现代传感器技术 &#xff0c; 本文主要针对基于单片机的智能窗户控制系统的设计进行探讨 &#xff0c; 仅供参考 。 关键词&#xff1a; 单片机 &#xff1b; 智能窗户 &#xff1b; 控制系统 &#xff1b; 设计 在现代科学技术持续发展的带…

【精品方案】产业园区数字孪生规划方案(39页PPT)

引言&#xff1a;随着数字化和智能化技术的快速发展&#xff0c;传统产业园区面临着转型升级的重大机遇。数字孪生技术作为一种将物理世界与数字世界紧密结合的创新技术&#xff0c;为产业园区的规划、建设和运营管理提供了全新的解决方案。本方案旨在通过构建产业园区数字孪生…

Upload-Labs:Pass - 1(JS前端白名单)

Pass_1 1. 上传测试2. 代码审计**获取文件输入的值**&#xff1a;**检查是否选择了文件**&#xff1a;**定义允许的文件类型**&#xff1a;**提取文件的扩展名**&#xff1a;**检查文件类型是否允许上传**&#xff1a;**构建错误消息并提醒用户**&#xff1a; 3.绕过思路3.1 将…

集合系列(二十六) -利用LinkedHashMap实现一个LRU缓存

一、什么是 LRU LRU是 Least Recently Used 的缩写&#xff0c;即最近最少使用&#xff0c;是一种常用的页面置换算法&#xff0c;选择最近最久未使用的页面予以淘汰。 简单的说就是&#xff0c;对于一组数据&#xff0c;例如&#xff1a;int[] a {1,2,3,4,5,6}&#xff0c;…