当前位置: 首页 > news >正文

C语言之通讯录的实现篇优化版

目录

动态内存管理

通讯录声明

静态版本 

 动态版本

 ​初始化通讯录

静态版本

动态版本

Add增加通讯录

静态版本

动态版本

 Checkcapacity增容

DestroyContact释放动态空间 

文件操作

SaveContact保存信息到文件中 

初始化通讯录

旧版本

文件版本

LoadContact加载文件信息到通讯录

test.c

contact.h

contact.c


我们前面已经学习完 动态内存管理 和 C语言操作文件,相信你对内存的管理和操作有了更加深入的了解。那我们今天接着来优化一下前面我们写过的通讯录。

  • 特别提醒:函数如果放在后面,在使用函数前面必须声明!!

动态内存管理

使用动态内存相关的知识优化通讯录。主要是从增加内存的方面去优化。我们设置为以下规则,注意这种设置仅仅为了方便讲解和测试仅此而已。后期大家可以设置为自己想要的规则。

  • 通讯录刚刚开始可以存放3个人的信息。
  • 通讯录放满,可以增加容量,每次增加2个人的信息的空间。

通讯录声明

静态版本 

//通讯录---存放结构体的数组--每个结构体就是一个人的信息
typedef struct Contact
{PeoInfo data[MAX];//存放数据int sz;//记录当前通讯录中存放的人的信息个数
}Contact;

 动态版本

//动态版本
typedef struct Contact
{PeoInfo* data;//存放数据,可修改数组内存的空间了
//🆗PeoInfo结构体类型的指针int sz;//记录当前通讯录中存放的人的信息个数int capacity;//记录的是通讯录的当前容量
}Contact;
  • 当通讯录中存放的人的信息个数 sz == 通讯录当前容量 capacity就可以考虑增加容量问题。
  • 目前的data是没有空间的,需要在初始化的时候在堆区开辟3个人的信息空间。
  • PeoInfo* data  存放数据,可修改数组内存的空间了,🆗PeoInfo结构体类型的指针
  • PeoInfo* data  指针维护开辟的空间

 ​初始化通讯录

静态版本

void InitContact(Contact* pc)
{assert(pc);pc->sz = 0;memset(pc->data, 0, sizeof(pc->data));
}

动态版本

#define DEFAULT_SZ 3 //后期容易修改
void InitContact(Contact* pc)
{assert(pc);pc->sz = 0;pc->capacity = DEFAULT_SZ;pc->data = calloc(pc->capacity ,sizeof(PeoInfo));if (pc->data == NULL){perror("InitContact->calloc");return;}
}
  •  PeoInfo* data  指针维护开辟的空间

Add增加通讯录

静态版本

void AddContact(Contact* pc)
{assert(pc);printf("请输入名字\n");scanf("%s", pc->data[pc->sz].name);//name是数组名,不用&printf("请输入年龄\n");scanf("%d", &(pc->data[pc->sz].age));//printf("请输入性别\n");scanf("%s", pc->data[pc->sz].sex);printf("请输入电话\n");scanf("%s", pc->data[pc->sz].tele);printf("请输入地址\n");scanf("%s", pc->data[pc->sz].addr);//pc->sz++;printf("增加成功\n");
}

动态版本

#define DEFAULT_INC 2//后期容易修改
//动态版本
void AddContact(Contact* pc)
{assert(pc);//满了增加容量if (pc->sz == pc->capacity){PeoInfo* ptr = (PeoInfo*)realloc(pc->data, (pc->capacity + DEFAULT_INC) * sizeof(PeoInfo));if (ptr != NULL){pc->data = ptr;}else{perror("AddContact->realloc");return;}}//不需要增容填写人信息printf("请输入名字\n");scanf("%s", pc->data[pc->sz].name);//name是数组名,不用&printf("请输入年龄\n");scanf("%d", &(pc->data[pc->sz].age));//printf("请输入性别\n");scanf("%s", pc->data[pc->sz].sex);printf("请输入电话\n");scanf("%s", pc->data[pc->sz].tele);printf("请输入地址\n");scanf("%s", pc->data[pc->sz].addr);//pc->sz++;printf("增加成功\n");
}
  • 当通讯录中存放的人的信息个数 sz == 通讯录当前容量 capacity就可以考虑增加容量问题。

