C语言程序设计—通讯录实现
本篇文章主要是实现一个简易的通讯录:
功能如下:
- 添加用户
- 修改用户
- 删除用户
- 查找用户(可重名)
- 按名字或年龄排序
- 显示用户
- 保存通讯录
- 日志追加
有如下知识点:
- 动态数组
- 结构体
- 枚举
- 自定义标识符和宏
- 文件打开与存储
- 函数
- 指针
- 循环
- 排序
简述特点:
- 将人员信息放在一个PeoInf的结构体中,再创建一个结构体List,用于存放peoinf这个结构体的指针,和容量与目前通讯录人员数量。
- 再用realloc动态开辟以结构体peoinf为大小的内存,用于实现动态内存开辟。
- 程序运行后,初始化这段空间,并查询是否有“contact.txt”的文件存在,如果存在,则读取文件里的内容,并放到peoinf的结构体“数组”中,并实时监控是否需要扩容。如果不存在就创建文件。
- 随后就可以添加、修改、查找、删除用户,每一次增删改查都会被记录到一个“contact_log.txt”的文件里,这里使用了时间戳。
- 用qsort进行名字或年龄进行排序
- 程序会知道本次是否进行修改,如果修改后就退出会提示是否需要保存,当然也可以自己手动保存。
- 程序以“rb”和“wb”进行文件的读写。
- 程序实现了重名查找,在有重名的情况下会进行选择。
- (代码可直接运行,复制到编译器vs2019即可)
代码部分
-
contact.h
#pragma once #include <stdio.h> #include <string.h> #include <stdlib.h> #include <errno.h> #include <assert.h> #include <time.h> #include <sys/stat.h>#define MAX_10 10 #define MAX_20 20 //#define LOG_PRINT(x) fprintf(pf, "In %s %s ,user %s name calling %s\n",__DATE__,__TIME__,(x),(list->pl+num)->name) typedef struct PeoInf {char name[MAX_20];int age;char sex[5];char tel[12];char addr[30]; }PeoInf; //定义通讯录结构体,嵌套PeoInf typedef struct List {//动态内存分配PeoInf* pl;int count;int capacity;//容量 }List; //定义一个枚举变量,用于存储菜单所有选择 enum select_all {EXIT,//0ADD,DEL,SELECT,MODIFY,SORT,SHOW,SAVE }; //菜单函数 void menu(); //定义初始化list函数 void initialise_list(List* list); //定义添加信息函数 void add_peoinf(List* list); //定义显示函数 void show_list(List* list); //定义删除函数 void del_peoinf(List* list); //定义通过找名字查找人的函数(已实现重名查找) int find_byname(const List* list); //定义查找人 void sele_peoinf(const List* list); //定义修改人信息函数 void modify_peoinf(List* list); //定义删除和修改已找到下标的信息函数 void del_havefond(List* list, int position); void modify_havefond(List* list, int position); //定义排序函数 void sort_peoinf(List* list); //定义文件保存函数 void file_save(List* list); //定义扩容函数 void expand_list(List* list); -
actualize.c
#include "contact.h" //实现菜单函数 void menu(){printf("----------------------------------------\n");printf("--------1. add 2. del--------------\n");printf("--------3. select 4. modify-----------\n");printf("--------5. sort 6. show-------------\n");printf("--------------7. save-------------------\n");printf("--------------0. exit-------------------\n");printf("----------------------------------------\n"); } //实现初始化list函数 void initialise_list(List* list){PeoInf* ptr = (PeoInf*)calloc(3, sizeof(PeoInf));//默认开辟三个人的存储空间if (ptr == NULL) {printf("%s", strerror(errno));return ;}list->pl = ptr;list->count = 0;list->capacity = 3;FILE* pf = NULL;struct stat buffer;//判断文件是否存在if (stat("contact.txt", &buffer) != 0) {//不存在就创建文件pf = fopen("contact.txt", "wb");fclose(pf);pf = NULL;return;}pf = fopen("contact.txt", "rb");if (pf != NULL) {for (int i = 0; fread(list->pl + i, sizeof(PeoInf), 1, pf) != 0; i++) {if (list->count == list->capacity - 1) {expand_list(list);}list->count++;}fclose(pf);}pf = NULL; } //扩容函数 void expand_list(List* list) {PeoInf* ptr =(PeoInf*) realloc(list->pl, (list->capacity + 2)*sizeof(PeoInf));//每次增加两个if (ptr == NULL) {printf("%s", strerror(errno));return;}list->pl = ptr;list->capacity += 2; } //实现添加日志功能 /* * return 0 失败 * return 1 成功 */ int add_log(List* list,char* moving,int num) {//打开文件FILE* pf=NULL;//判断写入模式是否要追加if (list->count == 0) {pf = fopen("contact_log.txt", "w");}else {pf = fopen("contact_log.txt", "a");}//如果打开失败,报错if (pf == NULL) {perror("fopen:");return 0;}//获取时间戳time_t rawtime;struct tm* timeinfo;time(&rawtime);timeinfo = localtime(&rawtime);fprintf(pf, "In %s \tuser %s name calling %s.\n", asctime(timeinfo), moving, (list->pl + num)->name);fclose(pf);pf = NULL;return 1; } //实现添加信息功能 void add_peoinf(List* list) {assert(list);//断言//判断是否需要扩容if (list->count == list->capacity) {expand_list(list);//内部函数,不必去头文件里定义printf("Automatic capacity expansion is successful,\n and the current address book capacity is %d\n", list->capacity);}printf("Please enter the name\n->");scanf("%s", (list->pl+list->count)->name);printf("Please enter age\n->");scanf("%d", &(list->pl + list->count)->age);printf("Please enter sex\n->");scanf("%s", (list->pl + list->count)->sex);printf("Please enter the telephone\n->");scanf("%s", (list->pl + list->count)->tel);printf("Please enter the address\n->");scanf("%s", (list->pl + list->count)->addr);//添加日志log功能if (!add_log(list,"add",list->count)) {printf("log fail,please find excause.\n");}list->count++;printf("succeed!\n"); } //实现显示函数 void show_list(List* list) {assert(list);printf("name\tage\tsex\ttelephone\taddr\n");for (int i = 0; i < (list->count); i++) {printf("%s\t%d\t%s\t%s\t\t%s\n", (list->pl + i)->name,(list->pl + i)->age, (list->pl + i)->sex, (list->pl + i)->tel, (list->pl + i)->addr);} } //实现通过寻找名字,找到这个人 //重名默认存放数组为10,如需变大可改为动态扩容实现 int find_byname(const List* list) {char s_name[MAX_20] = { 0 };int count = 0;int find_result[MAX_10] = { 0 };printf("Please enter the name that you want \n->");scanf("%s", s_name);for (int i = 0; i < list->count; i++) {if (strcmp((list->pl + i)->name, s_name)==0) {//找到了if (count == 0) {printf("Find the information, please confirm\n");printf("number\tname\tage\tsex\ttelephone\taddr\n");}printf("%d\t%s\t%d\t%s\t%s\t\t%s\n", count+1,(list->pl + i)->name,(list->pl + i)->age, (list->pl + i)->sex, (list->pl + i)->tel, (list->pl + i)->addr);find_result[count] = i;//将找到的坐标存入数组中count++;//判断是否有重复}}if (count == 0) {//找不到printf("Check no such person, please confirm after the input!\n");return -1;}else if (count == 1) {return find_result[0];}else {//两个以上int select_num = 0;while (1) {printf("Please select the object serial number that you want to operate on\n->");scanf("%d", &select_num);if (select_num >= 1 && select_num <= count) {//输入正确序号,方可返回return find_result[select_num - 1];}else {printf("error,please reenter\n");}}} } //实现删除函数 void del_peoinf(List* list) {assert(list);int del_num = find_byname(list);if (del_num < 0) return;//查找失败for (int i = 0; i < list->count - del_num - 1; i++) {*(list->pl + del_num + i) = *(list->pl + del_num + 1 + i);}list->count--;printf("delet successfully\n");if (!add_log(list, "delet", del_num)) {printf("log fail,please find excause.\n");} } void del_havefond(List* list,int position) {assert(list);for (int i = 0; i < list->count - position - 1; i++) {*(list->pl + position + i) = *(list->pl + position + 1 + i);}list->count--;printf("delet successfully\n");if (!add_log(list, "delet", position)) {printf("log fail,please find excause.\n");} } //实现查找信息功能 void sele_peoinf(const List* list) {assert(list);int find_num = find_byname(list);if (find_num < 0) return;//查找失败printf("The information is as follows\n");printf("name\tage\tsex\ttelephone\taddr\n");printf("%s\t%d\t%s\t%s\t\t%s\n", (list->pl + find_num)->name,(list->pl + find_num)->age, (list->pl + find_num)->sex, (list->pl + find_num)->tel, (list->pl + find_num)->addr);int input_find = 0;do {printf("--------------------------------\n");printf("--------------------------------\n");printf("-----1. del-------2. modif------\n");printf("------------0. exit-------------\n");printf("--------------------------------\n");printf("--------------------------------\n");printf("please enter what you want\n->");scanf("%d", &input_find);if (input_find == 1) {del_havefond(list, find_num);return;}else if (input_find == 2) {modify_havefond(list, find_num);return;}else if (input_find != 0) {printf("Input is wrong, please reagain\n");}} while (input_find);} void modify_havefond(List* list,int position) {assert(list);printf("Please enter the new name\n->");scanf("%s", (list->pl + position)->name);printf("Please enter new age\n->");scanf("%d", &(list->pl + position)->age);printf("Please enter new sex\n->");scanf("%s", (list->pl + position)->sex);printf("Please enter the new telephone\n->");scanf("%s", (list->pl + position)->tel);printf("Please enter the new address\n->");scanf("%s", (list->pl + position)->addr);printf("Modified successfully\n");if (!add_log(list, "modify", position)) {printf("log fail,please find excause.\n");} } //实现修改信息 void modify_peoinf(List* list) {assert(list);int mod_num = find_byname(list);if (mod_num < 0) return;//查找失败printf("Please enter the new name\n->");scanf("%s", (list->pl + mod_num)->name);printf("Please enter new age\n->");scanf("%d", &(list->pl + mod_num)->age);printf("Please enter new sex\n->");scanf("%s", (list->pl + mod_num)->sex);printf("Please enter the new telephone\n->");scanf("%s", (list->pl + mod_num)->tel);printf("Please enter the new address\n->");scanf("%s", (list->pl + mod_num)->addr);printf("Modified successfully\n");if (!add_log(list, "modify",mod_num)) {printf("log fail,please find excause.\n");} } //qsort的比较函数 int compare_name(const void* e1,const void* e2) {return strcmp(((PeoInf*)e1)->name, ((PeoInf*)e2)->name);} int compare_age(const void* e1, const void* e2) {return ((PeoInf*)e1)->age - ((PeoInf*)e2)->age;} //实现排序函数 void sort_peoinf(List* list) {int sort_input = 0;do {printf("--------------------------------\n");printf("--------------------------------\n");printf("-----1. name-------2. age------\n");printf("------------0. exit-------------\n");printf("--------------------------------\n");printf("--------------------------------\n");printf("please enter you want sort by\n->");scanf("%d", &sort_input);if (sort_input == 1) {qsort(list->pl, list->count, sizeof(PeoInf), compare_name);printf("sort by name successfully\n");return;}else if (sort_input == 2) {qsort(list->pl, list->count, sizeof(PeoInf), compare_age);printf("sort by age successfully\n");return;}} while (sort_input);} void file_save(List *list) {FILE* pf = fopen("contact.txt", "wb");//二进制写入if (pf == NULL) {perror("fopen:");return;}//写数据for (int i = 0; i < list->count; i++) {fwrite(list->pl+i, sizeof(PeoInf), 1, pf);}fclose(pf);pf = NULL; } -
test.c
#include "contact.h" int main() {int input = 0;List list;initialise_list(&list);//动态内存开辟,记得用完销毁int modify_num = 0;//修改数量记录do{menu();printf("Please choose!\n->");scanf("%d", &input);switch (input){case ADD: {add_peoinf(&list);modify_num++;}break;case DEL:{del_peoinf(&list);modify_num++;}break;case SELECT:{sele_peoinf(&list);}break;case MODIFY:{modify_peoinf(&list);modify_num++;}break;case SORT:{sort_peoinf(&list);}break;case SHOW:{show_list(&list);}break;case SAVE:{file_save(&list);printf("save in file sucessfully\n");modify_num = 0;}break;case EXIT:{if (modify_num != 0) {int save_select = 0;printf("=========1.save 2.no=============\n");printf("The modified data is not saved, whether it needs to be saved\n->");scanf("%d", &save_select);if (save_select == 1) {file_save(&list);printf("save in file sucessfully\n");}}printf("Ok,have a nice day! Bye~");}break;default:printf("Input is wrong,please reagain!\n");break;}} while (input);//销毁动态内存free(list.pl);list.pl = NULL; }
希望对大家有帮助!
相关文章:
C语言程序设计—通讯录实现
本篇文章主要是实现一个简易的通讯录: 功能如下: 添加用户修改用户删除用户查找用户(可重名)按名字或年龄排序显示用户保存通讯录日志追加 有如下知识点: 动态数组结构体枚举自定义标识符和宏文件打开与存储函数指针…...
实战:大数据Flink CDC同步Mysql数据到ElasticSearch
文章目录 前言知识积累CDC简介CDC的种类常见的CDC方案比较 Springboot接入Flink CDC环境准备项目搭建 本地运行集群运行将项目打包将包传入集群启动远程将包部署到flink集群 写在最后 前言 前面的博文我们分享了大数据分布式流处理计算框架Flink和其基础环境的搭建,…...
B-Tree 索引和 Hash 索引的对比
分析&回答 B-Tree 索引的特点 B-tree 索引可以用于使用 , >, >, <, < 或者 BETWEEN 运算符的列比较。如果 LIKE 的参数是一个没有以通配符起始的常量字符串的话也可以使用这种索引。 有时,即使有索引可以使用,MySQL 也不使用任何索引。…...
入门Python编程:了解计算机语言、Python介绍和开发环境搭建
文章目录 Python入门什么是计算机语言1. 机器语言2. 符号语言(汇编)3. 高级语言 编译型语言和解释型语言1. 编译型语言2. 解释型语言 Python的介绍Python开发环境搭建Python的交互界面 python学习专栏python基础知识(0基础入门)py…...
深度解析Redisson框架的分布式锁运行原理与高级知识点
推荐阅读 项目实战:AI文本 OCR识别最佳实践 AI Gamma一键生成PPT工具直达链接 玩转cloud Studio 在线编码神器 玩转 GPU AI绘画、AI讲话、翻译,GPU点亮AI想象空间 资源分享 史上最全文档AI绘画stablediffusion资料分享 AI绘画关于SD,MJ,GPT,SDXL百科全书 AI绘画 stable…...
C#扩展方法
参数列表中this的这种用法是在.NET 3.0之后新增的一种特性---扩展方法。通过这个属性可以让程序员在现有的类型上添加扩展方法(无需创建新的派生类型、重新编译或者以其他方式修改原始类型)。 扩展方法是一种特殊的静态方法,虽然是静态方法&a…...
uniapp 高度铺满全屏
问题:在有uni-tabbar的情况下,页面铺满剩下的部分 <template><view :style"{height:screenHeightpx}" class"page"></view> </template> <script>export default {data() {return {screenHeight: &q…...
UG\NX二次开发 判断向量在指定的公差内是否为零,判断是否是零向量 UF_VEC3_is_zero
文章作者:里海 来源网站:王牌飞行员_里海_里海NX二次开发3000例,里海BlockUI专栏,C\C++-CSDN博客 简介: UG\NX二次开发 判断向量在指定的公差内是否为零,判断是否是零向量 UF_VEC3_is_zero 效果: 代码: #include "me.hpp"void ufusr(char* param, int* retco…...
2023年MySQL实战核心技术第一篇
目录 四 . 基础架构:一条SQl查询语句是如何执行的? 4.1 MySQL逻辑架构图: 4.2 MySQL的Server层和存储引擎层 4.2.1 连接器 4.2.1.1 解释 4.2.1.2 MySQL 异常重启 解决方案: 4.2.1.2.1. 定期断开长连接: 4.2.1.2.2. 初始…...
hivesql执行过程
语法解析 SemanticAnalyzer SemanticAnalyzer是Hive中的语义分析器,负责检查Hive SQL程序的语义是否正确。SemanticAnalyzer会对Hive SQL程序进行以下检查: 检查过程 语法检查 SemanticAnalyzer会检查Hive SQL程序的语法是否正确,包括关…...
C语言学习:8、深入数据类型
数据超过类型规定的大小怎么办 C语言中,如果需要用的整数大于int类型的最大值了怎么办? 我们知道int能表示的最大数是2147483647,最小的数是-2147483648,为什么? 因为字32位系统中,寄存器是32位的&#…...
生成树协议 STP(spanning-tree protocol)
一、STP作用 1、消除环路:通过阻断冗余链路来消除网络中可能存在的环路。 2、链路备份:当活动路径发生故障时,激活备份链路,及时恢复网络连通性。 二、STP选举机制 1、目的:找到阻塞的端口 2、STP交换机的角色&am…...
【LeetCode】312.戳气球
题目 有 n 个气球,编号为0 到 n - 1,每个气球上都标有一个数字,这些数字存在数组 nums 中。 现在要求你戳破所有的气球。戳破第 i 个气球,你可以获得 nums[i - 1] * nums[i] * nums[i 1] 枚硬币。 这里的 i - 1 和 i 1 代表和…...
商业数据分析概论
🐳 我正在和鲸社区参加“商业数据分析训练营活动” https://www.heywhale.com/home/competition/6487de6649463ee38dbaf58b ,以下是我的学习笔记: 学习主题:波士顿房价数据快速查看 日期:2023.9.4 关键概念/知识点&…...
Golang GUI框架
Golang GUI框架fyne fyne简介第一个fyne应用fyne应用程序和运行循环fyne更新GUI内容fyne窗口处理fyne解决中文乱码问题fyne应用打包fyne画布和画布对象fyne容器和布局fyne绘制和动画fyne盒子布局fyne网格grid布局fyne网格包裹布局fyne边框布局fyne表单布局fyne中心布局fyne ma…...
LeetCode刷题笔记【24】:贪心算法专题-2(买卖股票的最佳时机II、跳跃游戏、跳跃游戏II)
文章目录 前置知识122.买卖股票的最佳时机II题目描述贪心-直观写法贪心-优化代码更简洁 55. 跳跃游戏题目描述贪心-借助ability数组贪心-只用int far记录最远距离 45.跳跃游戏II题目描述回溯算法贪心算法 总结 前置知识 参考前文 参考文章: LeetCode刷题笔记【23】…...
游戏出现卡顿有哪些因素
一、服务器CPU内存占用过大会导致卡顿,升级CPU内存或者优化自身程序占用都可以解决。 二、带宽跑满导致卡,可以升级带宽解决。 二、平常不卡,有大型的活动的时候会卡,这方面主要是服务器性能方面不够导致的,性能常说…...
学习Bootstrap 5的第八天
目录 加载器 彩色加载器 实例 闪烁加载器 实例 加载器大小 实例 加载器按钮 实例 分页 分页的基本结构 实例 活动状态 实例 禁用状态 实例 分页大小 实例 分页对齐 实例 面包屑(Breadcrumbs) 实例 加载器 彩色加载器 在 Bootstr…...
vue中自定义指令
什么是指令 在Vue.js中,指令是一种特殊的 token,用于在模板中以声明式方式将响应式数据绑定到 DOM 元素上,从而实现与 DOM 元素的交互和操作。指令以 “v-” 前缀开始,后跟指令的名称,例如 v-model、v-bind 和 v-on。…...
Python:安装Flask web框架hello world
安装easy_install pip install distribute 安装pip easy_install pip 安装 virtualenv pip install virtualenv 激活Flask pip install Flask 创建web页面demo.py from flask import Flask app Flask(__name__)app.route(/) def hello_world():return Hello World! 2023if _…...
shell脚本--常见案例
1、自动备份文件或目录 2、批量重命名文件 3、查找并删除指定名称的文件: 4、批量删除文件 5、查找并替换文件内容 6、批量创建文件 7、创建文件夹并移动文件 8、在文件夹中查找文件...
【位运算】消失的两个数字(hard)
消失的两个数字(hard) 题⽬描述:解法(位运算):Java 算法代码:更简便代码 题⽬链接:⾯试题 17.19. 消失的两个数字 题⽬描述: 给定⼀个数组,包含从 1 到 N 所有…...
将对透视变换后的图像使用Otsu进行阈值化,来分离黑色和白色像素。这句话中的Otsu是什么意思?
Otsu 是一种自动阈值化方法,用于将图像分割为前景和背景。它通过最小化图像的类内方差或等价地最大化类间方差来选择最佳阈值。这种方法特别适用于图像的二值化处理,能够自动确定一个阈值,将图像中的像素分为黑色和白色两类。 Otsu 方法的原…...
多种风格导航菜单 HTML 实现(附源码)
下面我将为您展示 6 种不同风格的导航菜单实现,每种都包含完整 HTML、CSS 和 JavaScript 代码。 1. 简约水平导航栏 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport&qu…...
html css js网页制作成品——HTML+CSS榴莲商城网页设计(4页)附源码
目录 一、👨🎓网站题目 二、✍️网站描述 三、📚网站介绍 四、🌐网站效果 五、🪓 代码实现 🧱HTML 六、🥇 如何让学习不再盲目 七、🎁更多干货 一、👨…...
《C++ 模板》
目录 函数模板 类模板 非类型模板参数 模板特化 函数模板特化 类模板的特化 模板,就像一个模具,里面可以将不同类型的材料做成一个形状,其分为函数模板和类模板。 函数模板 函数模板可以简化函数重载的代码。格式:templa…...
论文阅读笔记——Muffin: Testing Deep Learning Libraries via Neural Architecture Fuzzing
Muffin 论文 现有方法 CRADLE 和 LEMON,依赖模型推理阶段输出进行差分测试,但在训练阶段是不可行的,因为训练阶段直到最后才有固定输出,中间过程是不断变化的。API 库覆盖低,因为各个 API 都是在各种具体场景下使用。…...
【p2p、分布式,区块链笔记 MESH】Bluetooth蓝牙通信 BLE Mesh协议的拓扑结构 定向转发机制
目录 节点的功能承载层(GATT/Adv)局限性: 拓扑关系定向转发机制定向转发意义 CG 节点的功能 节点的功能由节点支持的特性和功能决定。所有节点都能够发送和接收网格消息。节点还可以选择支持一个或多个附加功能,如 Configuration …...
ZYNQ学习记录FPGA(一)ZYNQ简介
一、知识准备 1.一些术语,缩写和概念: 1)ZYNQ全称:ZYNQ7000 All Pgrammable SoC 2)SoC:system on chips(片上系统),对比集成电路的SoB(system on board) 3)ARM:处理器…...
第八部分:阶段项目 6:构建 React 前端应用
现在,是时候将你学到的 React 基础知识付诸实践,构建一个简单的前端应用来模拟与后端 API 的交互了。在这个阶段,你可以先使用模拟数据,或者如果你的后端 API(阶段项目 5)已经搭建好,可以直接连…...
