C++中的内存管理
学完了类与对象,这节我们来了解一下内存里的那些事
文章目录
一、C/C++中的内存分布
1. 常量区(代码段) (Text Segment)
2. 静态区(数据段) (Data Segment)
3. 堆区 (Heap)
4. 栈区 (Stack)
5. 内存映射区域 (Memory-mapped Region)
6. 堆栈溢出
内存布局总结
重要细节:
二、C/C++的内存管理方式
C语言中的内存管理
C++中的内存管理
new/delete操作内置类型
new和delete操作自定义类型
operator new与operator delete函数
new/delete的实现原理
对于内置类型:
对于自定义类型:
定位new表达式(placement-new)
三、malloc/free和new/delete的区别
1. 使用的语言
2. 内存分配和释放方式
3. 类型安全
4. 构造和析构函数
5. 内存分配失败
6. 效率
7. 使用习惯
前言
在C语言解答我们就已经学习了内存里面的那些东西,我们也会使用动态内存的一些函数,但是那些函数都是在C语言中所使用的,现在我们学习C++了,也要学习一下C++中动态内存的一些东西。
一、C/C++中的内存分布
在我们学习如果管理内存之前,我们首先要知道内存中有什么东西,内存中的东西是如何分布的。在 C/C++ 中,程序的内存分布是指程序在运行时,操作系统如何将不同类型的数据存储在内存的不同区域。通常,程序的内存可以分为以下几个主要部分:
1. 常量区(代码段) (Text Segment)
- 内容:包含程序的可执行代码。
- 特点:此区域通常是只读的,防止程序意外地修改其指令。操作系统会将其加载到内存中,并且可能会共享同一程序实例的多个进程。
2. 静态区(数据段) (Data Segment)
- 内容:用于存储程序中的全局变量、静态变量(即全程存在的变量),以及它们的初始值。
- 分为两部分:
- 已初始化数据段:存储已初始化的全局和静态变量。
- 未初始化数据段 (BSS段):存储未初始化的全局和静态变量。BSS段的变量会在程序启动时被操作系统自动初始化为 0。
3. 堆区 (Heap)
- 内容:用于动态分配内存。由程序员通过
malloc
、calloc
、realloc
等函数(在 C 语言中)或new
操作符(在 C++ 中)分配内存。 - 特点:堆是一个可以动态扩展的区域,程序员需要手动管理内存的分配与释放(通过
free
、delete
等)。如果堆内存不及时释放,会导致内存泄漏。
4. 栈区 (Stack)
- 内容:用于存储局部变量、函数参数、返回地址等。每当调用一个函数时,栈会为该函数分配空间,当函数执行完毕时,空间被释放。
- 特点:
- 先进后出:栈的特点是后进先出(LIFO)。每次函数调用会压栈,函数返回会出栈。
- 局部变量存储:局部变量通常存储在栈上,当函数退出时,它们的内存会自动释放。
5. 内存映射区域 (Memory-mapped Region)
- 内容:主要用于加载共享库、内存映射文件等。这个区域由操作系统管理,可以包括动态链接库、共享内存、I/O 映射等。
- 特点:这些区域的内容通常由操作系统管理和控制,程序可以直接访问,但不直接由程序员管理。
6. 堆栈溢出
- 内容:当栈的空间不足时,可能发生栈溢出。一般来说,栈空间的大小是有限的。
- 表现:栈溢出可能导致程序崩溃,常见原因包括无限递归或者分配过多的局部变量。
内存布局总结
区域 | 内容 | 生命周期 | 管理方式 |
---|---|---|---|
栈区 | 局部变量、函数参数、返回地址 | 函数调用时分配,调用结束时销毁 | 自动管理 |
堆区 | 动态分配的内存 | 由程序员手动管理 | 程序员手动管理 |
数据区 | 全局变量、静态变量、常量 | 程序运行期间持续存在 | 自动管理 |
文本区 | 程序的代码(机器码) | 程序运行时一直存在 | 操作系统加载 |
内存布局大致如下所示
+------------------------+ 高地址
| 内存映射区域 |
+------------------------+
| 堆 |
+------------------------+
| BSS段(未初始化数据) |
+------------------------+
| 数据段(已初始化数据)|
+------------------------+
| 代码段(Text段) |
+------------------------+ 低地址
| 栈 |
+------------------------+
重要细节:
- 栈和堆的增长方向:通常情况下,栈的增长方向是向下(即地址从高到低),而堆的增长方向是向上(即地址从低到高)。因此,当栈和堆相遇时,可能会导致“栈溢出”或“堆溢出”。
- 内存管理:在堆上分配的内存需要程序员显式地管理,在栈上分配的内存由编译器自动管理。
光说概念理念啥的还是太悬了,我们还是用具体实例来看看吧
二、C/C++的内存管理方式
C语言中的内存管理
首先我们先来回顾一下我们之前所学习的C语言中的动态内存管理方式:malloc,calloc,realloc,free.
//1.malloc//void *malloc(size_t size);//size表示的是我们要申请空间中的元素的大小,由于malloc函数在库中的数据类型是void*,所以我们每次使用都要进行强转int* p1 = (int*)malloc(sizeof(int));//2.calloc//void* calloc(size_t num, size_t size); //num表示要分配的元素个数,size表示的是每个元素的大小,由于calloc函数在库中的数据类型是void*,所以我们每次使用都要进行强转int* p2 = (int*)calloc(4, sizeof(int));//3.realloc//void* realloc(void* ptr, size_t new_size);//ptr指向的是已经分配内存的空间地址,new_size表示要重新分配的内存大小(单位是字节),同样地,它每次使用时也要使用强转int* p3 = (int*)realloc(p2, sizeof(int)*2);//4.free//void free(void *ptr);//ptr表示的是想要释放的内存空间地址,直接传递一个指针名字即可free(p1);free(p2);free(p3);
我们从上面的代码和注释,我们可以了解到上面三种函数都是申请空间的函数,最后一种函数是用来对动态申请的内存进行释放,最后一个函数在动态内存管理中是一个不可或缺的,如果我们只是一味地去申请空间,而不去释放空间,就很容易造成内存泄漏的问题。
现在我们对上面那三种动态申请内存的函数:malloc/calloc/reaclloc进行一下辨析。我们只从单词拼写来看,上面三个单词是十分相似的,仅个别单词的差别,但是它们的作用大同小异。malloc函数是从堆区主动为对象分配一块内存连续的空间,并返回该内存空间的起始地址。使用malloc函数动态申请的空间是不会进行初始化的,也就是说它所申请的空间里的内容是一个随机值,使用malloc函数时我们要始终记得NULL检查,防止返回一个NULL指针造成申请空间失败我们却发现不了。calloc函数也是一个动态内存申请的函数,它的功能和malloc函数是十分相似的,但是它有两点不同:1.它会指定动态申请的元素个数;2.它会将动态申请的内容全部初始化为0。有时候在某些情况calloc函数进行动态内存申请还是很好用的。最后是realloc函数,这个函数与前面那两个函数的功能有所差异,前面两个函数是直接申请空间,而这个函数是为一个对象重新申请并分配空间。reaclloc可以扩展或缩小已分配内存的大小。如果扩展内存,原有数据保持不变,新增内存会被清零;如果缩小内存,数据保持不变。当 reaclloc成功时,它可能会在内存的不同位置分配新的空间,因此必须将返回的指针保存到一个新的变量中,否则原指针可能会丢失。
C++中的内存管理
C语言的内存管理方式在C++中其实也是可以用的,但是在某些方面使用起来有点麻烦,于是C++就使用自己内存管理的方式:使用new/delete操作符进行内存管理。
new/delete操作内置类型
// 动态申请一个int类型的空间int* ptr4 = new int;// 动态申请一个int类型的空间并初始化为10int* ptr5 = new int(10);// 动态申请10个int类型的空间int* ptr6 = new int[10];//动态申请3个int类型的空间并进行初始化int* ptr7 = new int[3] {1, 2, 3};delete ptr4;delete ptr5;delete[] ptr6;delete[]ptr7;
我们从上面的代码可以看到我们使用C++中的new操作符,只要new 数据类型(参数)就可以动态申请一个指定类型的空间并且可以帮我们初始化为任意值(若要初始化一个空间的内容,我们在()内传递我们要初始化的值,若要初始化一个数组空间的内容,我们在{ }内传递我们想要初始化的值)。对比于C语言中的malloc/calloc,它们书写的方式麻烦(需要进行强转,给其传递要开辟的空间字节大小,还不能够随意初始化为自己想要的值),C++中的new操作符就清楚明白多了。至于delete操作符,它对于一个空间的释放以及一个数组空间的释放是有一些差别的,希望我们能够注意。
new和delete操作自定义类型
class A
{
public://写了A类的构造函数(带缺省参数)A(int a=10 ): _a(a){cout << "A():" << this << endl;}//A类的析构函数~A(){cout << "~A():" << this << endl;}
private:int _a;
};
int main()
{// new/delete 和 malloc/free最大区别是 new/delete对于【自定义类型】除了开空间//使用自定义类型来动态申请内存,malloc,new都可以申请。但是malloc只能够开空间,new不仅开空间而且还会调用A类的构造函数A* p1 = (A*)malloc(sizeof(A));A* p2 = new A(1);free(p1);delete p2;cout << endl;// 内置类型是几乎是一样的(因为内置类型没有构造函数,只要开辟空间即可)int* p3 = (int*)malloc(sizeof(int)); // int* p4 = new int;free(p3);delete p4;cout << endl;//同样地使用自定义类型动态申请数组内存空间,new不仅开空间还会调用构造函数中参数的缺省值进行初始化,如果构造函数中没有默认的缺省值,则无法进行初始化A* p5 = (A*)malloc(sizeof(A) * 10);A* p6 = new A[10];free(p5);delete[] p6;return 0;
}
由上面的代码以及运行结果我们可以看出来,对于那些自定义类型的动态内存管理,malloc/new,free/delete 都是可以的,但是对于那些自定义类型,我们在之前就已经学习过了类中有属于自己的默认构造函数/析构函数,malloc/free虽然可以申请释放空间,但是它们不能够调用到自定义类型的构造/析构函数。而在C++中,那些研发出new/delete的大佬们明显发现了这件事情,对于一个自定义类型怎么能够不调用它们的构造函数与析构函数呢,于是它们就将这些功能打包给了new/delete了。
operator new与operator delete函数
我们在上面已经说过了,new/delete就是malloc/free的一个升级版,那么它们为什么如此相像呢?学到这里不知道你们有没有这样的疑问。难道它们都是为了内存管理,C++研发者为了图简单,就照着malloc/free随便设计两个操作符就当作C++专属的呢。其实new/delete的底层就是malloc/free。new/delete它们两个是操作符,它们是对一个变量进行一个操作,真正发挥作用的是在编译器里面的两个全局函数:operator new和operator delete。每次我们使用操作符new/delete,它们就悄悄调用上面两个函数。而这两个函数的本质就是malloc/free,在C++中将其进行封装变成了两个新的函数,但是还是有一点点的小差别的:malloc如果申请空间失败就会返回NULL,而operator new 申请空间失败就会抛出异常,而这也是面向对象语言的一个经典特点。上面这两个函数只是实现开辟空间与释放空间的功能,并没有调用构造函数/析构函数的功能。
/*
*new/delete 是两个操作符,它们是通过调用全局域中的两个函数operator new / operator delete 来进行动态内存管理的
*而上面那两个函数本身又是我们之前C语言中的malloc与free的一个封装展现,,那两个函数单独使用和malloc与free的功能基本差不多
* 不过operator delete在内存释放失败时会抛出异常,而free则会返回一个NULL指针,这是一个差异
* new: 1.调用operator new来动态申请空间 2.调用构造函数进行初始化
* delete:1.调用析构函数,完成对象内存中资源的清理 2.调用operator delete来动态释放空间
* 至于new T[N] , delete[]就是上面那个原理重复N次
*/class A
{
public:A(int a = 10):_a(a){cout << "A(int a ):" << this << endl;}~A(){cout << "~A():" << this << endl;}private:int _a;
};int main()
{A* p1 = new A(10);p1->~A();cout << endl;// 这里我们调用operator new 即调用malloc, 因此我们的使用方式也和malloc一样,要先进行强转,然后在传要创建空间的大小A* p3 = (A*)operator new (sizeof(A));new(p3)A;//这一步是定位new表达式,我们是为了手动调出p3的构造函数//上面的两步合在一块就是一个new所实现的功能了p3->~A();//这是手动调用析构函数operator delete(p3);cout << endl;A* p2 = new A;p2->~A();return 0;
}
从上面的代码我们可以看出来,单单使用operator new/operator delete仅仅是起到malloc/free的功能,如果想要调用构造函数/析构函数就需要我们自己手动去调用了。所以我们就索性直接使用new/delete这两个操作符,想要的功能它们都会实现。
new/delete的实现原理
对于内置类型:
它们的实现原理和malloc/free一样,虽然new/delete调用的是上面那两个函数,但是那两个函数的本质还是malloc/free。不同的是new/delete类型是申请一个类型的内存空间,new[]/delete[]是申请连续的内存空间,malloc申请失败时会返回NULL,而new申请失败时则会抛出异常。
对于自定义类型:
new的原理:1.调用operator new函数来动态申请内存空间;2.调用构造函数进行初始化。
delete的原理:1.调用析构函数对对象资源的清理;2.调用operator delete函数来释放内存空间。
newT[N]的原理:1.调用operator new[]函数的调用,在operator new[]中实际调用operator new N次完成对N个对象的空间申请;2.调用N次构造函数进行对N个对象进行初始化
delete[ ]的原理:1.在释放空间上进行N次析构函数的调用,完成对N个对象的资源清理;2.调用operator delete[ ]函数来释放内存,实际上是调用operator delete来释放内存。
定位new表达式(placement-new)
placement new
是 C++ 中的一种特殊形式的 new
表达式,它允许用户在指定的内存位置上构造对象,而不是在堆上动态分配内存。与常规的 new
表达式不同,placement new
不会分配内存,而是将对象构造在一个已经存在的内存区域中。
语法:
new (pointer) Type(args);
pointer
是指向预分配内存的指针,必须传递指针。Type
是要构造的对象类型。args
是传递给构造函数的参数,即类型的初始化列表
使用场景: 定位new表达式在实际中一般是配合内存池使用。因为内存池分配出的内存没有初始化,所以如果是自定义类型的对象,需要使用new的定义表达式进行显示调构造函数进行初始化。
int main()
{char* buffer[sizeof(int)]; // 预分配一块内存,给这个字符数组分配整型字节的大小空间// 在 buffer 上使用placement new构造一个int对象int* ptr = new (buffer) int(42); // 在buffer的位置上构造int对象并初始化为42,buffer是数组名,也是数组首地址,即指针cout << *ptr << endl; // 输出42return 0;
}
同样地对于自定义类型的变量使用定位new,它同样能够发挥new操作符的作用(调用构造函数初始化,申请空间)但是它是指定内存空间进行分配内存空间,并不是从堆中分配内存空间,这就是定位new的功能。
三、malloc/free和new/delete的区别
1. 使用的语言
malloc
和free
是 C 语言中的内存管理函数。new
和delete
是 C++ 中的内存管理操作符。
2. 内存分配和释放方式
malloc
:用来从堆中分配一块指定大小的内存。返回的是一个void*
指针,需要进行类型转换才能使用。它只关心分配的字节数,不会调用构造函数。free
:用来释放malloc
分配的内存块,它接受一个指针,释放对应的内存区域。new
:用来为对象分配内存并调用构造函数。它不仅分配内存,还返回一个指向已构造对象的指针。delete
:用来释放通过new
分配的内存,并自动调用对象的析构函数。
3. 类型安全
malloc
/free
:malloc
返回的是void*
,需要强制转换为目标类型的指针,存在类型不安全的风险。free
的参数是void*
,可以接收任何类型的指针。new
/delete
:new
和delete
是类型安全的,new
返回所需类型的指针,不需要类型转换。delete
的参数也是相应类型的指针。
4. 构造和析构函数
malloc
/free
:malloc
只是简单地分配内存,不会调用对象的构造函数。free
也不会调用对象的析构函数。new
/delete
:new
会调用对象的构造函数,delete
会调用析构函数,确保对象的资源能够被正确清理。
5. 内存分配失败
malloc
:如果malloc
无法分配所需的内存,它会返回NULL
。new
:new
如果无法分配内存,会抛出std::bad_alloc
异常(除非使用new(std::nothrow)
,此时会返回nullptr
)。
6. 效率
malloc
/free
:在 C 语言中,malloc
和free
主要用于手动管理内存,不会涉及对象的构造和析构,因此相对较低级和直接。new
/delete
:new
和delete
由 C++ 编译器实现,通常会做额外的检查(比如调用构造/析构函数、内存池管理等),可能比malloc
和free
稍微慢一些,但它们与对象的生命周期管理是紧密结合的。
7. 使用习惯
malloc
/free
:这些函数更常见于 C 语言中,或者在与 C 兼容的 C++ 代码中使用。new
/delete
:这两个操作符是 C++ 推荐的内存管理方式,它们与 C++ 的面向对象特性(如构造、析构)兼容。
相关文章:

