C++和标准库速成(八)——指针、动态数组、const、constexpr和consteval
目录
- 1. 指针和动态数组
- 1.1 栈和自由存储区
- 1.2 使用指针
- 1.3 动态分配的数组
- 1.4 空指针常量
- 2. const
- 2.1 const修饰类型
- 2.2 const与指针
- 2.3 使用const保护参数
- 2.4 const方法(建议)
- 3. constexpr
- 4. consteval
- 参考
1. 指针和动态数组
动态内存允许所创建的程序具有在编译期大小可变的数据,大多数复杂程序都会以某种方式使用动态内存。
1.1 栈和自由存储区
C++程序中的内存分为两部分——栈和自由存储区。将栈可视化的一种方式就是将其看作一幅纸牌,当前顶部的牌代表程序的当前作用域,通常是正在执行的函数。当前函数中声明的所有变量将占用顶部栈帧的内存。如果当前函数foo()调用了另一个函数bar(),一张新牌就会被放在牌堆上面,这样bar()就会拥有自己的栈帧供其运行。任何从foo()传递给bar()的参数都会从foo()栈帧复制到bar()栈帧。
栈帧很好,因为它为每个函数提供了独立的内存空间。如果在foo()栈帧中声明了一个变量,那么除非专门要求,否则调用bar()函数不会更改该变量。此外,foo()函数执行完毕时,栈帧就会消失,该函数中声明的所有变量都不会再占用内存。在栈上分配内存的变量不需要由程序员释放内存,这个过程是自动完成的。
自由存储区是与当前函数或栈帧完全独立的内存区域。如果想在函数调用结束之后仍然保存其中声明的变量,可以将变量放到自由存储区中。自由存储区的结构不如栈复杂,可以将它当作一堆位。程序可在任何时候向其中添加新的位或修改已有的位。必须确保释放在自由存储区上分配的任何内存,这个过程不会自动完成,除非使用了智能指针。
警告:这里介绍指针是因为你将会遇到它们,尤其是在遗留代码中。但是在新代码中,仅在不涉及所有权的情况下,才允许使用此类原始/裸指针。
1.2 使用指针
可以通过显式分配内存的方式将任何东西放到自由存储区中。例如,要将一个整数放在自由存储区中,需要为其分配内存,但是首先需要声明一个指针:
int* myIntegerPointer;
int类型后面的*表示,所声明的变量引用/指向某个整数内存。可将指针看作指向动态分配自由存储区中内存的一个箭头,它还没有指向任何内容,因为你还没有把它指派给任何内容,它是一个未初始化的变量。在任何时候都应避免使用未初始化的变量, 尤其是未初始化的指针,因为它们会指向内存中的某个随机位置。使用这种指针很可能使程序崩溃。这就是总是应同时声明和初始化指针的原因。如果不希望立即分配内存,可以把它们初始化为空指针nullptr。
int* myIntegerPointer { nullptr };
空指针是一个特殊的默认值,有效的指针都不含该值,在布尔表达式中使用时会被转换成false。
if ( !myIntegerPointer ) {/* myIntegerPointer is a null pointer. */
}
使用new操作符分配内存:
myIntegerPointer = new int;
在此情况下,指针指向一个整数值的地址。为访问这个值,需要对指针解引用。可将解引用看作沿着指针箭头寻找自由存储区中实际的值。为给自由存储区中新分配的整数赋值,可采用如下代码:
*myIntegerPointer = 8;
注意:这并非将myIntegerPointer的值设置为8,在此并没有改变指针,而是改变了指针所指的内存。如果真要重新设置指针的值,它将指向内存地址8,这可能是一个随机的无用内存单元,最终会导致程序崩溃。
使用完动态分配的内存后,需要使用delete操作符释放内存。为防止在释放指针所指的内存后再使用指针,建议将指针设置为nullptr。
delete myIntegerPointer;
myIntegerPointer = nullptr;
警告:在解引用之前指针必须有效。对null或未初始化的指针解引用会导致未定义的行为。程序可能崩溃,也可能继续运行,却给出奇怪的结果。
指针并非总是指向自由存储区内存,可声明一个指向栈中变量甚至指向其他指针的指针。为让指针指向某个变量,需要使用取址运算符&。
int i { 8 };
int* myIntegerPointer { &i }; // points to the variable with the value 8.
C++使用特殊语法处理指向结构体或类的指针。从技术上讲,如果指针指向某个结构体或类,可以首先用*对指针解引用,然后使用普通的.语法访问其中的字段,如下面的代码所示,在此假定存在一个名为getEmployee()的函数,它返回一个指向Employee实例的指针。
Employee* anEmployee { getEmployee() };
std::cout << (*anEmployee).salary << "\n";
此语法有一点混乱。->运算符允许同时对指针解引用并访问字段。下面的代码与前面的代码等效,但阅读起来更方便。
Employee* anEmployee { getEmployee() };
std::cout << anEmployee->salary << "\n";
逻辑短路可与指针一起使用,以免使用无效指针,如下所示。
bool isValidSalary { ( anEmployee && anEmployee->salary > 0 ) };
或者稍微详细一点:
bool isValidSalary { ( anEmployee != nullptr && anEmployee->salary > 0 ) };
仅当anEmployee有效时,才对其进行解引用以获取salary。如果它是一个空指针,则逻辑运算短路,不再解引用anEmployee指针。
1.3 动态分配的数组
自由存储区也可以用于动态分配数组。使用new[]操作符可给数组分配内存:
int arraySize { 8 };
int* myVariableSizedArray { new int[arraySize] };
这条语句分配足够的内存,用于存储arraySize个整数。下图展示了执行这条语句后栈和自由存储区的情况。可以看到指针变量仍在栈中,当动态创建的数组在自由存储区中。
现在已经分配了内存,可将myVarialbeSizedArray当作基于栈的普通数组使用。
myVariableSizedArray[3] = 2;
使用完这个数组后,应该将其从自由存储区中删除,这样其他变量就可以使用这块内存。在C++中,可使用delete[]操作符完成这一任务。
delete[] myVariableSizedArray;
myVariableSizedArray = nullptr;
delete后的方括号表明所删除的是一个数组!
注意:避免使用C中的malloc()和free(),而使用new和delete,或者使用new[]和delete[]。
警告:在C++中,每次调用new时,都必须相应地调用delete;每次调用new[]时,都必须相应地调用delete[],以避免内存泄漏。如果未调用delete或delete[],或调用不匹配,会导致内存泄漏。
1.4 空指针常量
在C++11之前,常量NULL用于表示空指针。NULL只是简单地定义为常量0,这会导致一些问题。分析下面的例子:
void func(int i) {std::cout << "func(int)" << "\n";
}int main() {func(NULL);
}
这段代码定义了一个func()函数,它有一个整型参数。main()函数通过参数NULL调用func(),NULL被当作一个空指针常量。但是,NULL不是指针,而等价于整数0,所以实际调用的是func(int)。这可能不是预期的行为,因此,有些编译器会给出警告。
可引入真正的空指针常量nullptr来解决这个问题。下面的代码使用了真正的空指针,并且导致了编译错误,因为我们没有重载参数为指针的func()版本。
func(nullptr);
2. const
在C++中有很多方法使用const关键字。所有用法都是相关的,但存在微妙的差别。基本上,const是constant的缩写,它表示某些内容保持不变。编译器通过将任何试图将其更改的行为标记为错误,用来保证此要求。此外,启用优化后,编译器可以利用此知识生成更好的代码。
2.1 const修饰类型
如果已经认为关键字const与常量有一定关系,就正确地揭示了它的一种用法。在C语言中,程序员经常使用预处理器的#define机制声明一个符号名称,其值在程序执行时不会变化,如版本号。在C++中,鼓励程序员使用const取代#define定义常量。使用const定义常量就像定义变量一样,只是编译器保证代码不会改变这个值。实例如下:
const int versionNumberMajor { 2 };
const int versionNumberMinor { 1 };
const std::string productName { "Super Hyper Net Modulator" };
const double PI { 3.141592653589793238462 };
可以将任何变量标记为const,包括全局变量和类中的数据成员。
2.2 const与指针
当变量通过指针包含一层或多层间接时,应用const将变得棘手。考虑以下代码:
int* ip { nullptr };
ip = new int[10];
ip[4] = 5;
假设你决定对ip使用const。暂时不要考虑这样做的用处,考虑它意味着什么。你要是阻止ip变量本身被更改,还是要阻止其指向的值被更改?也就是说,你要阻止第二行还是第三行?
为了防止指向的值被修改,可以用下面这种方式将const添加到ip的声明中。
const int* ip { nullptr };
ip = new int[10];
ip[4] = 5; // does not compile!
现在,你无法修改ip指向的值。一种替代的但在语义上等效的书写方式如下:
int const* ip { nullptr };
ip = new int[10];
ip[4] = 5; // does not compile!
将const放在int之前还是之后在功能上没有区别。
如果想将ip本身标记为const,而不是它指向的值,需要这样写:
int* const ip { nullptr };
ip = new int[10]; // does not compile!
ip[4] = 5; // error: dereferencing a null pointer.
现在,ip本身无法更改,编译器要求你在声明它时对其进行初始化,可以使用如先前代码中的nullptr或如下所示的新分配的内存。
int* const ip { new int[10] };
ip[4] = 5;
也可以像下面这样,将指针本身和指针所指的值都标记为const。
int const* const ip { nullptr };
这是另一种等效的写法:
const int* const ip { nullptr };
尽管此语法可能看起来令人困惑,但实际上存在一个简单的规则:const关键字作用于其直接左侧的内容。再次考虑这一行:
int const* const ip { nullptr };
从左到右,第一个const直接位于单词int的右侧,因此它适用于ip指向的int,指定你不能更改IP指向的值。第二个const直接位于*的右侧,因此它适用于指向int的指针,该指针是ip变量,指定你不能更改ip指针本身。
该规则令人困惑的原因是一个例外。也就是,第一个const可以放在变量之前,如下所示。
const int* const ip { nullptr };
这种例外语法比其他语法更常遇到。
可以将这个规则扩展到任意级别的间接级别,正如以下示例:
const int* const* const* const ip { nullptr };
该声明中存在3个*表明这是一个三级指针,从右到左,第一个const直接位于*的右边,表明第三级指针ip是常量,不能修改它指向的地址;第二个const直接位于*的右边,表明第二级指针*ip是常量,不能修改它指向的地址;第三个const直接位于*的右边,表明第一级指针**ip是常量,不能修改它指向的地址;第四个const表明**ip解引用后的值为常量,不能修改。
2.3 使用const保护参数
在C++中,可将非const变量转换为const变量。为什么想这样做呢?这提供了一定程度的保护,防止其他代码修改变量。如果你调用同事编写的一个函数,并且想确保这个函数不会传递改变给它的实参,可以告诉同事让函数采用const参数。如果这个函数试图改变参数的值,就不会让编译通过。
在下面的代码中,调用mysteryFunction()时string自动转换为const string。如果编写mysteryFunction()的人员试图修改所传递字符串的值,代码将无法编译。有绕过这个限制的方法,但是需要有意识地这么做,C++只是阻止无意义地修改const变量。
void mysteryFunction(const std::string* someString) {*someString = "Test"; // will not compile.
}int main() {std::string myString { "The string" };mysteryFunction(&myString);
}
还可以在原始类型参数上使用const,以防止在函数体中意外修改它们。例如,以下函数具有const整型参数。在函数体中,无法修改整数param。如果尝试对其修改,则编译器将生成错误。
void func(const int param) {/* not allowed to change param... */
}
2.4 const方法(建议)
const关键字的第二个用途是将类方法标记为const,以防止它们修改类的数据成员。可以修改前面介绍的AirlineTicket类,以将所有只读方法标记为const。如果任何const方法尝试修改AirlineTicket数据成员之一,则编译器将提示错误。
export class AirlineTicket {
public:double calculatePriceInDollars() const;std::string getPassengerName() const;void setPassengerName(std::string name);int getNumberOfMiles() const;void setNumberOfMiles(int miles);bool hasEliteSuperRewardsStatus() const;void setHasEliteSuperRewardsStatus(bool status);private:std::string m_passengerName { "Unknown Passenger" };int m_numberOfMiles { 0 };bool m_hasEliteSuperRewardsStatus { false };
};// all methods omitted...
注意:为了遵循const-correctness原则,建议将不改变对象的任何数据成员的成员函数声明为const。与非const成员函数也被称为赋值函数相对,这些成员函数也称为检查器。
3. constexpr
C++中一直有常量表达式的概念,即在编译器求值的表达式。在某些情况下,必须使用常量表达式。例如,定义数组时,数组的大小需要为常量表达式。由于此限制,以下代码在C++中无效。
const int getArraySize() {return 32;
}int main() {std::array<int, getArraySize()> myArray {}; // invalid in C++.
}
使用constexpr关键字,getArraySize()函数可以被重定义,允许在常量表达式中调用它。
constexpr int getArraySize() {return 32;
}int main() {std::array<int, getArraySize()> myArray {}; // ok.
}
你甚至可以这样做:
int myArray[getArraySize() + 1]; // ok.
将函数声明为constexpr对函数的功能施加了很多限制,因为编译器必须能够在编译期对函数求值。例如,允许constexpr函数调用其他constexpr函数,但不允许调用任何非constexpr函数。这样的函数不允许有任何副作用,也不能引发任何异常。
通过定义constexpr构造函数,可以创建用户自定义类型的常量表达式变量。与constexpr函数一样,constexpr类也有很多限制。下面的Rect类定义了constexpr构造函数,他还定义了执行一些计算的constexpr getArea()方法。
class Rect {
public:constexpr Rect(std::size_t width, std::size_t height) :m_width { width }, m_height { height } {}constexpr std::size_t getArea() const {return m_width * m_height;}
private:std::size_t m_width {}, m_height {};
}
使用这个类声明constexpr对象是非常容易的。
constexpr Rect r { 8, 2 };
std::array<int, r.getArea()> myArray {}; // ok.
4. consteval
上一节讨论的constexpr关键字指定函数在编译期执行,但不能保证一定在编译期执行。采用以下constexpr函数:
constexpr double inchToMm(double inch) {return inch * 25.4;
}
如果按以下方式调用,则会在需要时在编译期对函数求值。
constexpr double const_inch { 6.0 };
constexpr double mml { inchToMm(const_inch) }; // at compile time.
然而,如果按以下方式调用,函数将不会在编译期被求值,而是在运行时。
double dynamic_inch { 8.0 };
double mm2 { inchToMm(dynamic_inch) }; // at run time.
如果确实希望保证始终在编译期对函数进行求值,则需要使用C++20的consteval关键字将函数转换为所谓的立即函数。可以按照如下方式更改inchToMm()函数:
consteval double inchToMm(double inch) {return inch * 25.4;
}
参考
[比] 马克·格雷戈勒著 程序喵大人 惠惠 墨梵 译 C++20高级编程(第五版)
相关文章:
C++和标准库速成(八)——指针、动态数组、const、constexpr和consteval
目录 1. 指针和动态数组1.1 栈和自由存储区1.2 使用指针1.3 动态分配的数组1.4 空指针常量 2. const2.1 const修饰类型2.2 const与指针2.3 使用const保护参数2.4 const方法(建议) 3. constexpr4. consteval参考 1. 指针和动态数组 动态内存允许所创建的程序具有在编…...
深入解析 Spring Boot 中的 FailureAnalyzer
深入解析 Spring Boot 中的 FailureAnalyzer 在 Spring Boot 应用中,我们难免会遇到启动失败的情况,而默认的异常信息往往过于复杂,导致排查问题变得困难。Spring Boot 提供了一套强大的 FailureAnalyzer 机制,能够捕获常见的异常…...
20. Excel 自动化:Excel 对象模型
一 Excel 对象模型是什么 Excel对象模型是Excel图形用户界面的层次结构表示,它允许开发者通过编程来操作Excel的各种组件,如工作簿、工作表、单元格等。 xlwings 是一个Python库,它允许Python脚本与Excel进行交互。与一些其他Python库&#x…...
【Matlab GUI】封装matlab GUI为exe文件
注:封装后的exe还是需要有matlab环境才能运行 (1)安装MCRinstaller.exe文件,在matlab安装目录下的toolbox/compiler/deploy/win64文件夹里 (2)安装完MCRinstaller.exe,字命令窗口输入&#x…...
ModBus TCP/RTU互转(主)(从)|| Modbus主动轮询下发的工业应用 || 基于智能网关的串口服务器进行Modbus数据收发的工业应用
目录 前言 一、ModBus TCP/RTU互转(从)及应用|| 1.1 举栗子 二、ModBus TCP/RTU互转(主) 2.1 举栗子 三、ModBus 主动轮询 3.1 Modbus主动轮询原理 3.2 Modbus格式上传与下发 3.2.1.设置Modbus主动轮询指令 3.2.2 设…...
Linux top 命令详解:从入门到高级用法
Linux top 命令详解:从入门到高级用法 在 Linux 系统中,top 是一个强大的实时监控工具,用于查看系统资源使用情况和进程状态。它可以帮助你快速了解 CPU、内存、负载等信息,是系统管理员和开发者的日常利器。本文将从基本用法开始…...
【网络协议】基于UDP的可靠协议:KCP
TCP是为流量设计的(每秒内可以传输多少KB的数据),讲究的是充分利用带宽。而 KCP是为流速设计的(单个数据包从一端发送到一端需要多少时间),以10%-20%带宽浪费的代价换取了比 TCP快30%-40%的传输速度。TCP信…...
【Docker入门】构建推送第一个Docker映像
【Docker入门】构建推送第一个Docker映像 Build and Push the First Docker Image By JacksonML Docker的容器(Container)映像是轻量级的可执行独立包,包含代码、运行时、库、环境变量以及配置文件,它对于运行软件至关重要。注册表可在团队间分享映像。…...
Python----计算机视觉处理(Opencv:图像颜色替换)
一、开运算 开运算就是对图像先进行腐蚀操作, 然后进行膨胀操作。开运算可以去除二值化图中的小的噪点,并分离相连的物体。 其主要目的就是消除那些小白点 在开运算组件中,有一个叫做kernel的参数,指的是核的大小,通常…...
搭建自己的OCR服务
网上看到相关文章,这里整理记录一下,仅供学习。 搭建自己的OCR服务,第一步:选择合适的开源OCR项目 - PandaCode辉 - 博客园 一、OCR是什么? 光学字符识别(Optical Character Recognition, OCR)…...
vue:组件的使用
Vue:组件的使用 1、什么是组件 1.1、传统方式开发的应用 一个网页通常包括三部分:结构(HTML)、样式(CSS)、交互(JavaScript)。在传统开发模式下,随着项目规模的增大&a…...
leetcode日记(105)买卖股票的最佳时机Ⅱ
原本以为是一个很难想的动态规划,没想到是最简单的贪心…… 如果实在想不出就画个折线图,只买上涨的就行了,所有上涨的段都取到。 真的没想到会这么简单…… class Solution { public:int maxProfit(vector<int>& prices) {int …...
7种数据结构
7种数据结构 顺序表sqlite.hseqlite.c 单链表linklist.clinklist.h 双链表doulinklist.cdoulinklist.h 链式栈linkstack.clinkstack.h 队列SeqQueue.cSeqQueue.h 树tree.c 哈希表hash.c 顺序表 sqlite.h #ifndef __SEQLIST_H__ #define __SEQLIST_H__ typedef struct person…...
论文阅读:Deep Hybrid Camera Deblurring for Smartphone Cameras
今天介绍一篇 ACM SIGGRAPH 2024 的文章,关于手机影像中的去模糊的文章。 Deep Hybrid Camera Deblurring for Smartphone Cameras Abstract 手机摄像头尽管取得了显著的进步,但由于传感器和镜头较为紧凑,在低光环境下的成像仍存在困难&am…...
Redis 三主三从集群部署的完整方案
一、架构设计原理 分布式数据分片 哈希槽机制:Redis Cluster 将数据划分为 16384 个槽位,每个主节点负责部分槽位(如主节点1管理槽0-5460,主节点2管理5461-10922等)。 自动负载均衡:数据按哈希值分配…...
C++项目:高并发内存池_上
目录 1. 项目介绍 2. 内存池概念 2.1 池化技术 2.2 内存池和内存碎片 2.3 细看malloc 3. 定长内存池的实现 ObjectPool.hpp 4. 高并发内存池框架 5. thread cache测试 5.1 thread cache框架 5.2 ConcurrentAlloc.hpp 6. central cache测试 6.1 central cache框架 …...
『Plotly实战指南』--折线图绘制基础篇
在数据分析的世界中,折线图是一种不可或缺的可视化工具。 它能够清晰地展示数据随时间或其他变量的变化趋势,帮助我们快速发现数据中的模式、趋势和异常。 无论是金融市场分析、气象数据监测,还是业务增长趋势预测,折线图都能以直…...
【css酷炫效果】纯CSS实现波浪形分割线
【css酷炫效果】纯CSS实现波浪形分割线 缘创作背景html结构css样式完整代码效果图 想直接拿走的老板,链接放在这里:https://download.csdn.net/download/u011561335/90492023 缘 创作随缘,不定时更新。 创作背景 刚看到csdn出活动了&…...
【资料分享】全志科技T113-i全国产(1.2GHz双核A7 RISC-V)工业核心板规格书
核心板简介 创龙科技SOM-TLT113 是一款基于全志科技T113-i 双核ARM Cortex-A7 玄铁C906 RISC-V HiFi4 DSP 异构多核处理器设计的全国产工业核心板,ARM Cortex-A7 处理单元主频高达1.2GHz。核心板 CPU、ROM、RAM、电源、晶振等所有元器件均采用国产工业级方案&…...
Coco AI 智能检索 Hugo Blog 集成指南
在此前的文章中,我们介绍了如何使用 Coco Server 连接 Notion,实现智能内容检索。本次,我们将进一步探索如何在 Coco Server 最新版本 中集成 Hugo Site,以便对 Hugo 站点 进行高效检索。 Coco Server 部署方式 要在本地或服务器…...
【MySQL数据库】多表查询(笛卡尔积现象,联合查询、内连接、左外连接、右外连接、子查询)-通过练习快速掌握法
在DQL的基础查询中,我们已经学过了多表查询的一种:联合查询(union)。本文我们将系统的讲解多表查询。 笛卡尔积现象 首先,我们想要查询emp表和stu表两个表,按照我们之前的知识栈,我们直接使用…...
jmeter将返回的数据写入csv文件
举例说明,我需要接口返回体中的exampleid与todoid的数据信息(使用边界提取器先将其提取),并将其写入csv文件进行保存 使用后置处理器BeanShell 脚本实例如下 import java.io.*;// 设置要写入的文件路径 String filePath "…...
AI如何在财务工作中提升效率的一些看法
文章目录 1. 自动化重复性任务2. 财务预测与分析3. 欺诈检测与风险管理4. 智能报表与决策支持5. 税务管理优化6. 提升团队协作与客户体验未来的趋势与挑战结论 随着人工智能(AI)技术的迅猛发展,其正全方位地革新各行各业的运作模式࿰…...
OpenCV入门指南:从安装到基本操作
引言 OpenCV(Open Source Computer Vision Library)是一个开源的计算机视觉和机器学习软件库。它包含了数百种计算机视觉算法,广泛应用于图像处理、视频分析、物体检测、人脸识别等领域。本文将带你从安装OpenCV开始,逐步了解其基…...
简单以太网配置
display arp //查看路由器mac地址 交换机配置命令: system-view // 从用户视图进入系统视图 dis mac-address //查看mac地址表 路由器配置命令: system-view // 从用户视图进入系统视图 int GigabitEthernet 0/0/0 //进入G口 0/0/0 进入之后配置网关: ip addre…...
蓝桥杯嵌入式组第十四届省赛题目解析+STM32G431RBT6实现源码
文章目录 1.题目解析1.1 分而治之,藕断丝连1.2 模块化思维导图1.3 模块解析1.3.1 KEY模块1.3.2 LED模块1.3.3 LCD模块1.3.4 TIM模块1.3.4.1 频率变化处理1.3.4.1 占空比计算 1.3.5 ADC模块 2.源码2.1cubemx配置3.第十四届题目 前言:STM32G431RBT6实现嵌入…...
让双向链表不在云里雾里
又来博客留下我的足迹了,哈哈哈,这次是对于双向链表的理解 目录 创建双向链表: 申请结点: 双向链表初始化: 双向链表插入结点: 双向链表删除结点: 双向链表的打印: 双向链表…...
基于django+vue的购物商城系统
开发语言:Python框架:djangoPython版本:python3.8数据库:mysql 5.7数据库工具:Navicat11开发软件:PyCharm 系统展示 系统首页 热卖商品 优惠资讯 个人中心 后台登录 管理员功能界面 用户管理 商品分类管理…...
在Vue3中使用Echarts的示例
1.常用-引用ts文件方式 1.1 导出ts文件-一个简单的柱状图 export const baseBarChart (xdata: string[], data: number[][], legendData: string[]) > {if (data.length 0) {return noData;}// 定义颜色数组const color [#00CCCC,#FF9900,#1677DC,#FF6666,#B366FF,#666…...
TCP协议的多线程应用、多线程下的网络编程
DAY13.2 Java核心基础 多线程下的网络编程 基于单点连接的方式,一个服务端对应一个客户端,实际运行环境中是一个服务端需要对应多个客户端 创建ServerSocketNable类,多线程接收socket对象 public class ServerSocketNable implements Run…...
每日学习Java之一万个为什么(待补充)
Git分支操作 git branch 分支名 git branch -v git checkout -b 分支名 git checkout 分支名 git merge 分支名 git branch -d | -D 分支名Git冲突 git同名文件合并的最基本单位是行。同名文件同一行不同就会发生冲突。 解决办法:及时沟通,手动更改&…...
设计C语言的单片机接口
一、主要内容 (一)控制引脚 1、定义管脚 // 定义管脚的结构体 struct pin{ int id; // 管脚编号 int mode; // 模式,输入为1,输出为0 int pull; // 输入电阻 int driver; // 功率 } 2、输出电平 语法: void pin_output(s…...
博客迁移----宝塔面板一键迁移遇到问题
前景 阿里云轻量级服务器到期了,又免费领了个ESC, 安转了宝塔面板。现在需要迁移数据,使用宝塔面板一键迁移功能,完成了数据的迁移,改了域名的解析,现在进入博客是显示502 bad grateway 宝塔搬家参考链接…...
抽象工厂模式 (Abstract Factory Pattern)
抽象工厂模式 (Abstract Factory Pattern) 是一种创建型设计模式,它提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。 一、基础 1. 意图 提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。 2. …...
LeetCode 第14~16题
目录 LeetCode 第14题:最长公共前缀 LeetCode 第15题:三数之和 LeetCode 第16题:最接近的三数之和 LeetCode 第14题:最长公共前缀 题目描述 编写一个函数来查找字符数组中的最长公共前缀。如果不存在公共前缀,返回字符…...
深入了解Linux —— git三板斧
版本控制器git 为了我们方便管理不同版本的文件,就有了版本控制器; 所谓的版本控制器,就是能够了解到一个文件的历史记录(修改记录);简单来说就是记录每一次的改动和版本迭代的一个管理系统,同…...
再学:abi编码 地址类型与底层调用
目录 1.内置全局变量及函数 2.abi 3.地址类型 4.transfer 1.内置全局变量及函数 2.abi data就是abi编码 abi描述:以json格式表明有什么方法 3.地址类型 4.transfer x.transfer:合约转给x call 和 delegatecall 是 Solidity 中用于底层合约调用的函数࿰…...
Redis的消息队列是怎么实现的
Redis 本身并不是一个专门的消息队列系统,但它的 List、Pub/Sub 和 Stream 数据结构可以用来实现消息队列的功能。以下是 Redis 实现消息队列的几种常见方式: 1. 基于 List 实现消息队列 Redis 的 List 是一个双向链表,支持在头部和尾部进行高效的插入和删除操作,非常适合…...
图论入门【数据结构基础】:什么是树?如何表示树?
图论是计算机科学和数学中的一个重要分支,研究图的结构及其性质。之前我们介绍了图的基本概念和表示:图论入门【数据结构基础】:什么是图?如何表示图?,本文将介绍树的基本概念、性质及其在计算机科学中的应…...
微信小程序订阅消息发送消息,点击消息进入小程序页面
1、在小程序官网订阅消息选用或创建消息模板获取模板ID可多个 如图: 2、微信小程序前端页面发送请求订阅权限 请求模板id的权限可以是一个可以是多个,用户同意订阅,获取code传递给后端——后端拿到code生成唯一的openid用于发送订阅消息 注…...
基于小参数量大语言模型(Small Language Models) ---- 在制造业落地降本增效应用:可行性研究初探
文章大纲 一、引言二、小参数量模型概述基本技术要求小参数量大语言模型在制造业场景中的适用性分析(一)排产优化(二)错误根因分析三、制造业小参数量大语言模型开源解决方案简介Bert 系列 模型Google微软MetaMistral AI国产解决方案四、技术实现方案进行逻辑(一)模型选择…...
pandas中excel自定义单元格颜色
writerpd.ExcelWriter(filepathf05教师固定学生占比1月{today}.xlsx,engineopenpyxl) df.to_excel(writer,sheet_name明细) piv1.to_excel(writer,sheet_name1月分布) wswriter.book.create_sheet(口径) ws.cell(1,1).value综合占比: ws.cell(1,2).value固定学生占比…...
MySQL事务:确保数据一致性的关键机制
目录 1. 为什么需要事务? 2. 什么是事务? 3. 事务的四大特性 3.1 原子性(Atomicity) 3.2 一致性(Consistency) 3.3 隔离性(Isolation) 3.4 持久性(Durability&…...
图论入门【数据结构基础】:什么是图?如何表示图?
图(Graph) 是一种非线性数据结构,用于表示对象之间的关系。图由 顶点(Vertex) 和 边(Edge) 组成,其中顶点表示对象,边表示对象之间的关系。图广泛应用于计算机科学、数学…...
SpringBoot中使用AJ-Captcha实现行为验证码(滑动拼图、点选文字)
简介 AJ-Captcha行为验证码,包含滑动拼图、文字点选两种方式,UI支持弹出和嵌入两种方式。后端提供Java、Golang实现,前端提供了php、angular、html、vue、uni-app、flutter、android、ios等代码示例。点击前往AJ-Captcha代码仓库 引入Maven…...
【国际研讨会】2025年3-5月通信、算法、电气工程、自动化等领域国际学术会议征稿开启!大型学术盛宴!
【国际研讨会】2025年3-5月通信、算法、电气工程、自动化等领域国际学术会议征稿开启!大型学术盛宴! 【国际研讨会】2025年3-5月通信、算法、电气工程、自动化等领域国际学术会议征稿开启!大型学术盛宴! 文章目录 【国际研讨会】…...
AI战略家:X厂三年复盘大纲——业务与组织双视角深度拆解
一、业务负责人视角:从0到1与从1到100的核心能力模型 (一)阶段能力要求与问题预判 1. 从0到1:破局能力 核心能力升级框架: 需求洞察三阶漏斗: 行业需求池:广泛收集行业内的各种需求ÿ…...
LuaJIT 学习(4)—— FFI 语义
文章目录 C Language SupportC Type Conversion RulesConversions from C types to Lua objects例子:访问结构体成员 Conversions from Lua objects to C typesConversions between C types例子:修改结构体成员 Conversions for vararg C function argum…...
剑指 Offer II 078. 合并排序链表
comments: true edit_url: https://github.com/doocs/leetcode/edit/main/lcof2/%E5%89%91%E6%8C%87%20Offer%20II%20078.%20%E5%90%88%E5%B9%B6%E6%8E%92%E5%BA%8F%E9%93%BE%E8%A1%A8/README.md 剑指 Offer II 078. 合并排序链表 题目描述 给定一个链表数组,每个链…...
go回调函数的使用
在Go语言中,回调函数可以有参数,也可以没有参数。它们的定义和使用方式略有不同,但本质上都是将函数作为参数传递给另一个函数,并在适当的时候调用它。以下是带参数和不带参数的回调函数的示例和说明。 1. 不带参数的回调函数 不…...