当然也可以封装成函数Checkcapacity 

 Checkcapacity增容

Checkcapacity(pc);
void Checkcapacity(Contact* pc)
{if (pc->sz == pc->capacity){PeoInfo* ptr = (PeoInfo*)realloc(pc->data, (pc->capacity + DEFAULT_INC) * sizeof(PeoInfo));if (ptr != NULL){pc->data = ptr;}else{perror("AddContact->realloc");return;}}
}

 当然我们使用了动态内存的空间,我们必须手动释放和销毁,我们封装一个函数去销毁。

DestroyContact释放动态空间 

void DestroyContact(Contact* pc);
case EXIT:DestroyContact(&con);printf("退出通讯录\n");break;
void DestroyContact(Contact* pc)
{free(pc->data);pc->data = NULL;pc->sz = 0;pc->capacity = 0;
}

文件操作

程序退出之后,输入的信息都丢了。所以在通讯录之前最好把我们输入的信息全部保存到文件里。

SaveContact保存信息到文件中 

//保存信息到文件
void SaveContact(Contact* pc);
case EXIT://保存通讯录中的数据到文件中SaveContact(&con);DestroyContact(&con);printf("退出通讯录\n");break;
void SaveContact(Contact* pc)
{//打开文件FILE* pf = fopen("contact.txt", "wb");//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);fwrite(pc->data+i, sizeof(PeoInfo), 1, pf);}//关闭文件fclose(pf);pf = NULL;
}
  • 字符以ASCII码和二进制的存储的方式相同
  • 整型以ASCII码和二进制的存储的方式不同

初始化通讯录

但是当程序再次跑起来的时候,还是看不到信息??所以我们需要在执行通讯录等一系列的功能之前我们就要从文件里读取到数据信息。我们去修改初始化部分

旧版本

void InitContact(Contact* pc)
{assert(pc);pc->sz = 0;pc->capacity = DEFAULT_SZ;pc->data = calloc(pc->capacity * sizeof(PeoInfo));if (pc->data == NULL){perror("InitContact->calloc");return;}
}

文件版本

//文件版本
void InitContact(Contact* pc)
{assert(pc);pc->sz = 0;pc->capacity = DEFAULT_SZ;pc->data = calloc(pc->capacity * sizeof(PeoInfo));if (pc->data == NULL){perror("InitContact->calloc");return;}LoadContact(pc);
}

LoadContact加载文件信息到通讯录

//加载文件信息到通讯录
void LoadContact(Contact* pc);
void Checkcapacity(Contact* pc);//声明void LoadContact(Contact* pc)
{//打开文件FILE* pf = fopen("contact.txt", "rb");//以二进制的形式读if (pf == NULL){perror("LoadContact");return;}//读文件PeoInfo tmp = { 0 };//创建临时变量,结构体PeoInfo类型while (fread(&tmp, sizeof(PeoInfo), 1, pf))//读到就返回1,没有读到就返回0,一个一个读直到没有读到为0跳出循环{Checkcapacity(pc);//若文件中有5个人,但是这里只有3个人的容量,首先判断需不需要增容pc->data[pc->sz] = tmp;pc->sz++;}//关闭文件fclose(pf);pf = NULL;
}

test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"contact.h"
void menu()
{printf("************************************\n");printf("********1.add      2.del************\n");printf("********3.search   4.modify*********\n");printf("********5.show     6.sort***********\n");printf("********0.exit           ***********\n");printf("************************************\n");
}
enum Option
{EXIT,//0ADD,//1DEL,//2SEARCH,//3MODIFY,//4SHOW,//5SORT,//6	
};
int main()
{int input = 0;//创建通讯录Contact con;//初始化通讯录InitContact(&con);do{menu();printf("请输入你的选择:>\n");scanf("%d", &input);switch (input)//这里为了代码更加清晰用枚举常量{case ADD:AddContact(&con);break;case DEL:DelContact(&con);break;case SEARCH:SearchContact(&con);break;case MODIFY:ModifyContact(&con);break;case SHOW:ShowContact(&con);break;case SORT://SortContact(&con);break;case EXIT://保存通讯录中的数据到文件中SaveContact(&con);DestroyContact(&con);printf("退出通讯录\n");break;default:printf("选择错误,请重新选择:>\n");break;}} while (input);return 0;
}

