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 _…...
web vue 项目 Docker化部署
Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段: 构建阶段(Build Stage):…...

cf2117E
原题链接:https://codeforces.com/contest/2117/problem/E 题目背景: 给定两个数组a,b,可以执行多次以下操作:选择 i (1 < i < n - 1),并设置 或,也可以在执行上述操作前执行一次删除任意 和 。求…...
工业自动化时代的精准装配革新:迁移科技3D视觉系统如何重塑机器人定位装配
AI3D视觉的工业赋能者 迁移科技成立于2017年,作为行业领先的3D工业相机及视觉系统供应商,累计完成数亿元融资。其核心技术覆盖硬件设计、算法优化及软件集成,通过稳定、易用、高回报的AI3D视觉系统,为汽车、新能源、金属制造等行…...

什么是Ansible Jinja2
理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具,可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板,允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板,并通…...
MySQL JOIN 表过多的优化思路
当 MySQL 查询涉及大量表 JOIN 时,性能会显著下降。以下是优化思路和简易实现方法: 一、核心优化思路 减少 JOIN 数量 数据冗余:添加必要的冗余字段(如订单表直接存储用户名)合并表:将频繁关联的小表合并成…...

Linux nano命令的基本使用
参考资料 GNU nanoを使いこなすnano基础 目录 一. 简介二. 文件打开2.1 普通方式打开文件2.2 只读方式打开文件 三. 文件查看3.1 打开文件时,显示行号3.2 翻页查看 四. 文件编辑4.1 Ctrl K 复制 和 Ctrl U 粘贴4.2 Alt/Esc U 撤回 五. 文件保存与退出5.1 Ctrl …...
Python Einops库:深度学习中的张量操作革命
Einops(爱因斯坦操作库)就像给张量操作戴上了一副"语义眼镜"——让你用人类能理解的方式告诉计算机如何操作多维数组。这个基于爱因斯坦求和约定的库,用类似自然语言的表达式替代了晦涩的API调用,彻底改变了深度学习工程…...
python爬虫——气象数据爬取
一、导入库与全局配置 python 运行 import json import datetime import time import requests from sqlalchemy import create_engine import csv import pandas as pd作用: 引入数据解析、网络请求、时间处理、数据库操作等所需库。requests:发送 …...
uniapp 实现腾讯云IM群文件上传下载功能
UniApp 集成腾讯云IM实现群文件上传下载功能全攻略 一、功能背景与技术选型 在团队协作场景中,群文件共享是核心需求之一。本文将介绍如何基于腾讯云IMCOS,在uniapp中实现: 群内文件上传/下载文件元数据管理下载进度追踪跨平台文件预览 二…...
如何配置一个sql server使得其它用户可以通过excel odbc获取数据
要让其他用户通过 Excel 使用 ODBC 连接到 SQL Server 获取数据,你需要完成以下配置步骤: ✅ 一、在 SQL Server 端配置(服务器设置) 1. 启用 TCP/IP 协议 打开 “SQL Server 配置管理器”。导航到:SQL Server 网络配…...