C++中的内存管理
学完了类与对象,这节我们来了解一下内存里的那些事 文章目录 一、C/C中的内存分布 1. 常量区(代码段) (Text Segment) 2. 静态区(数据段) (Data Segment) 3. 堆区 (Heap) 4. 栈区 (Stack) 5. 内存映射区域 (Memory-map…...

MySQL为什么默认引擎是InnoDB ?
大家好,我是锋哥。今天分享关于【MySQL为什么默认引擎是InnoDB ?】面试题。希望对大家有帮助; MySQL为什么默认引擎是InnoDB ? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 MySQL 默认引擎是 InnoDB,主要…...

ComfyUI安装调用DeepSeek——DeepSeek多模态之图形模型安装问题解决(ComfyUI-Janus-Pro)
ComfyUI 的 Janus-Pro 节点,一个统一的多模态理解和生成框架。 试用: https://huggingface.co/spaces/deepseek-ai/Janus-1.3B https://huggingface.co/spaces/deepseek-ai/Janus-Pro-7B https://huggingface.co/spaces/deepseek-ai/JanusFlow-1.3B 安装…...

电脑要使用cuda需要进行什么配置
在电脑上使用CUDA(NVIDIA的并行计算平台和API),需要进行以下配置和准备: 1. 检查NVIDIA显卡支持 确保你的电脑拥有支持CUDA的NVIDIA显卡。 可以在NVIDIA官方CUDA支持显卡列表中查看显卡型号是否支持CUDA。 2. 安装NVIDIA显卡驱动…...

利用Muduo库实现简单且健壮的Echo服务器
一、muduo网络库主要提供了两个类: TcpServer:用于编写服务器程序 TcpClient:用于编写客户端程序 二、三个重要的链接库: libmuduo_net、libmuduo_base、libpthread 三、muduo库底层就是epoll线程池,其好处是…...

Scratch 《像素战场》系列综合游戏:像素战场游戏Ⅰ~Ⅲ 介绍
资源下载 Scratch《像素战场》系列综合游戏合集:像素战场游戏Ⅰ~Ⅲ压缩包 https://download.csdn.net/download/leyang0910/90332765 游戏操作介绍 Scratch 《像素战场Ⅰ》操作规则: 这是一款与朋友一起玩的 1v1 游戏。先赢得6轮胜利! WA…...

Android学习制作app(ESP8266-01S连接-简单制作)
一、理论 部分理论见arduino学习-CSDN博客和Android Studio安装配置_android studio gradle 配置-CSDN博客 以下直接上代码和效果视频,esp01S的收发硬件代码目前没有分享,但是可以通过另一个手机网络调试助手进行模拟。也可以直接根据我的代码进行改动…...

三甲医院大型生信服务器多配置方案剖析与应用(2024版)
一、引言 1.1 研究背景与意义 在当今数智化时代,生物信息学作为一门融合生物学、计算机科学和信息技术的交叉学科,在三甲医院的科研和临床应用中占据着举足轻重的地位。随着高通量测序技术、医学影像技术等的飞速发展,生物医学数据呈爆发式…...

【Unity3D】实现横版2D游戏——单向平台(简易版)
目录 问题 项目Demo直接使用免费资源:Hero Knight - Pixel Art (Asset Store搜索) 打开Demo场景,进行如下修改,注意Tag是自定义标签SingleDirCollider using System.Collections; using System.Collections.Generic;…...

大白话讲清楚embedding原理
Embedding(嵌入)是一种将高维数据(如单词、句子、图像等)映射到低维连续向量的技术,其核心目的是通过向量表示捕捉数据之间的语义或特征关系。以下从原理、方法和应用三个方面详细解释Embedding的工作原理。 一、Embe…...

电脑优化大师-解决电脑卡顿问题
我们常常会遇到电脑运行缓慢、网速卡顿的情况,但又不知道是哪个程序在占用过多资源。这时候,一款能够实时监控网络和系统状态的工具就显得尤为重要了。今天,就来给大家介绍一款小巧实用的监控工具「TrafficMonitor」。 「TrafficMonitor 」是…...

el-table组件样式如何二次修改?
文章目录 前言一、去除全选框按钮样式二、表头颜色的修改 前言 ElementUI中的组件el-table表格组件提供了丰富的样式,有一个全选框的el-table组件,提供了全选框和多选。 一、去除全选框按钮样式 原本默认是有全选框的。假如有一些开发者,因…...

java练习(1)
两数之和(题目来自力扣) 给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。 你可以假设每种输入只会对应一个答案,并且你不能使用两次相…...

UbuntuWindows双系统安装
做系统盘: Ubuntu20.04双系统安装详解(内容详细,一文通关!)_ubuntu 20.04-CSDN博客 ubuntu系统调整大小: 调整指南: 虚拟机中的Ubuntu扩容及重新分区方法_ubuntu重新分配磁盘空间-CSDN博客 …...

DeepSeek大模型技术深度解析:揭开Transformer架构的神秘面纱
摘要 DeepSeek大模型由北京深度求索人工智能基础技术研究有限公司开发,基于Transformer架构,具备卓越的自然语言理解和生成能力。该模型能够高效处理智能对话、文本生成和语义理解等复杂任务,标志着人工智能在自然语言处理领域的重大进展。 关…...

MusicFree-开源的第三方音乐在线播放和下载工具, 支持歌单导入[对标落雪音乐]
MusicFree 链接:https://pan.xunlei.com/s/VOI0RrVLTTWE9kkpt0U7ofGBA1?pwd4ei6#...

Versal - 基础4(VD100+Versal IBERT)
1. 简介 在之前的一篇博文中,我分享了在 Zynq Ultrascale MPSoC 中使用 IBERT 的方法。 《Vivado - 集成眼图分析仪 Serial I/O IBERT 误码率_vivado ibert-CSDN博客》 本文进一步探讨 Versal 中使用 IBERT 的方法。 2. 硬件平台 芯片:XCVE2302-SF…...

vue2和vue3路由封装及区别
Vue 2 和 Vue 3 在路由封装方面有一些区别,主要体现在 Vue Router 版本的升级(Vue Router 3 -> Vue Router 4)上。下面我们来对比一下 Vue 2 和 Vue 3 在路由封装上的主要区别,并提供相应的代码示例。 1. Vue 2 路由封装&#…...

Windows 系统下使用 Ollama 离线部署 DeepSeek - R1 模型指南
引言 随着人工智能技术的飞速发展,各类大语言模型层出不穷。DeepSeek - R1 凭借其出色的语言理解和生成能力,受到了广泛关注。而 Ollama 作为一款便捷的模型管理和部署工具,能够帮助我们轻松地在本地环境中部署和使用模型。本文将详细介绍如…...

性能测试网络风险诊断有哪些?
目录 一、网络定位分析手段 二、sar命令 三、netstat命令 以下是几种常见的网络风险诊断方法 网络连通性检查 带宽与延迟测量 丢包率分析 网络拓扑结构审查 安全设备影响评估 协议层面上的优化 负载均衡器效能检验 云化服务架构下的特殊考量 系统应用之间的交换&am…...

八股文 (一)
文章目录 项目地址一、前端1.1 大文件上传,预览1.2 首页性能优化1.2 流量染色,灰度发布1.3 Websock心跳机制,大数据实时数据优化1.4 Gpu 加速 fps优化1.5 echarts包大小优化和组件封装1.6 前端监控系统1.7 超大虚拟列表卡顿1. 实现2. 相关问题(1) 什么是虚拟化列表,为什么要…...

TVM调度原语完全指南:从入门到微架构级优化
调度原语 在TVM的抽象体系中,调度(Schedule)是对计算过程的时空重塑。每一个原语都是改变计算次序、数据流向或并行策略的手术刀。其核心作用可归纳为: 优化目标 max ( 计算密度 内存延迟 指令开销 ) \text{优化目标} \max…...

c语言进阶(简单的函数 数组 指针 预处理 文件 结构体)
c语言补充 格式 void函数头 {} 中的是函数体 sum函数名 () 参数表 #include <stdio.h>void sum(int begin, int end) {int i;int sum 0;for (i begin ; i < end ; i) {sum i;}printf("%d到%d的和是%d\n", begin, end, sum); …...

终极版已激活!绿话纯净,打开即用!!!
今天我想和大家聊聊一个非常实用的工具——视频转换大师最终版。 视频转换大师终极版,堪称一款全能型的视频制作神器,集视频转换与编辑功能于一体。它搭载的视频增强器技术,能够最大限度地保留原始视频质量,甚至还能实现质量的进…...

Vue.js 什么是 Composition API?
Vue.js 什么是 Composition API? 今天我们来聊聊 Vue 3 引入的一个重要特性:组合式 API(Composition API)。如果你曾在开发复杂的 Vue 组件时感到代码难以维护,那么组合式 API 可能正是你需要的工具。 什么是组合式 …...

MySQL高可用
一、mysql路由 1.利用路由器的连接路由特性,用户可以编写应用程序来连接到路由器,并令路由器使用响应的路由策略来处理连接来使其连接到正确的mysql数据库服务器 2.mysql route的部署方式 需要在所有数据库主机之外再打开一台主机mysql-router 配置mysql…...

30.Word:设计并制作新年贺卡以及标签【30】
目录 NO1.2 NO3邮件合并-信函 NO4邮件合并-标签 NO1.2 另存为/F12:考生文件夹:Word.docx布局→页面设置对话框→页边距:上下左右→纸张:宽度/高度(先调页边距🆗)设计→页面颜色→填充效果→…...

Flink2支持提交StreamGraph到Flink集群
最近研究Flink源码的时候,发现Flink已经支持提交StreamGraph到集群了,替换掉了原来的提交JobGraph。 新增ExecutionPlan接口,将JobGraph和StreamGraph作为实现。 Flink集群Dispatcher也进行了修改,从JobGraph改成了接口Executio…...

大模型本地化部署(Ollama + Open-WebUI)
文章目录 环境准备下载Ollama模型下载下载Open-WebUI 本地化部署的Web图形化界面本地模型联网查询安装 Docker安装 SearXNG本地模型联网查询 环境准备 下载Ollama 下载地址:Ollama网址 安装完成后,命令行里执行命令 ollama -v查看是否安装成功。安装成…...

C++哈希(链地址法)(二)详解
文章目录 1.开放地址法1.1key不能取模的问题1.1.1将字符串转为整型1.1.2将日期类转为整型 2.哈希函数2.1乘法散列法(了解)2.2全域散列法(了解) 3.处理哈希冲突3.1线性探测(挨着找)3.2二次探测(跳…...