contact.h

#pragma once
#include<stdio.h>
#include<string.h>
#include<assert.h>
#define NAME_MAX 20
#define SEX_MAX 20
#define TELE_MAX 20
#define ADDR_MAX 30
#define MAX 100
#define DEFAULT_SZ 3
#define DEFAULT_INC 2
typedef struct PeoInfo
{char name[NAME_MAX];int age;char sex[SEX_MAX];char tele[TELE_MAX];char addr[ADDR_MAX];
}PeoInfo;//静态版本
//typedef struct Contact
//{
//	PeoInfo data[MAX];//存放数据
//	int sz;//记录当前通讯录中存放的人的信息个数
//}Contact;//动态版本
typedef struct Contact
{PeoInfo* data;//存放数据int sz;//记录当前通讯录中存放的人的信息个数int capacity;//记录的是通讯录的当前容量
}Contact;//初始化通讯录
void InitContact(Contact* pc);
//增加个人信息
void AddContact(Contact* pc);
//展示个人信息
void ShowContact(Contact* pc);
//删除个人信息
void DelContact(Contact *pc);
//查找个人信息
void SearchContact(Contact* pc);
//修改个人信息
void ModifyContact(Contact* pc);
//排序
//void SortContact(Contact* pc);
//释放空间
void DestroyContact(Contact* pc);
//保存信息到文件
void SaveContact(Contact* pc);
//加载文件信息到通讯录
void LoadContact(Contact* pc);

