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 _…...
IDEA运行Tomcat出现乱码问题解决汇总
最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…...
vue3 定时器-定义全局方法 vue+ts
1.创建ts文件 路径:src/utils/timer.ts 完整代码: import { onUnmounted } from vuetype TimerCallback (...args: any[]) > voidexport function useGlobalTimer() {const timers: Map<number, NodeJS.Timeout> new Map()// 创建定时器con…...
BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践
6月5日,2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席,并作《智能体在安全领域的应用实践》主题演讲,分享了在智能体在安全领域的突破性实践。他指出,百度通过将安全能力…...
Java入门学习详细版(一)
大家好,Java 学习是一个系统学习的过程,核心原则就是“理论 实践 坚持”,并且需循序渐进,不可过于着急,本篇文章推出的这份详细入门学习资料将带大家从零基础开始,逐步掌握 Java 的核心概念和编程技能。 …...
力扣-35.搜索插入位置
题目描述 给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。 请必须使用时间复杂度为 O(log n) 的算法。 class Solution {public int searchInsert(int[] nums, …...
BLEU评分:机器翻译质量评估的黄金标准
BLEU评分:机器翻译质量评估的黄金标准 1. 引言 在自然语言处理(NLP)领域,衡量一个机器翻译模型的性能至关重要。BLEU (Bilingual Evaluation Understudy) 作为一种自动化评估指标,自2002年由IBM的Kishore Papineni等人提出以来,…...
Golang——7、包与接口详解
包与接口详解 1、Golang包详解1.1、Golang中包的定义和介绍1.2、Golang包管理工具go mod1.3、Golang中自定义包1.4、Golang中使用第三包1.5、init函数 2、接口详解2.1、接口的定义2.2、空接口2.3、类型断言2.4、结构体值接收者和指针接收者实现接口的区别2.5、一个结构体实现多…...
stm32wle5 lpuart DMA数据不接收
配置波特率9600时,需要使用外部低速晶振...
【实施指南】Android客户端HTTPS双向认证实施指南
🔐 一、所需准备材料 证书文件(6类核心文件) 类型 格式 作用 Android端要求 CA根证书 .crt/.pem 验证服务器/客户端证书合法性 需预置到Android信任库 服务器证书 .crt 服务器身份证明 客户端需持有以验证服务器 客户端证书 .crt 客户端身份…...
深入解析 ReentrantLock:原理、公平锁与非公平锁的较量
ReentrantLock 是 Java 中 java.util.concurrent.locks 包下的一个重要类,用于实现线程同步,支持可重入性,并且可以选择公平锁或非公平锁的实现方式。下面将详细介绍 ReentrantLock 的实现原理以及公平锁和非公平锁的区别。 ReentrantLock 实现原理 基本架构 ReentrantLo…...
