用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

相关文章

hdu1043(八数码问题,广搜 + hash(实现状态压缩) )

利用康拓展开将一个排列映射成一个自然数,然后就变成了普通的广搜题。 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#inclu

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

【Prometheus】PromQL向量匹配实现不同标签的向量数据进行运算

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全栈,前后端开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi

让树莓派智能语音助手实现定时提醒功能

最初的时候是想直接在rasa 的chatbot上实现,因为rasa本身是带有remindschedule模块的。不过经过一番折腾后,忽然发现,chatbot上实现的定时,语音助手不一定会有响应。因为,我目前语音助手的代码设置了长时间无应答会结束对话,这样一来,chatbot定时提醒的触发就不会被语音助手获悉。那怎么让语音助手也具有定时提醒功能呢? 我最后选择的方法是用threading.Time

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

C#实战|大乐透选号器[6]:实现实时显示已选择的红蓝球数量

哈喽,你好啊,我是雷工。 关于大乐透选号器在前面已经记录了5篇笔记,这是第6篇; 接下来实现实时显示当前选中红球数量,蓝球数量; 以下为练习笔记。 01 效果演示 当选择和取消选择红球或蓝球时,在对应的位置显示实时已选择的红球、蓝球的数量; 02 标签名称 分别设置Label标签名称为:lblRedCount、lblBlueCount

科研绘图系列:R语言扩展物种堆积图(Extended Stacked Barplot)

介绍 R语言的扩展物种堆积图是一种数据可视化工具,它不仅展示了物种的堆积结果,还整合了不同样本分组之间的差异性分析结果。这种图形表示方法能够直观地比较不同物种在各个分组中的显著性差异,为研究者提供了一种有效的数据解读方式。 加载R包 knitr::opts_chunk$set(warning = F, message = F)library(tidyverse)library(phyl

透彻!驯服大型语言模型(LLMs)的五种方法,及具体方法选择思路

引言 随着时间的发展,大型语言模型不再停留在演示阶段而是逐步面向生产系统的应用,随着人们期望的不断增加,目标也发生了巨大的变化。在短短的几个月的时间里,人们对大模型的认识已经从对其zero-shot能力感到惊讶,转变为考虑改进模型质量、提高模型可用性。 「大语言模型(LLMs)其实就是利用高容量的模型架构(例如Transformer)对海量的、多种多样的数据分布进行建模得到,它包含了大量的先验

Kubernetes PodSecurityPolicy:PSP能实现的5种主要安全策略

Kubernetes PodSecurityPolicy:PSP能实现的5种主要安全策略 1. 特权模式限制2. 宿主机资源隔离3. 用户和组管理4. 权限提升控制5. SELinux配置 💖The Begin💖点点关注,收藏不迷路💖 Kubernetes的PodSecurityPolicy(PSP)是一个关键的安全特性,它在Pod创建之前实施安全策略,确保P

工厂ERP管理系统实现源码(JAVA)

工厂进销存管理系统是一个集采购管理、仓库管理、生产管理和销售管理于一体的综合解决方案。该系统旨在帮助企业优化流程、提高效率、降低成本,并实时掌握各环节的运营状况。 在采购管理方面,系统能够处理采购订单、供应商管理和采购入库等流程,确保采购过程的透明和高效。仓库管理方面,实现库存的精准管理,包括入库、出库、盘点等操作,确保库存数据的准确性和实时性。 生产管理模块则涵盖了生产计划制定、物料需求计划、