contact.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"contact.h"//初始化静态版本
//void InitContact(Contact* pc)
//{
//	assert(pc);
//	pc->sz = 0;
//	memset(pc->data, 0, sizeof(pc->data));
//}//动态版本
//void InitContact(Contact* pc)
//{
//	assert(pc);
//	pc->sz = 0;
//	pc->capacity = DEFAULT_SZ;
//	pc->data = calloc(pc->capacity * sizeof(PeoInfo));
//	if (pc->data == NULL)
//	{
//		perror("InitContact->calloc");
//		return;
//	}
//}//文件版本
void Checkcapacity(Contact* pc);//声明
void LoadContact(Contact* pc)
{//打开文件FILE* pf = fopen("contact.txt", "rb");//以二进制的形式读if (pf == NULL){perror("LoadContact");return;}//读文件PeoInfo tmp = { 0 };while (fread(&tmp, sizeof(PeoInfo), 1, pf)){Checkcapacity(pc);pc->data[pc->sz] = tmp;pc->sz++;}//关闭文件fclose(pf);pf = NULL;
}
void InitContact(Contact* pc)
{assert(pc);pc->sz = 0;pc->capacity = DEFAULT_SZ;pc->data = calloc(pc->capacity * sizeof(PeoInfo));if (pc->data == NULL){perror("InitContact->calloc");return;}LoadContact(pc);
}//增加静态版本
//void AddContact(Contact* pc)
//{
//	assert(pc);
//	printf("请输入名字\n");
//	scanf("%s", pc->data[pc->sz].name);//name是数组名,不用&
//	printf("请输入年龄\n");
//	scanf("%d", &(pc->data[pc->sz].age));//
//	printf("请输入性别\n");
//	scanf("%s", pc->data[pc->sz].sex);
//	printf("请输入电话\n");
//	scanf("%s", pc->data[pc->sz].tele);
//	printf("请输入地址\n");
//	scanf("%s", pc->data[pc->sz].addr);
//	//
//	pc->sz++;
//	printf("增加成功\n");
//}//动态版本
void Checkcapacity(Contact* pc)
{if (pc->sz == pc->capacity){PeoInfo* ptr = (PeoInfo*)realloc(pc->data, (pc->capacity + 2) * sizeof(PeoInfo));if (ptr != NULL){pc->data = ptr;}else{perror("AddContact->realloc");return;}}
}void AddContact(Contact* pc)
{assert(pc);//满了增加容量Checkcapacity(pc);//不需要增容填写人信息printf("请输入名字\n");scanf("%s", pc->data[pc->sz].name);//name是数组名,不用&printf("请输入年龄\n");scanf("%d", &(pc->data[pc->sz].age));//printf("请输入性别\n");scanf("%s", pc->data[pc->sz].sex);printf("请输入电话\n");scanf("%s", pc->data[pc->sz].tele);printf("请输入地址\n");scanf("%s", pc->data[pc->sz].addr);//pc->sz++;printf("增加成功\n");
}//展示
void ShowContact(const Contact* pc)
{assert(pc);if (pc->sz == 0){printf("通讯录为空,无需打印\n");return 0;}int i = 0;//名字 年龄 性别 电话 地址//-左对齐//20是需要20字符的位置来放名字 printf("%-20s%-5s%-5s%-12s%-30s\n", "姓名", "年龄", "性别", "电话", "地址");for (i = 0; i < pc->sz; i++){printf("%-20s%-5d%-5s%-12s%-30s\n",pc->data[i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].tele, pc->data[i].addr);}
}//删除,查找,修改都需要使用
int FindByName(const Contact* pc, char name[])
{assert(pc);int i = 0;for (i = 0; i < pc->sz; i++){if (strcmp(pc->data[i].name, name) == 0){return i;}}return -1;
}//删除
void DelContact(Contact* pc)
{char name[NAME_MAX];//assert(pc);if (pc->sz == 0){printf("通讯录为空,无法删除\n");return;}printf("输入要删除的名字:>");scanf("%s", name);int ret = FindByName(pc, name);if (ret == -1){printf("要删除的人不存在\n");return;}//存在返回这个人的所在data的下标放入retint i = 0;for (i = ret; i < pc -> sz - 1; i++){pc->data[i] = pc->data[i + 1];}pc->sz--;printf("删除成功\n");
}//查找
void SearchContact(Contact* pc)
{char name[NAME_MAX];assert(pc);if (pc->sz == 0){printf("通讯录为空,无法查找\n");return;}//查找printf("输入要查找的名字:>");scanf("%s", name);int ret = FindByName(pc, name);if (ret == -1){printf("要查找的人不存在\n");return;}//返回下标显示这个的信息🆗printf("%-20s%-5s%-5s%-12s%-30s\n", "姓名", "年龄", "性别", "电话", "地址");printf("%-20s%-5d%-5s%-12s%-30s\n",pc->data[ret].name, pc->data[ret].age, pc->data[ret].sex, pc->data[ret].tele, pc->data[ret].addr);
}//修改
void ModifyContact(Contact* pc)
{char name[NAME_MAX];assert(pc);if (pc->sz == 0){printf("通讯录为空,无法修改\n");return;}//查找printf("输入要修改的名字:>");scanf("%s", name);int ret = FindByName(pc, name);if (ret == -1){printf("要修改的人不存在\n");return;}//修改assert(pc);printf("请输入名字\n");scanf("%s", pc->data[ret].name);//name是数组名,不用&printf("请输入年龄\n");scanf("%d", &(pc->data[ret].age));//printf("请输入性别\n");scanf("%s", pc->data[ret].sex);printf("请输入电话\n");scanf("%s", pc->data[ret].tele);printf("请输入地址\n");scanf("%s", pc->data[ret].addr);printf("修改成功\n");
}//释放动态空间
void DestroyContact(Contact* pc)
{free(pc->data);pc->data = NULL;pc->sz = 0;pc->capacity = 0;
}//写函数到文件中
void SaveContact(Contact* pc)
{//打开文件FILE* pf = fopen("contact.txt", "wb");//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);fwrite(pc->data+i, sizeof(PeoInfo), 1, pf);}//关闭文件fclose(pf);pf = NULL;
}

