C语言小项目——通讯录
功能介绍:
1.联系人信息:姓名+年龄+性别+地址+电话
2.通讯录中可以存放100个人的信息
3.功能:
1>增加联系人
2>删除指定联系人
3>查找指定联系人的信息
4>修改指定联系人的信息
5显示所有联系人的信息
6>排序(名字)
我们将采用模块化设计,分为三个模块:
1. test.c ——— 测试通讯录
2. contact.c ——— 通讯录的声明
3. contact.h ——— 函数的声明
首先,我们需要一个菜单,以及主函数选择功能的部分。
```test.c
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>void menu()
{printf("*******************欢迎来到你的通讯录*******************\n");printf("**********1.添加联系人************2.删除联系人**********\n");printf("**********3.查找联系人************4.修改联系人**********\n");printf("**********5.显示联系人************6.联系人排序**********\n");printf("**********0.退出通讯录*********************************\n");printf("*******************欢迎来到你的通讯录*******************\n");
}
int main()
{int input = 0;do {menu();printf("请选择:>");scanf("%d", &input);switch (input){case 1:break;case 2:break;case 3:break;case 4:break;case 5:break;case 6:break;case 0:printf("退出通讯录");break;default:printf("选择错误\n");break;}} while (input);return 0;
}
```
- 在
main
函数中,使用do-while
循环不断调用menu
函数显示菜单,并使用scanf
函数获取用户的输入。然后通过switch
语句根据用户的输入执行相应的操作,如果输入为0
,则输出 “退出通讯录” 并结束程序;如果输入为其他值,则输出 “选择错误”。
那么通讯录中肯定需要人的信息,那么这些人的信息,我们可以把他封装成一个结构体。我们将这些类型信息放进头文件中,在这里我们将它放进已经创建好的contact.h中。
```contact.h
//人的信息
typedef struct Peopleinform
{char name[40];int age;char sex[5];char addr[20];char telephone[20];
}Peopleinform;
```
在这里,我们定义了一个名为
Peopleinform
的结构体类型,用于存储人员的信息。我们通过使用typedef
关键字,可以为这个结构体类型定义一个别名Peopleinform
,这样在后续的代码中就可以直接使用Peopleinform
来声明该类型的变量,而不需要每次都写完整的struct Peopleinform
。
我们继续往下写,接下来我们创建通讯录,我们可以声明一个名为data
的数组,数组的元素类型为Peopleinform
结构体,当然我们在这里必须添加contact.h头文件才能使用它。代码部分如下:
```test.c
#include<stdio.h>
#include"contact.h"
/* --省略void menu部分--*/
int main()
{int input = 0;//创建通讯录Peopleinform data[100];do {menu();printf("请选择:>");scanf("%d", &input);/*-- 省略switch部分 --*/} while (input);return 0;
}
```
在我们的项目中,自己创建的头文件通常用双引号''"包裹起来,这样我们就可以在.c文件中使用它啦!当然,我们如果把这个通讯录存放人的信息的容量,以及可以显示的当前创建的人的信息封装起来,变成一个结构体。为了方便之后修改我们增加一个预处理器指令#define MAX 100
```contact.h
#define MAX 100
typedef struct Contact
{Peopleinform data[MAX];//存放人的信息的容量int sz;//当前存放信息的个数
}Contact;
```
那么我们如果想在主函数中使用,只需要创建一个名为con
的Contact
类型的对象。这样就可以使用con
来存储和操作通讯录相关的数据了。接着我们初始化通讯录。并在contact.h头文件中为他声明。
```test.c
int main()
{int input = 0;//创建通讯录Contact con;//创建一个名为con的Contact对象//初始化通讯录InitContact(&con);do {menu();printf("请选择:>");scanf("%d", &input);/*-- 省略switch部分 --*/} while (input);
```
```contact.h
void InitContact(Contact *pc);
```
接下来,contact.c文件终于出场了,由于我们在contact.h头文件声明过void InitContact(Contact *pc); 接下来,我们就可以在contact.c直接使用它。
我们给这个Contact
结构体的函数初始化一下:
```contact.c
#include"contact.h"
void InitContact(Contact* pc)
{pc->sz=0;memset(pc->data,0,sizeof(pc->data));
}
```
这里我们选择使用memset函数进行初始化,
(注:memset
函数是 C 标准库中的一个函数,定义在<string.h>
头文件中。它的作用是将一段内存区域设置为指定的值。函数原型为void *memset(void *s, int c, size_t n)
,其中s
是指向要填充的内存块的指针,c
是要设置的值,n
是要填充的字节数。)
紧接着,我们在Switch()语句中,加入我们目前需要的语句,我们现在来写添加联系人模块。
添加联系人模块
```contact.h
//增加联系人
void AddContact(Contact* pc);
```
```contact.c
void AddContact(Contact* pc)
{if (pc->sz == MAX){printf("通讯录已满!无法添加!\n");return;}//增加一个人的信息printf("请输入名字:>");scanf("%s", pc->data[pc->sz].name);printf("请输入年龄:>");scanf("%s", &pc->data[pc->sz].age);printf("请输入性别:>");scanf("%s", pc->data[pc->sz].sex);printf("请输入地址:>");scanf("%s", pc->data[pc->sz].addr);printf("请输入电话:>");scanf("%s", pc->data[pc->sz].telephone);pc->sz++;
}
```
(注:在
InitContact
和AddContact
函数中,pc
用于访问和修改调用者提供的Contact
结构体实例。当调用这些函数时,传递的是Contact
结构体变量的地址,函数内部通过这个指针来操作外部传入的结构体。)
pc-sz++; 的作用
假设
sz
初始值为5
,执行pc->sz++;
后,sz
的值变为6
,表示通讯录中联系人的数量从5
个增加到了6
个。 这对于跟踪通讯录中实际存储的联系人数量非常重要,在后续的操作,如显示联系人列表、检查通讯录是否已满等功能中,都依赖这个计数。
显示联系人模块
显示联系人模块也是一样,我们现将函数声明放在头文件当中,
void ShowContact(const Contact* pc);
然后我们用一个for
循环遍历pc->data
数组,其中,pc->data
数组存储了所有联系人的信息,循环条件i < pc->sz
确保只遍历已存储联系人的部分,pc->sz
表示当前通讯录中实际存储的联系人数量。
```contact.c
void ShowContact(Contact* pc)
{int i = 0;printf("%s\t%-5s\t%-5s\t%-5s\t%-5s\t\n", "姓名","年齡","性別","地址","電話");for (i = 0; i < pc->sz; i++){printf("%s\t%d\t%s\t%s\t%s\t",pc->data[i].name,pc->data[i].age,pc->data[i].sex,pc->data[i].addr,pc->data[i].telephone);}
}
```
这样,我们就基本完成了这个显示联系人的设计啦!那么紧接着,我们如果想要删除这个指定的联系人,该怎么办呢?和上面一样,我们先在头文件中添加一个声明。
void DelContact(Contact* pc);
接着,我们在contact.c文件中去构建这个删除联系人模块,
删除联系人模块
void DelContact(Contact* pc)
{if (pc->sz ==0){printf("无可删除的联系人");return;}//删除//找到要删除的人printf("请输入要删除的人的名字:");scanf("%s", name);int i = 0;int del = 0;for (i = 0; i<pc->sz; i++){if(strcmp(pc->data[i].name,name))==0{del = i;break;}//删除for (i = 0; i < pc->sz; i++){pc->data[i] = pc->data[i + 1];}pc->sz--;printf("删除成功");}
}
当我们通讯录里面没有联系人的时候,我们输出“无可删除的联系人”。接着,我们使用 for
循环遍历联系人列表,使用 strcmp
函数比较每个联系人的名字和输入的名字,如果相等则将该元素的索引存储在 del
中并跳出循环。
那么接下来,我们可以发现的是,无论是删除模块、查找模块和修改模块中,我们都需要先找到联系人,才能进行下一步的操作,既然都需要,我们似乎就可以把这个查找部分封装成一个函数,
// 根据姓名查找联系人在数组中的位置,如果找到返回对应索引,未找到返回 -1
int FINDBY_NAME(const Contact* pc, char name[])
{int i = 0;for (i = 0; i < pc->sz; i++){if (strcmp(pc->data[i].name, name) == 0) // 比较字符串是否相等{return i; // 找到返回索引}}return -1; // 未找到返回 -1
}
替换后代码如下:
// 删除联系人的函数
void DelContact(Contact* pc)
{if (pc->sz == 0){printf("没有联系人可删除\n");return;}// 输入要删除的联系人姓名char name[40] = { 0 };printf("请输入要删除的联系人姓名: ");scanf("%s", name);int ret = FINDBY_NAME(pc, name);if (ret == -1){printf("要删除的联系人不存在\n");return;}// 删除操作,将后面的元素依次往前移for (int i = ret; i < pc->sz - 1; i++){pc->data[i] = pc->data[i + 1];}pc->sz--;printf("删除成功\n");
}
我们来看查找联系人模块,
查找联系人模块
void SerContact(const Contact* pc)
{char name[NAME_MAX] = { 0 };printf("请输入要查找人的名字:");scanf("%s",name);int pos = FINDBY_NAME(pc, name);if (-1 == pos){printf("要查找的人不存在\n");return;}//打印信息printf("%s\t%-5s\t%-5s\t%-5s\t%-5s\t\n", "姓名", "年齡", "性別", "地址", "電話");printf("%s\t%-5d\t%-5s\t%-5s\t%-5s\t\n", pc->data[pos].name,pc->data[pos].age,pc->data[pos].sex,pc->data[pos].addr,pc->data[pos].telephone);
}
我们查找模块,首先输入要查找的联系人姓名,调用 FINDBY_NAME
函数查找该联系人的位置,如果不存在则提示联系人不存在并返回。否则,打印该联系人的详细信息。
紧接着,我们再来看修改联系人,
修改联系人模块
//修改联系人
void ReviContact(Contact* pc)
{char name[NAME_MAX] = { 0 };printf("请输入要修改人的名字:");scanf("%s", name);int pos = FINDBY_NAME(pc, name);if (-1 == pos){printf("要修改的人不存在\n");return;}printf("请输入名字:>");scanf("%s", pc->data[pos].name);printf("请输入年龄:>");scanf("%d", &pc->data[pos].age);printf("请输入性别:>");scanf("%s", pc->data[pos].sex);printf("请输入地址:>");scanf("%s", pc->data[pos].addr);printf("请输入电话:>");scanf("%s", pc->data[pos].telephone);printf("修改完成\n");
}
我们想要修改联系人,首先肯定需要找到这个联系人,所以我们首先要查找,输入要修改的联系人姓名,调用FINDBY_NAME
函数可以查找该联系人的位置,如果不存在则提示联系人不存在并返回。否则,依次输入新的联系人信息。
排序联系人模块
最后一个模块,就是对这些联系人进行排序,这里使用使用冒泡排序算法,比较相邻联系人的姓名,如果前一个联系人的姓名大于后一个联系人的姓名,则交换它们的位置。
// 排序联系人(按姓名升序排序)
void SortContact(Contact* pc)
{int i, j;Peopleinform temp;for (i = 0; i < pc->sz - 1; i++){for (j = 0; j < pc->sz - i - 1; j++){if (strcmp(pc->data[j].name, pc->data[j + 1].name) > 0){temp = pc->data[j];pc->data[j] = pc->data[j + 1];pc->data[j + 1] = temp;}}}printf("联系人已按姓名排序\n");
}
strcmp
是 C 语言标准库 <string.h>
中的一个字符串比较函数,用于比较两个字符串的大小。
函数原型int strcmp(const char *str1, const char *str2);
在 SortContact
函数中,strcmp(pc->data[j].name, pc->data[j + 1].name) > 0
表示如果 pc->data[j].name
这个字符串在字典序上大于 pc->data[j + 1].name
这个字符串,就交换这两个联系人的信息,从而实现按姓名排序的功能。
源代码如下:
```contact.h
#pragma once
#include<stdio.h>
#include<string.h>
#define MAX 100
#define NAME_MAX 40 // 定义 NAME_MAX 的大小
// 个人信息
typedef struct Peopleinform
{char name[40];int age;char sex[5];char addr[20];char telephone[20];
}Peopleinform;
typedef struct Contact
{Peopleinform data[MAX];// 存储个人信息的数组int sz;// 当前存储信息的数量
}Contact;// 初始化通讯录
void InitContact(Contact* pc);
// 添加联系人
void AddContact(Contact* pc);
// 删除联系人
void DelContact(Contact* pc);
// 查找联系人
void SerContact(const Contact* pc);
// 修改联系人
void ReviContact(Contact* pc);
// 排序联系人
void SortContact(Contact* pc);
// 显示联系人
void ShowContact(const Contact* pc);
```
```contact.c
#define _CRT_SECURE_NO_WARNINGS
#include"contact.h"
void InitContact(Contact* pc)
{pc->sz = 0;memset(pc->data, 0, sizeof(pc->data));
}
void AddContact(Contact* pc)
{char name[NAME_MAX] = { 0 };if (pc->sz == MAX){printf("通讯录已满!无法添加!\n");return;}//增加一个人的信息printf("请输入名字:>");scanf("%s", pc->data[pc->sz].name);printf("请输入年龄:>");scanf("%d", &pc->data[pc->sz].age);printf("请输入性别:>");scanf("%s", pc->data[pc->sz].sex);printf("请输入地址:>");scanf("%s", pc->data[pc->sz].addr);printf("请输入电话:>");scanf("%s", pc->data[pc->sz].telephone);pc->sz++;
}// 根据姓名查找联系人在数组中的位置,如果找到返回对应索引,未找到返回 -1
int FINDBY_NAME(const Contact* pc, char name[])
{int i = 0;for (i = 0; i < pc->sz; i++){if (strcmp(pc->data[i].name, name) == 0) // 比较字符串是否相等{return i; // 找到返回索引}}return -1; // 未找到返回 -1
}// 删除联系人的函数
void DelContact(Contact* pc)
{if (pc->sz == 0){printf("没有联系人可删除\n");return;}// 输入要删除的联系人姓名char name[40] = { 0 };printf("请输入要删除的联系人姓名: ");scanf("%s", name);int ret = FINDBY_NAME(pc, name);if (ret == -1){printf("要删除的联系人不存在\n");return;}// 删除操作,将后面的元素依次往前移for (int i = ret; i < pc->sz - 1; i++){pc->data[i] = pc->data[i + 1];}pc->sz--;printf("删除成功\n");
}
//查找联系人
void SerContact(const Contact* pc)
{char name[NAME_MAX] = { 0 };printf("请输入要查找人的名字:");scanf("%s",name);int pos = FINDBY_NAME(pc, name);if (-1 == pos){printf("要查找的人不存在\n");return;}//打印信息printf("%s\t%-5s\t%-5s\t%-5s\t%-5s\t\n", "姓名", "年齡", "性別", "地址", "電話");printf("%s\t%-5d\t%-5s\t%-5s\t%-5s\t\n", pc->data[pos].name,pc->data[pos].age,pc->data[pos].sex,pc->data[pos].addr,pc->data[pos].telephone);
}
//修改联系人
void ReviContact(Contact* pc)
{char name[NAME_MAX] = { 0 };printf("请输入要修改人的名字:");scanf("%s", name);int pos = FINDBY_NAME(pc, name);if (-1 == pos){printf("要修改的人不存在\n");return;}printf("请输入名字:>");scanf("%s", pc->data[pos].name);printf("请输入年龄:>");scanf("%d", &pc->data[pos].age);printf("请输入性别:>");scanf("%s", pc->data[pos].sex);printf("请输入地址:>");scanf("%s", pc->data[pos].addr);printf("请输入电话:>");scanf("%s", pc->data[pos].telephone);printf("修改完成\n");
}
// 排序联系人(按姓名升序排序)
void SortContact(Contact* pc)
{int i, j;Peopleinform temp;for (i = 0; i < pc->sz - 1; i++){for (j = 0; j < pc->sz - i - 1; j++){if (strcmp(pc->data[j].name, pc->data[j + 1].name) > 0){temp = pc->data[j];pc->data[j] = pc->data[j + 1];pc->data[j + 1] = temp;}}}printf("联系人已按姓名排序\n");
}// 显示所有联系人信息的函数
void ShowContact(const Contact* pc)
{int i = 0;printf("%s\t%-5s\t%-5s\t%-5s\t%-5s\t\n", "姓名", "年龄", "性别", "地址", "电话");for (i = 0; i < pc->sz; i++){printf("%s\t%d\t%s\t%s\t%s\n", pc->data[i].name,pc->data[i].age,pc->data[i].sex,pc->data[i].addr,pc->data[i].telephone);}
}
```
```test.c
#define _CRT_SECURE_NO_WARNINGS
#include"contact.h"void menu()
{printf("*******************欢迎来到你的通讯录*******************\n");printf("**********1.添加联系人************2.删除联系人**********\n");printf("**********3.查找联系人************4.修改联系人**********\n");printf("**********5.显示联系人************6.联系人排序**********\n");printf("**********0.退出通讯录**********************************\n");printf("*******************欢迎来到你的通讯录*******************\n");
}
int main()
{int input = 0;//创建通讯录Contact con;//创建一个名为con的Contact对象//初始化通讯录InitContact(&con);do {menu();printf("请选择:>");if (scanf("%d", &input) != 1) {// 处理输入错误的情况,例如提示用户重新输入printf("输入错误,请重新输入\n");// 清空输入缓冲区while (getchar() != '\n');continue;}switch (input){case 1:AddContact(&con);break;case 2:DelContact(&con);break;case 3:SerContact(&con);break;case 4:ReviContact(&con);break;case 5:ShowContact(&con);break;case 6:SortContact(&con);case 0:printf("退出通讯录");break;default:printf("选择错误\n");break;}} while (input!=0);
}
```
相关文章:
C语言小项目——通讯录
功能介绍: 1.联系人信息:姓名年龄性别地址电话 2.通讯录中可以存放100个人的信息 3.功能: 1>增加联系人 2>删除指定联系人 3>查找指定联系人的信息 4>修改指定联系人的信息 5显示所有联系人的信息 6>排序(名字&…...

uni-app连接EventSource
前言 uniapp默认是不支持event-source,这里是借助renderjs进行SSE连接 正文 引入event-source-polyfill 这里演示的是直接将代码下载到本地进行引入 下载地址 把里面的eventsource.min.js文件放到项目中的static文件夹 项目封装event-source.vue组件 <templ…...
Spring Boot 实战:轻松实现文件上传与下载功能
目录 一、引言 二、Spring Boot 文件上传基础 (一)依赖引入 (二)配置文件设置 (三)文件上传接口编写 (一)文件类型限制 (二)文件大小验证 ࿰…...

火狐浏览器Firefox一些配置
没想到还会开这个…都是Ubuntu的错 一些个人习惯吧 标签页设置 常规-标签页 1.按最近使用顺序切换标签页 2.打开新标签而非新窗口(讨厌好多窗口) 3.打开新链接不直接切换过去(很打断思路诶) 4.关闭多个标签页时不向我确认 启动…...

[STM32 HAL库]串口中断编程思路
一、前言 最近在准备蓝桥杯比赛(嵌入式赛道),研究了以下串口空闲中断DMA接收不定长的数据,感觉这个方法的接收效率很高,十分好用。方法配置都成功了,但是有一个点需要进行考虑,就是一般我们需要…...

C++入门 详细版
欢迎来到干货小仓库!! 一分耕耘一分收获,离自己的目标越来越近。 passion!passion!!passion!!! 1.命名空间 由于C语言无法避免名字或者函数重复等问题,当有多…...

MIAOYUN信创云原生项目亮相西部“中试”生态对接活动
近日,以“构建‘中试’生态,赋能科技成果转化”为主题的“科创天府智汇蓉城”西部“中试”生态对接活动在成都高新区菁蓉汇隆重开幕。活动分为成果展览、“中试”生态主场以及成果路演洽谈对接三大板块。在成果展览环节,成都元来云志科技有限…...

网络编程 | UDP组播通信
1、什么是组播 在上一篇博客中,对UDP的广播通信进行了由浅入深的总结梳理,本文继续对UDP的知识体系进行探讨,旨在将UDP的组播通信由浅入深的讲解清楚。 组播是介于单播与广播之间,在一个局域网内,将某些主机添加到组中…...
T-SQL语言的语法
T-SQL深度解析与应用 T-SQL(Transact-SQL)是微软SQL Server使用的一种扩展SQL(结构化查询语言)。它不仅支持标准SQL的所有功能,而且增加了许多实用的扩展和特性,使得数据库的操作更加灵活和强大。本文将对…...
Java开发提效秘籍:巧用Apache Commons IO工具库
一、引言 在 Java 开发的广袤领域中,输入输出(I/O)操作宛如一座桥梁,连接着程序与外部世界,从文件的读取与写入,到网络数据的传输,I/O 操作无处不在,其重要性不言而喻。然而…...
第1章:Python TDD基础与乘法功能测试
写在前面 这本书是我们老板推荐过的,我在《价值心法》的推荐书单里也看到了它。用了一段时间 Cursor 软件后,我突然思考,对于测试开发工程师来说,什么才更有价值呢?如何让 AI 工具更好地辅助自己写代码,或许…...

web前端1--基础
(时隔数月我又来写笔记啦~) 1、下载vscode 1、官网下载:Visual Studio Code - Code Editing. Redefined 2、步骤: 1、点击同意 一直下一步 勾一个创建桌面快捷方式 在一直下一步 2、在桌面新建文件夹 拖到vscode图标上 打开v…...

.Net Core微服务入门全纪录(五)——Ocelot-API网关(下)
系列文章目录 1、.Net Core微服务入门系列(一)——项目搭建 2、.Net Core微服务入门全纪录(二)——Consul-服务注册与发现(上) 3、.Net Core微服务入门全纪录(三)——Consul-服务注…...

2024嵌入式系统的未来发展与技术洞察分享
时间如白驹过隙,不知不觉又是一年,这一年收获满满。接下来,将本年度对技术的感悟和洞察分析如下,希望对大家有所帮助。 在过去几十年里,嵌入式系统技术迅速发展,成为现代电子设备和智能硬件的核心组成部分。…...
python-44-嵌入式数据库SQLite和DuckDB
文章目录 1 SQLite1.1 世界上最流行的数据库1.1 SQLite简介1.2 插入语句1.3 查询数据1.4 更新数据1.5 删除数据2 DuckDB2.1 DuckDB简介2.2 DuckDB与Python结合使用2.2.1 创建表2.2.2 分析语句2.2.3 导出为parquet文件2.3 Windows中使用DuckDB3 参考附录1 SQLite Python的一个特…...

1.2.神经网络基础
目录 1.2.神经网络基础 1.2.1.Logistic回归 1.2.2 梯度下降算法 1.2.3 导数 1.2.4 向量化编程 1.2.5 正向传播与反向传播 1.2.6.练习 1.2.神经网络基础 1.2.1.Logistic回归 1.2.1.1.Logistic回归 逻辑回归是一个主要用于二分分类类的算法。那么逻辑回归是给定一个x ,…...
算法题目总结-双指针
文章目录 1.滑动窗口类型1.长度最小的子数组1.答案2.思路 2.无重复字符的最长子串1.答案2.思路 2.双指针类型1.盛最多水的容器1.答案2.思路 2.三数之和1.答案2.思路 1.滑动窗口类型 1.长度最小的子数组 1.答案 package com.sunxiansheng.arithmetic.day10;/*** Description:…...

人形机器人将制造iPhone!
前言 优必选机器人和富士康通过一项突破性的合作伙伴关系,正在将先进的人形机器人(如Walker S1及其升级版Walker S2)整合到制造流程中,以改变iPhone的生产方式。这一合作旨在通过提升机器人能力、优化工作流程以及实现更智能的自动…...
redis 各个模式的安装
一、Redis单机安装 1、安装gcc依赖 Redis是C语言编写的,编译需要GCC。 Redis6.x.x版本支持了多线程,需要gcc的版本大于4.9,但是CentOS7的默认版本是4.8.5。 升级gcc版本: yum -y install centos-release-scl yum -y install d…...

《王者荣耀》皮肤爬虫源码
1.爬取网页 https://pvp.qq.com/web201605/herolist.shtml 2.python代码 import requests from bs4 import BeautifulSoup import os import threading from queue import Queuedef mul(x):if not os.path.exists(x):os.mkdir(x)print("目录创建成功")else:pass h…...
东芝Toshiba e-STUDIO2110AC打印机信息
基本信息 产品类型:数码复合机颜色类型:彩色涵盖功能:复印、打印、扫描接口类型:标配为 Ethernet(RJ45)10/100/1000BASE - T、USB2.0 高速;选配为 Wireless Lan、IEEE802.11b/g/n、blueteeth。中…...
IOS 打包账号发布上传和IOS Xcode证书配置
xcode下载 https://developer.apple.com/download/all/ App发布 https://appstoreconnect.apple.com/ https://appstoreconnect.apple.com/teams/83ba877c-af24-4fa5-aaf2-e9b9b6066e82/apps/6473148620/testflight/groups/eb983352-b2e2-4c29-bbb7-071bf7287795 https://devel…...

使用 HTML + JavaScript 实现文章逐句高亮朗读功能
在这个信息爆炸的时代,我们每天都要面对大量的文字阅读。无论是学习、工作还是个人成长,阅读都扮演着至关重要的角色。然而,在快节奏的生活中,我们往往难以找到足够的安静时间专注于阅读。本文用 HTML JavaScript 实现了一个基于…...
NGINX `ngx_stream_core_module` 模块概览
一、模块定位与功能 通用 TCP/UDP 代理 支持同时处理 TCP 和 UDP 流量,透明转发请求到后端服务器组(upstream)。可作为四层负载均衡,根据客户端 IP、权重、最少连接等策略将连接分发给后端。 预读(preread)…...

html文字红色粗体,闪烁渐变动画效果,中英文切换版本
1. 代码 <!DOCTYPE html> <html lang"zh"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>红色粗体闪烁文字表格 - 中英文切换</t…...

五、查询处理和查询优化
五、查询处理和查询优化 主要内容 查询概述查询处理过程关系操作的基本实现算法查询优化技术代数优化基于存取路径的优化基于代价估算的优化 1. 查询概述 查询是数据库管理系统中使用最频繁、最基本的操作,对系统性能有很大影响。 对于同一个SQL查询,…...

基于开源AI大模型与AI智能名片的S2B2C商城小程序源码优化:企业成本管理与获客留存的新范式
摘要:本文以企业成本管理的两大核心——外部成本与内部成本为切入点,结合开源AI大模型、AI智能名片及S2B2C商城小程序源码技术,构建了企业数字化转型的“技术-成本-运营”三维模型。研究结果表明,通过AI智能名片实现获客留存效率提…...

Google机器学习实践指南(机器学习模型泛化能力)
🔥 Google机器学习(14)-机器学习模型泛化能力解析 Google机器学习(14)-机器学习模型泛化原理与优化(约10分钟) 一、泛化问题引入 ▲ 模型表现对比: 假设森林中树木健康状况预测模型: 图1:初始模型表现 …...
【MySQL基础】数据库的备份与还原
MySQL学习: https://blog.csdn.net/2301_80220607/category_12971838.html?spm1001.2014.3001.5482 前言: 在数据库管理中,删除操作是不可逆的,因此备份是数据安全的重要保障。下面我将详细介绍MySQL数据库删除前的备份方法&am…...

用go从零构建写一个RPC(4)--gonet网络框架重构+聚集发包
在追求高性能的分布式系统中,RPC 框架的底层网络能力和数据传输效率起着决定性作用。经过几轮迭代优化,我完成了第四版本的 RPC 框架。相比以往版本,这一版本的最大亮点在于 重写了底层网络框架 和 实现了发送端的数据聚集机制,这…...