✔✔✔✔✔最后,感谢大家的阅读,若有错误和不足,欢迎指正!

接下来的博文会更新一些练习题,到实践中去加深对知识的理解。C语言的基本学习就快结束了,还是要多加练习。🆗

代码----------→【gitee:唐棣棣 (TSQXG) - Gitee.com】

联系----------→ 【邮箱:2784139418@qq.com】

相关文章:

C语言之通讯录的实现篇优化版

目录 动态内存管理 通讯录声明 静态版本 动态版本 ​初始化通讯录 静态版本 动态版本 Add增加通讯录 静态版本 动态版本 Checkcapacity增容 DestroyContact释放动态空间 文件操作 SaveContact保存信息到文件中 初始化通讯录 旧版本 文件版本 LoadContact加载…...

C++17中std::string_view的使用

为了解决std::string初始化(或拷贝)成本高昂的问题&#xff0c;C17引入了std::string_view。std::string_view提供对现有字符串(C风格字符串、std::string、或另一个std::string_view)的只读访问&#xff0c;而无需进行拷贝。当想要有效地处理和操作字符串而不修改它们时&#…...

C#,数值计算——分类与推理Phylo_nj的计算方法与源程序

1 文本格式 using System; using System.Collections.Generic; namespace Legalsoft.Truffer { public class Phylo_nj : Phylagglom { public double[] u; public override void premin(double[,] d, int[] nextp) { i…...

element-ui 图片压缩上传

picture.js export const compressImgNew (file) > {return new Promise(resolve > {const reader new FileReader()const image new Image()image.onload (imageEvent) > {const canvas document.createElement(canvas) // 创建画布const context canvas.getCo…...

【Java 进阶篇】Java XML约束:确保数据一致性和有效性

XML&#xff08;可扩展标记语言&#xff09;是一种常用的数据交换格式&#xff0c;用于存储和交换数据。然而&#xff0c;为了确保数据的一致性和有效性&#xff0c;通常需要定义XML约束。XML约束是一种规则集&#xff0c;定义了XML文档的结构、元素、属性和数据类型。本篇博客…...

第一章概述

一、学习目的与要求 本章对软件测试作了概括性的介绍&#xff0c;目的是使学生对软件测试有个初步的认识。通过本章的学习&#xff0c;应使学生掌握软件测试的基本概念&#xff0c;了解软件测试的发展历程和行业现状&#xff0c;掌握软件测试技术的分类&#xff0c;理解软件测试…...

XCode15与iOS17/17.1 真机测试问题处理

XCode15与iOS17/17.1 真机测试问题处理&#xff0c;网上相关博客很多&#xff0c;摘录了如下实践后能起作用的地址如下&#xff1a;Xcode 15 报错处理 - 简书iOS17版本适配-CSDN博客 Xcode15适配-六虎 主要介绍下&#xff1a;Assertion failure in void _UIGraphicsBeginImag…...

使用 Rust 和 cURL 库下载程序

以下是一个使用 Rust 和 cURL 库的下载器程序&#xff0c;用于下载 图像。此程序使用了 https://www.duoip.cn/get_proxy 的代码。 extern crate curl; ​ use std::io::{self, Read}; use std::error::Error; ​ fn main() {let url "https://www.baidu.com";let …...

三维模型表面积计算方法

【版权声明】 本文为博主原创文章&#xff0c;未经博主允许严禁转载&#xff0c;我们会定期进行侵权检索。 更多算法总结请关注我的博客&#xff1a;https://blog.csdn.net/suiyingy&#xff0c;或”乐乐感知学堂“公众号。 本文章来自于专栏《Python三维模型处理基础》的系列文…...

unity脚本_力 c#

创建一个脚本 将代码挂载到物体上 取消物体的重力 运行即向z轴运动 加力之后 是否停止是由阻力影响 如果阻力为零 则会一直运动 如果希望就算有阻力也让物体一直动就将加力代码放在Update函数里 using UnityEngine; public class Power : MonoBehaviour{ Rigidbody rigidBo…...

LeetCode 面试题 10.05. 稀疏数组搜索

文章目录 一、题目二、C# 题解 一、题目 稀疏数组搜索。有个排好序的字符串数组&#xff0c;其中散布着一些空字符串&#xff0c;编写一种方法&#xff0c;找出给定字符串的位置。 示例1: 输入: words [“at”, “”, “”, “”, “ball”, “”, “”, “car”, “”, “”…...

分类预测 | MATLAB实现基于BiLSTM-AdaBoost双向长短期记忆网络结合AdaBoost多输入分类预测

分类预测 | MATLAB实现基于BiLSTM-AdaBoost双向长短期记忆网络结合AdaBoost多输入分类预测 目录 分类预测 | MATLAB实现基于BiLSTM-AdaBoost双向长短期记忆网络结合AdaBoost多输入分类预测预测效果基本介绍模型描述程序设计参考资料 预测效果 基本介绍 1.MATLAB实现基于BiLSTM-…...

Sobel算子详解及例程

Sobel算子是一种经典的边缘检测算子&#xff0c;被广泛应用于图像处理领域。它基于图像亮度的变化率来检测边缘的位置&#xff0c;主要通过计算图像中像素点的梯度来实现。 Sobel算子分为水平和垂直两个方向的算子&#xff0c;记作Gx和Gy。它们分别对图像进行水平和垂直方向的…...

ScrapeKit 和 Swift 编写程序

以下是一个使用 ScrapeKit 和 Swift 编写的爬虫程序&#xff0c;用于爬取 图片。同时&#xff0c;我们使用了proxy 这段代码来获取代理。 import ScrapeKit ​ class PeopleImageCrawler: NSObject, ScrapeKit.Crawler {let url: URLlet proxyUrl: URL ​init(url: URL, proxy…...

Java基础面试题知识点总结(上篇)

大家好&#xff0c;我是栗筝i&#xff0c;从 2022 年 10 月份开始&#xff0c;我持续梳理出了全面的 Java 技术栈内容&#xff0c;一方面是对自己学习内容进行整合梳理&#xff0c;另一方面是希望对大家有所帮助&#xff0c;使我们一同进步。得到了很多读者的正面反馈。 而在 2…...

STM32进行LVGL裸机移植

本文的移植参考的是正点原子的课程《手把手教你学LVGL图形界面编程》 基于该课程和《LVGL开发指南_V1.3》“第二章 LVGL 无操作系统移植”&#xff0c;然后结合自身的实际情况进行整理。 先根据自己的习惯&#xff0c;创建基础的单片机工程&#xff0c;然后在APP业务层和DRIVE…...

python解析robot framework的output.xml并生成html

一、用pyh模块解析stat结点数据&#xff08;output.py&#xff09; #codingutf-8import xml.dom.minidom import xml.etree.ElementTree#打开xml文档 dom xml.dom.minidom.parse(./ui/output.xml);root2 xml.etree.ElementTree.parse(./ui/output.xml) #得到文档元素对象 ro…...

【RuoYi移动端】uni-app中的单击和双击事件

1、单击事件&#xff1a; click"enterpriseSelect" 2、双击事件&#xff1a; touchend"userinfo"...

使用 conda 在 Ubuntu 16.04 上安装 Python 3.9 的步骤:和 VSCode配置

一、使用conda在 Ubuntu 16.04 上安装 Python 3.9 的步骤: 当然可以,conda 是一个非常强大的包管理器,它可以方便地管理不同版本的 Python 和各种库包。以下是使用 conda 在 Ubuntu 16.04 上安装 Python 3.9 的步骤: 1. 安装 Miniconda Miniconda 是 Anaconda 的轻量级版…...

spring6-国际化:i18n | 数据校验:Validation

文章目录 1、国际化&#xff1a;i18n1.1、i18n概述1.2、Java国际化1.3、Spring6国际化1.3.1、MessageSource接口1.3.2、使用Spring6国际化 2、数据校验&#xff1a;Validation2.1、Spring Validation概述2.2、实验一&#xff1a;通过Validator接口实现2.3、实验二&#xff1a;B…...

变量 varablie 声明- Rust 变量 let mut 声明与 C/C++ 变量声明对比分析

一、变量声明设计&#xff1a;let 与 mut 的哲学解析 Rust 采用 let 声明变量并通过 mut 显式标记可变性&#xff0c;这种设计体现了语言的核心哲学。以下是深度解析&#xff1a; 1.1 设计理念剖析 安全优先原则&#xff1a;默认不可变强制开发者明确声明意图 let x 5; …...

web vue 项目 Docker化部署

Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段&#xff1a; 构建阶段&#xff08;Build Stage&#xff09;&#xff1a…...

C++实现分布式网络通信框架RPC(3)--rpc调用端

目录 一、前言 二、UserServiceRpc_Stub 三、 CallMethod方法的重写 头文件 实现 四、rpc调用端的调用 实现 五、 google::protobuf::RpcController *controller 头文件 实现 六、总结 一、前言 在前边的文章中&#xff0c;我们已经大致实现了rpc服务端的各项功能代…...

模型参数、模型存储精度、参数与显存

模型参数量衡量单位 M&#xff1a;百万&#xff08;Million&#xff09; B&#xff1a;十亿&#xff08;Billion&#xff09; 1 B 1000 M 1B 1000M 1B1000M 参数存储精度 模型参数是固定的&#xff0c;但是一个参数所表示多少字节不一定&#xff0c;需要看这个参数以什么…...

电脑插入多块移动硬盘后经常出现卡顿和蓝屏

当电脑在插入多块移动硬盘后频繁出现卡顿和蓝屏问题时&#xff0c;可能涉及硬件资源冲突、驱动兼容性、供电不足或系统设置等多方面原因。以下是逐步排查和解决方案&#xff1a; 1. 检查电源供电问题 问题原因&#xff1a;多块移动硬盘同时运行可能导致USB接口供电不足&#x…...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个生活电费的缴纳和查询小程序

一、项目初始化与配置 1. 创建项目 ohpm init harmony/utility-payment-app 2. 配置权限 // module.json5 {"requestPermissions": [{"name": "ohos.permission.INTERNET"},{"name": "ohos.permission.GET_NETWORK_INFO"…...

AspectJ 在 Android 中的完整使用指南

一、环境配置&#xff08;Gradle 7.0 适配&#xff09; 1. 项目级 build.gradle // 注意&#xff1a;沪江插件已停更&#xff0c;推荐官方兼容方案 buildscript {dependencies {classpath org.aspectj:aspectjtools:1.9.9.1 // AspectJ 工具} } 2. 模块级 build.gradle plu…...

使用 SymPy 进行向量和矩阵的高级操作

在科学计算和工程领域&#xff0c;向量和矩阵操作是解决问题的核心技能之一。Python 的 SymPy 库提供了强大的符号计算功能&#xff0c;能够高效地处理向量和矩阵的各种操作。本文将深入探讨如何使用 SymPy 进行向量和矩阵的创建、合并以及维度拓展等操作&#xff0c;并通过具体…...

云原生玩法三问:构建自定义开发环境

云原生玩法三问&#xff1a;构建自定义开发环境 引言 临时运维一个古董项目&#xff0c;无文档&#xff0c;无环境&#xff0c;无交接人&#xff0c;俗称三无。 运行设备的环境老&#xff0c;本地环境版本高&#xff0c;ssh不过去。正好最近对 腾讯出品的云原生 cnb 感兴趣&…...

iOS性能调优实战:借助克魔(KeyMob)与常用工具深度洞察App瓶颈

在日常iOS开发过程中&#xff0c;性能问题往往是最令人头疼的一类Bug。尤其是在App上线前的压测阶段或是处理用户反馈的高发期&#xff0c;开发者往往需要面对卡顿、崩溃、能耗异常、日志混乱等一系列问题。这些问题表面上看似偶发&#xff0c;但背后往往隐藏着系统资源调度不当…...