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

STL?string!!!

一、引言

        在之前的文章中,我们一同学习了有关类和对象、模板、动态内存管理的相关知识,那么接下来一段时间我们将要趁热打铁,一起来手撕C++库中最重要的一个库----STL中的一些容器,在手撕它们之前,我将先介绍一下对应的容器,在这个过程中,我们将加深之前学习过的相关知识。

二、string的前置内容

        1、string的介绍

        事实上string并不是STL中的一个容器,这是由于C++的发展历史的原因,但是随着语言的发展,string与STL中的容器的风格以及使用方法已经有着很高的耦合度了,所以我将它放在STL这里一起学习。

        string是一个字符串类,可以借助其提供的接口进行字符串的各种增删查改操作,它的底层其实就是一个存储字符数组的顺序表。

·        2、string中的常用接口

        事实上,string所提供的接口是有很多冗余的,大概有100多个接口,在实现部分都只涉及到一些常用的接口,通过这些常用的接口已经可以处理平常所能遇到的几乎所有情况了,如果需要了解所有接口或者对于以下接口的使用还不太熟悉的话,可以调转到以下网站了解:cplusplus.com - The C++ Resources Networkhttps://legacy.cplusplus.com/三、手撕一个string类

        1、string类的成员变量及整体的框架

        为了与库中的string区分,我们将在自己的命名空间中进行定义相关变量,这个命名空间的名字是无所谓的,为了方便起见,我将直接展开std命名空间,但是在真实场景下,不直接展开会更好一些 

        同时在这里说明一下,我们将在写一个函数之前先将库中的函数头放在前面,以其为导引,同时在这里简单的说明一下该函数的作用

        string类是一个字符类型的顺序表,所以需要一个内置的字符类型的指针来管理字符串中的内容,对于一个顺序表,需要记录它的长度,同时我们将动态开辟空间,所以记录此时string中的空间是多少也是非常重要的:
        

        涉及到类似顺序表的结构,_size、_capacity都是必要的,这个在以后也经常用到,同时在命名时,在成员变量之前加一个‘_’可以区分成员变量与外部变量

        2、类的构造函数与析构函数

        库中的函数头:
        

        以上是库中所提供的所有的构造函数,我们只实现图中圈出的两个,还有几个是拷贝构造函数,在后面会实现,同时由于析构函数名一定并且没有返回值,不传参,这里就不展示了

        一般来说构造函数我们更倾向于在初始化列表进行初始化,但是由于要开空间,同时对于一个内置类型来说,在函数体内赋值和在初始化列表进行初始化的效率差别不是很大,所以我都采用函数体内赋值:
        

       可以看到,在上面我们只实现了一个构造函数但是由于它是带缺省值的,如果不传参默认会构造一个空串,所以与库中的函数是配合的,需要注意的是,在开空间时一定要多开一个空间,这个位置是留给‘\0’的

        3、类中留给类外读取信息的几个简单函数

        库中的函数头:

                (1).size函数:返回此时字符串中的元素个数
                

                (2).c_str函数:返回一个c风格的字符串

                

                这两个函数实现起来是很简单的,就不做过多的介绍了:
                

        4、[]操作符重载

        库中的函数头:
        

        []操作符重载的作用是让我们实现的类类型可以像正常的数组一样使用[]访问下标的方式来访问字符串中指定位置的内容,使用起来很方便,同时代码的可读性变高

        可以看到,该操作重载有两个函数重载,这两个函数重载都是很有必要的,当this指针不被const修饰时,函数提供给非const类型使用,可读可写;当this指针被const修饰时,函数提供给const类型使用,只读不写:
        

        可以看到,该函数的实现也是非常的方便的,并且两个重载的内容也一模一样,这时候我们可以使用模板来简化代码,但由于这是很简单的两个重载,所以没有必要,在以后STL中其它部分,我们会大量的使用模板的相关知识

        5、完成迭代器的封装

        库中的函数头:
                (1).begin

                

                (2).end

                

        迭代器是STL的相关容器中的一个重要工具,常被用来遍历容器,它是类中定义的一个类型,使用起来和指针非常相似,在类中定义类型有两种方式,封装内部类和typedef,很明显使用指针就可以直接遍历一个字符类型的数组,所以string类的迭代器我们可以直接使用typedef封装字符指针的方式

        了解迭代器之后,我们还需要了解begin和end是留给用户使用迭代器的两个接口,begin返回指向首元素的迭代器,end返回指向末尾元素下一个位置的迭代器,它们也都进行了重载,同样分为只读不写和可读可写,在之前已经详细介绍过,这里就不多介绍了:
        

        6、一个特殊的常量

        库中的介绍:
        

        在库中定义了一个静态成员变量npos,它的值是-1,但由于它是size_t类型的,所以实质上是一个非常大的正整数,我们默认一个自负床不会有这么长,所以在库中的函数将npos这一静态成员变量当作无穷大来使用:
        

        在这里需要注意:类中的静态成员变量一定要记得在类外进行定义,虽然const修饰的静态成员变量是可以i直接在类内声明时直接定义的,但为了统一性,这里我还是在类外进行了定义

       7、拷贝构造函数

        库中的函数头:
        

        拷贝构造函数的作用在这里就不多介绍了,它在之后的函数返回一个string类型、传参时传一个string类型、赋值运算符重载时都会用到:
        

        8、开空间函数

        库中的函数头:
        reserve:开指定大小的空间,将原数据进行拷贝,剩余部分不做处理

        

        

        9、插入相关函数-----append

        库中的函数头:
        

        append函数是用于在字符串末尾插入的函数,可以看到库中提供了很多的函数重载,接下来我们只会实现以上圈出的几个,同时我们将借助缺省值简化代码:
               

        纠正一下:不小心忘记进行:_size += n\_size += sublen啦,这是在写完之后测试的时候发现的,所以一定要边写边测试啊!!!

        10、交换函数

        库中的函数头:
        

        swap函数顾名思义就是交换两个string类对象,需要注意的是我们将完成深拷贝,也就是说要重新开空间,而不能简单的交换两个类对象的成员变量,这时候我们可以借助算法库中提供的swap函数,它可以帮助我们完成深拷贝,事实上我们可以直接进行深拷贝,但是借助算法库实现会更简单:

        

        需要注意的是:在这里我们需要指定标准命名空间

        11、赋值运算符重载

        库中的函数头:
        

        库中海还有该函数的其它重载,但其实都可以通过该函数完成剩余操作,所以只实现这一个,同时,由于我们可以借助一种更简单的方式来完成该函数的实现,所以接下来我对该函数的实现时,函数头与库中的略有差异,但是对于用户的使用是相同的:
        

        对以上代码做一下解释:我们的函数实参传给形参会进行临时拷贝,这是会调用我们之前实现过的拷贝构造函数进行深拷贝,再交换*this与str,*this就变成了str,str是形参,出作用域销毁,调用析构函数,不会造成内存泄漏,*this出函数还存在,进行传引用返回

        12、其它运算符重载

        由于接下来都是正常的运算符重载,功能也是显而易见的,所以在这里就不提供库中的函数头了,直接进行相关的实现:
        

//其它运算符重载//+=运算符重载
string& operator+=(const string& str)
{return append(str);
}
string& operator+=(const char* s)
{return append(s);
}
string& operator+=(char c)
{return append(1, c);
}
//+运算符重载
string operator+(const string& str)
{string strtmp(*this);return (strtmp += str);
}
string operator+(const char* s)
{string strtmp(*this);return (strtmp += s);
}
string operator+(char c)
{string strtmp(*this);return (strtmp += c);
}
//<运算符重载
bool operator < (const string& s) const
{int minlen = _size;if (s._size < _size){minlen = s._size;}for (int i = 0; i < minlen; i++){if (_str[i] != s._str[i]){return _str[i] < s._str[i];}}return _size < s._size;
}
//==运算符重载
bool operator==(const string& s) const
{if (_size != s._size) return false;for (int i = 0; i < _size; i++){if (_str[i] != s._str[i]){return false;}}return true;
}
//<=运算符重载
bool operator<=(const string& s) const
{return ((*this < s) || (*this == s));
}
//>运算符重载
bool operator>(const string& s) const
{return (!(*this < s) && !(*this == s));
}
//>=运算符重载
bool operator>=(const string& s) const
{return ((*this > s) || (*this == s));
}
//!=运算符重载
bool operator!=(const string& s) const
{return !(*this == s);
}

        以上就是所有可能用到的运算符重载了,由于很长,所以我将代码直接放在上面,可以看到,由于这些逻辑运算符有天然的互斥性,所以我们可以很好的进行代码复用,大大提高了代码的质量

        13、插入相关函数-----push_back

        库中的函数头:
        

        该函数的作用是在字符串末尾插入一个字符,无返回值:
        

        在这个位置我们可以直接进行代码复用

        14、插入相关函数-----insert

        库中的函数头:
        

        库中对于插入函数也是提供了非常多的重载,我们只实现图中圈出的几个,同时我们会使用缺省值的方式简化代码:
         

//插入函数
string& insert(size_t pos, const string& str, size_t subpos = 0, size_t sublen = npos)
{assert(pos < _size);assert(subpos < str._size);if (subpos + sublen >= str._size) sublen = str._size - subpos;if (_capacity < _size + sublen + 1){reserve(_size + sublen + 1 + 0.5 * sublen);}int end = _size , next = end + sublen;while (next > pos){_str[next--] = _str[end--];}for (int i = 0; i < sublen; i++){_str[pos + i] = str._str[i];}_size += sublen;return *this;
}
string& insert(size_t pos, const char* s, size_t n = npos)
{string strtmp(s);return insert(pos, s, 0, n);
}
string& insert(size_t pos, size_t n, char c)
{assert(pos < _size);if (_capacity < _size + n + 1){reserve(_size + n + 1 + 0.5 * n);}int end = _size, next = end + n;while (next > pos){_str[next] = _str[end];}for (int i = 0; i < n; i++){_str[pos + n] = c;}_size += n;return *this;
}

        可以看到,在上面我们也进行了一定程度的代码复用,所以代码复用是非常重要的,可以大大提高代码质量

        15、删除函数

        库中的函数头:
        

        erase函数的作用是从pos位置开始,删除len长度的字符:
        

        16、查找相关函数

        库中的函数头:
        

        库中对于查找函数也是实现了多个函数重载,在这里我们只实现上面圈出的两个,其他的通过借助这两个函数也是都可以完成的:

        

        在上面的实现中我们借助了C语言常用的几个函数,简化了代码

        17、返回子串的函数

        库中的函数头:
        

        该函数的作用是返回从pos位置开始len长度的子串:

        

        18、清理函数

        库中的函数头:

        

        该函数可以清空字符串中的数据:
        

四、最终的string类

        终于,我们一起写完了一个简陋版的string类,需要注意的是在这个过程中我们更关注的是了解string的使用、加深对于类和对象等知识的理解和提升我们的代码能力,并不是写出一个更好的string类,最终完成的string类如下:
        

namespace bea
{class string{public://相关函数//构造函数string(const char* s = ""){int n = strlen(s);_str = new char[n + 1];memcpy(_str, s, n + 1);_size = n;_capacity = n;}//size函数size_t size() const{return _size;}//c_str函数const char* c_str() const{return _str;}//[]操作符重载// // 普通类型char& operator[](size_t pos){assert(pos < _size);return _str[pos];}//const类型const char& operator[](size_t pos) const{assert(pos < _size);return _str[pos];}//迭代器相关接口//先进行类型的封装typedef char* iterator;typedef const char* const_iterator;//begin函数iterator begin(){return _str;}const_iterator begin() const{return _str;}//end函数iterator end(){return _str + _size;}const_iterator end() const{return _str + _size;}string(const string& str){_str = new char[str._capacity + 1];memcpy(_str, str._str, _size + 1);_size = str._size;_capacity = str._capacity;}//开空间函数void reserve(size_t n = 0){if (n > _capacity){char* strtmp = new char[n + 1];memcpy(strtmp, _str, _size + 1);delete[] _str;_str = strtmp;_capacity = n;}}//尾接函数//尾接C风格字符串//接入s字符串的前n个字符string& append(const char* s, size_t n = npos){size_t len = strlen(s);if (n > len) n = len;if (_capacity < _size + n + 1){reserve(_size + n + 1 + 0.5 * n);}for (int i = 0; i < n; i++){_str[_size + i] = s[i];}_str[_size + n + 1] = '\0';_size += n;return *this;}//尾接一个string//接入str的subpos开始sublen长度的子串string& append(const string& str, size_t subpos = 0, size_t sublen = npos){assert(subpos < str._size);if (subpos + sublen >= str._size) sublen = _size - subpos;if (_capacity < _size + sublen + 1){reserve(_size + sublen + 1 + 0.5 * sublen);}for (int i = 0; i < sublen; i++){_str[_size + i] = str._str[i];}_str[_size + sublen + 1] = '\0';_size += sublen;return *this;}//尾接n个chstring& append(size_t n, char ch){if (_capacity < _size + n + 1){reserve(_size + n + n * 0.5);}for (int i = 0; i < n; i++){_str[_size + i] = ch;}_str[_size + n + 1] = '\0';_size += n;return *this;}//交换函数void swap(string& str){std::swap(_str, str._str);std::swap(_size, str._size);std::swap(_capacity, str._capacity);}//赋值运算符重载string& operator=(string str){swap(str);return *this;}//其它运算符重载//+=运算符重载string& operator+=(const string& str){return append(str);}string& operator+=(const char* s){return append(s);}string& operator+=(char c){return append(1, c);}//+运算符重载string operator+(const string& str){string strtmp(*this);return (strtmp += str);}string operator+(const char* s){string strtmp(*this);return (strtmp += s);}string operator+(char c){string strtmp(*this);return (strtmp += c);}//<运算符重载bool operator < (const string& s) const{int minlen = _size;if (s._size < _size){minlen = s._size;}for (int i = 0; i < minlen; i++){if (_str[i] != s._str[i]){return _str[i] < s._str[i];}}return _size < s._size;}//==运算符重载bool operator==(const string& s) const{if (_size != s._size) return false;for (int i = 0; i < _size; i++){if (_str[i] != s._str[i]){return false;}}return true;}//<=运算符重载bool operator<=(const string& s) const{return ((*this < s) || (*this == s));}//>运算符重载bool operator>(const string& s) const{return (!(*this < s) && !(*this == s));}//>=运算符重载bool operator>=(const string& s) const{return ((*this > s) || (*this == s));}//!=运算符重载bool operator!=(const string& s) const{return !(*this == s);}//push_back函数void push_back(char c){*this += c;}//插入函数string& insert(size_t pos, const string& str, size_t subpos = 0, size_t sublen = npos){assert(pos < _size);assert(subpos < str._size);if (subpos + sublen >= str._size) sublen = str._size - subpos;if (_capacity < _size + sublen + 1){reserve(_size + sublen + 1 + 0.5 * sublen);}int end = _size , next = end + sublen;while (next > pos){_str[next--] = _str[end--];}for (int i = 0; i < sublen; i++){_str[pos + i] = str._str[i];}_str[pos + sublen + 1] = '\0';_size += sublen;return *this;}string& insert(size_t pos, const char* s, size_t n = npos){string strtmp(s);return insert(pos, s, 0, n);}string& insert(size_t pos, size_t n, char c){assert(pos < _size);if (_capacity < _size + n + 1){reserve(_size + n + 1 + 0.5 * n);}int end = _size, next = end + n;while (next > pos){_str[next] = _str[end];}for (int i = 0; i < n; i++){_str[pos + n] = c;}_str[pos + n + 1] = '\0';_size += n;return *this;}//删除函数string& erase(size_t pos = 0, size_t len = npos){assert(pos < _size);if (pos + len >= _size){_str[pos] = '\0';_size -= len;return *this;}int end = pos + len, front = pos;while (front < _size){_str[front++] = _str[end++];}_size -= len;_str[pos + len + 1] = '\0';return *this;}//找字符函数size_t find(char ch, size_t pos = 0){assert(pos < _size);for (int i = pos; i < _size; i++){if (_str[i] == ch) return i;}return npos;}//找字符串size_t find(const char* str, size_t pos = 0){assert(pos < _size);const char* ptr = strstr(_str + pos, str);if (ptr){return ptr - _str;}else{return npos;}}//子串函数string substr(size_t pos = 0, size_t len = npos){if (pos == 0 && len >= _size) return *this;if (pos + len >= _size) len = _size - pos;string tmp;for (int i = pos; i < pos + len; i++) tmp.push_back(_str[i]);return tmp;}//清除函数void clear(){_str[0] = '\0';_size = 0;}//析构函数~string(){delete[] _str;_str = nullptr;_size = _capacity = 0;}private:char* _str;size_t _size;size_t _capacity;static const size_t npos;};const size_t string::npos = -1;
}

五、结语

        以上就是本期关于手撕string类的所有内容了,感谢大家的阅读,欢迎各位于晏、亦菲和我一起交流、学习、进步!!!        

        

        
        
        

      

                

             
                        

        
        

                                

                

相关文章:

STL?string!!!

一、引言 在之前的文章中&#xff0c;我们一同学习了有关类和对象、模板、动态内存管理的相关知识&#xff0c;那么接下来一段时间我们将要趁热打铁&#xff0c;一起来手撕C库中最重要的一个库----STL中的一些容器&#xff0c;在手撕它们之前&#xff0c;我将先介绍一下对应的容…...

CentOS 7 安装指定版本 Docker 及镜像加速/配置优化攻略

摘要 本文详述 CentOS 7 系统下安装指定版本 Docker &#xff0c;涵盖镜像加速配置&#xff08;实测最快&#xff09;、存储位置优化、日志轮转等核心配置。 文章目录 一、安装指定版本Docker1.1 卸载旧版本&#xff08;如有&#xff09;1.2 安装依赖包1.3 添加Docker仓库&…...

域名别名(CNAME)解析及域名注册操作步骤

以虚拟主机为例&#xff0c;大多网站空间无独立ip&#xff0c;域名打开以别名解析为主&#xff0c;那域名别名&#xff08;CNAME&#xff09;如何解析呢&#xff1f;以下以新网为例&#xff0c;别名解析操作步骤&#xff1a; 1.登录域名管理界面&#xff0c;点击管理解析记录; …...

JVM内存模型深度解剖:分代策略、元空间与GC调优实战

堆 堆是Java虚拟机&#xff08;JVM&#xff09;内存管理的核心区域&#xff0c;其物理存储可能分散于不同内存页&#xff0c;但逻辑上被视为连续的线性空间。作为JVM启动时创建的第一个内存区域&#xff0c;堆承载着几乎所有的对象实例和数组对象&#xff08;极少数通过逃逸分…...

Unity_JK框架【1】 框架导入 对象池示例 (资源管理底层)

一、JK框架介绍 主要功能系统&#xff1a; 对象池系统&#xff1a;重复利用GameObject或普通class实例&#xff0c;并且支持设置对象池容量 事件系统&#xff1a;解耦工具&#xff0c;不需要持有引用来进行函数的调用 资源系统 Resources版本&#xff1a;关联对象池进行资源…...

JDK 发展历史及其版本特性

JDK&#xff08;Java Development Kit&#xff0c;Java开发工具包&#xff09;是用于开发Java应用程序的核心工具之一。它由Oracle&#xff08;最初由Sun Microsystems&#xff09;提供&#xff0c;包含了Java编译器、Java运行环境&#xff08;JRE&#xff09;、Java标准类库等…...

B站视频下载到电脑的方法总结

将B站&#xff08;哔哩哔哩&#xff09;视频下载到电脑的方法有多种&#xff0c;以下是几种常见且有效的方法&#xff0c;分为 官方工具 和 第三方工具 两类&#xff1a; 一、官方方法&#xff08;B站客户端或功能&#xff09; 哔哩哔哩客户端&#xff08;UWP/PC版&#xff09;…...

2025 后端自学UNIAPP【项目实战:旅游项目】2、安装下载引用前端UI框架:uview-plus

1、uview-plus官网地址&#xff0c;有详细介绍&#xff0c;感兴趣的可以深入了解学习 介绍 | uview-plus - 全面兼容nvue/鸿蒙/uni-app-x的uni-app生态框架 - uni-app UI框架 2、Hbuilder X 方式安装下载引入uview-plus ①进入该网址&#xff0c;点击 下载插件并导入Hbuild…...

Vue 的双向绑定原理,Vue2 和 Vue3 双向绑定原理的区别

Vue 的双向绑定原理&#xff0c;Vue2 和 Vue3 双向绑定原理的区别 Vue 的双向绑定&#xff08;Two-way Data Binding&#xff09;是其核心特性之一&#xff0c;其本质是通过数据劫持结合发布-订阅模式实现的。以下是 Vue2 和 Vue3 在双向绑定原理上的区别和演进&#xff1a; 文…...

RAG_Techniques:探索GitHub热门RAG技术开源项目

RAG_Techniques&#xff1a;探索GitHub热门RAG技术开源项目 引言项目概述RAG技术简介与重要性核心功能详解1. 分类清晰的技术体系2. 前沿技术解析3. 评估工具与方法 安装和使用教程应用场景和实际价值企业知识库和文档检索教育和研究辅助个性化内容推荐 结论 引言 在当今AI领域…...

Java高频面试之并发编程-12

hello啊&#xff0c;各位观众姥爷们&#xff01;&#xff01;&#xff01;本baby今天又来报道了&#xff01;哈哈哈哈哈嗝&#x1f436; 面试官&#xff1a;详细说说java的内存模型 Java内存模型&#xff08;Java Memory Model, JMM&#xff09;是Java多线程编程的核心&#…...

多线程系列五:面试中常考的单例模式

1.设计模式 在了解单例模式之前我们先要了解设计模式&#xff1a; 设计模式是一种软性规定&#xff0c;遵守了设计模式&#xff0c;代码的下限就被兜住了&#xff0c;类似于棋谱&#xff0c;是大佬设计出来的&#xff0c;让小白程序员也能写出好的代码 设计模式有很多种&#x…...

音视频之H.265/HEVC编解码并处理

H.265/HEVC系列文章&#xff1a; 1、音视频之H.265/HEVC编码框架及编码视频格式 2、音视频之H.265码流分析及解析 3、音视频之H.265/HEVC预测编码 4、音视频之H.265/HEVC变换编码 5、音视频之H.265/HEVC量化 6、音视频之H.265/HEVC环路后处理 7、音视频之H.265/HEVC熵编…...

Python入门(一)

目录 一、Python数据类型 1.字面量 2.注释 3.变量 4.数据类型 二、 运算符 1.数据类型之间的相互转换 2 算数运算符 3、逻辑运算符 三、判断语句 if 四、循环 1、while循环 2、for循环 2.1 for...else... 五、格式化字符串 1.字符串 1.1创建字符串的方式&…...

2025年01月09日德美医疗前端面试

目录 vue2 的双向绑定的原理vue3 的双向绑定原理vue 的生命周期vue 子组件为何不能修改父组件的值js delete 删除数组的某一个值会怎么样vue 和 react 的 diff 算法什么是闭包原型链this指向 vue2 的双向绑定的原理 以下是 Vue 2 双向绑定的原理&#xff1a; 1. 核心概念 …...

02 mysql 管理(Windows版)

一、启动及关闭 MySQL 服务器 1.1 通过 “服务” 管理工具 winr打开运行&#xff0c;输入services.msc 找到MySQL80&#xff0c;这个是我们在安装mysql的时候给的服务的名称&#xff0c;具体见文章mysql 安装 右键选择启动或者停止。 1.2 通过命令提示符 1.2.1 关闭命令…...

开发搭载OneNet平台的物联网数据收发APP的设计与实现

一、开发环境与工具准备 工具安装 下载HBuilderX开发版(推荐使用开发版以避免插件兼容性问题)安装Node.js和npm(用于依赖管理及打包)配置Android Studio(本地打包需集成离线SDK)项目初始化 创建uni-app项目,选择“默认模板”或“空白模板”安装必要的UI库(如uView或Van…...

ntdll!LdrpInitializeProcess函数分析之Peb->Ldr和全局变量ntdll!PebLdr的关系

代码部分A&#xff1a; PEB_LDR_DATA PebLdr; //全局变量ntdll!PebLdr NTSTATUS LdrpInitializeProcess ( IN PCONTEXT Context OPTIONAL, IN PVOID SystemDllBase ) { 代码部分B&#xff1a; // // Figure out process name. // Teb NtCurrentTeb…...

如何开始使用 Blender:Blender 3D 初学者指南和简介 怎么下载格式模型

Blender 是一个强大的 3D 创作套件&#xff0c;为动画、视觉效果、艺术等提供了一系列功能。无论您是初学者还是经验丰富的艺术家&#xff0c;Blender 都提供了一个免费的开源平台来释放您的创造力。凭借其内置的视频序列编辑器&#xff0c;Blender 还提供基本的编辑功能&#…...

Nginx安全防护与HTTPS部署

目录 一、Nginx 概述 二、Nginx 核心安全配置 &#xff08;一&#xff09;编译安装 Nginx &#xff08;二&#xff09;隐藏版本号 &#xff08;三&#xff09;限制危险请求方法 &#xff08;四&#xff09;请求限制&#xff08;CC 攻击防御&#xff09; &#xff08;五&…...

HTTP 与 HTTPS 的深度剖析:差异、原理与应用场景

HTTP 与 HTTPS 的深度剖析&#xff1a;差异、原理与应用场景 在互联网的世界里&#xff0c;HTTP&#xff08;超文本传输协议&#xff09;和 HTTPS&#xff08;超文本传输安全协议&#xff09;是数据传输的 “高速公路”&#xff0c;它们承载着我们日常浏览网页、购物支付等各种…...

SMT贴片钢网精密设计与制造要点解析

内容概要 SMT贴片钢网作为电子组装工艺的核心载体&#xff0c;其设计与制造质量直接影响焊膏印刷精度及产品良率。本文系统梳理了钢网全生命周期中的15项关键技术指标&#xff0c;从材料选择、结构设计到工艺控制构建完整技术框架。核心要点涵盖激光切割精度的微米级调控、开口…...

算法每日一题 | 入门-顺序结构-三角形面积

三角形面积 题目描述 一个三角形的三边长分别是 a、b、c&#xff0c;那么它的面积为 p ( p − a ) ( p − b ) ( p − c ) \sqrt{p(p-a)(p-b)(p-c)} p(p−a)(p−b)(p−c) ​&#xff0c;其中 p 1 2 ( a b c ) p\frac{1}{2}(abc) p21​(abc) 。输入这三个数字&#xff0c;…...

Linux内核视角:线程同步与互斥的原理、实现与锁优化策略

Linux系列 文章目录 Linux系列前言一、前提知识二、线程互斥概念引入三、线程互斥3.1 什么是线程的互斥3.2 线程互斥的实现 四、锁的实现原理 前言 在前两篇文章中&#xff0c;我们已经对线程的相关概念及基本操作进行了深入介绍。在本篇中&#xff0c;我们将深入探讨编写多线…...

【区块链】Uniswap详细介绍

一、前言 本文将结合网上的资料和博主的理解&#xff0c;像大家详细介绍Uniswap&#xff0c;包括其核心概念、工作原理、版本演进、代币经济学以及风险点&#xff0c;适合想深入了解去中心化交易所&#xff08;DEX&#xff09;机制的用户。 二、Uniswap是什么 Uniswap 是一个…...

YOLOv8的Python基础--函数篇

1. 文件/目录操作相关函数 这些函数来自 os 和 shutil 模块&#xff1a; 函数/用法作用示例说明os.listdir(dir)列出目录下所有文件名os.listdir("./images")返回文件名列表&#xff08;不包含路径&#xff09;os.path.join()拼接路径os.path.join("dir"…...

vue源代码采用的设计模式分解

No.大剑师精品GIS教程推荐0地图渲染基础- 【WebGL 教程】 - 【Canvas 教程】 - 【SVG 教程】 1Openlayers 【入门教程】 - 【源代码示例 300】 2Leaflet 【入门教程】 - 【源代码图文示例 150】 3MapboxGL【入门教程】 - 【源代码图文示例150】 4Cesium 【入门教程】…...

强化学习是AI Agent的进化引擎还是技术枷锁呢?

第一章 强化学习&#xff1a;Agent的“灵魂”觉醒之路 1.1 AlphaGo的启示&#xff1a;从规则到目标驱动的范式革命 2016年AlphaGo击败李世石的事件&#xff0c;标志着RL首次在复杂决策场景中展现其颠覆性价值。通过深度神经网络与RL的结合&#xff0c;AlphaGo无需依赖人类棋谱…...

python简易实现勒索病毒

python简易实现勒索病毒 1.首先介绍Crypto库1.1首先是对称加密1.2 非对称加密1.3 哈希 2.生成RSA密钥并保存3.文件加密4.文件解密1. 导入必要的模块2. 定义解密函数3. 设置私钥的密码4. 打开并读取文件5. 导入私钥6. 读取加密数据7. 解密会话密钥8. 创建 AES 解密器9. 解密数据…...

Nacos源码—4.Nacos集群高可用分析三

大纲 6.CAP原则与Raft协议 7.Nacos实现的Raft协议是如何写入数据的 8.Nacos实现的Raft协议是如何选举Leader节点的 9.Nacos实现的Raft协议是如何同步数据的 10.Nacos如何实现Raft协议的简版总结 6.CAP原则与Raft协议 (1)CAP分别指的是什么 (2)什么是分区以及容错 (3)为…...

AWS WebRTC如何实现拉流?内部是这样实现的

当我们通过手机上的app选择某一个Iot设备,例如,摄像头,想看实时视频的时候,aws都做了什么?最近在搞自研Iot项目,借机整理一下相关流程。 App通过 AWS SDK 发起拉流请求的内部机制是AWS Kinesis Video Streams (KVS) WebRTC 模式中一个非常关键的问题。 一、KVS WebRTC …...

NGINX `ngx_http_browser_module` 深度解析与实战

1. 模块定位 ngx_http_browser_module 在 HTTP 头 User-Agent 解析的基础上&#xff0c;给出三个内置变量&#xff1a; 变量作用典型值$modern_browser当 UA 被判定为 现代浏览器 时取 modern_browser_value 指定的值&#xff1b;否则为空modern. / 1$ancient_browser当 UA 被…...

Elasticsearch知识汇总之 ElasticSearch高可用方案

六 ElasticSearch高可用方案 6.1 高可用架构 请求协调节点根据负载均衡&#xff0c;转发给主分片节点&#xff0c;主分片同步复制给从节点&#xff0c;主从节点都写入完成返回客户端请求成功。对于读请求&#xff0c;协调负载到任意节点数据节点&#xff0c;数据节点把各自符合…...

多线程2-多线程编程

引入 当我们想要代码能够实现并发执行时&#xff0c;我们可以使用多进程进行并发编程&#xff08;在Java中并不推荐这种方式&#xff0c;许多API在Java标准库中都没有提供&#xff09;&#xff0c;也可以使用多线程进行并发编程&#xff08;系统提供了相关的API&#xff0c;Ja…...

电商系统中单商户和多商户的区别

在电商的商业版图上&#xff0c;单商户与多商户模式如同两条并行的发展脉络&#xff0c;各自构建起独特的商业生态。它们在运营逻辑、商业模式等多方面存在显著差异&#xff0c;这些差异不仅塑造了不同的平台特性&#xff0c;也深刻影响着企业的发展路径。接下来&#xff0c;我…...

【东枫科技】代理英伟达产品:智能网卡的连接线

文章目录 总览详细&#xff1a;NVIDIA 400Gb/s QSFP-DD 线缆详细&#xff1a;NVIDIA 400Gb/s OSFP 线缆详细&#xff1a;NVIDIA 200Gb/s QSFP56 线缆详细&#xff1a;NVIDIA 100Gb/s QSFP28 线缆 总览 详细&#xff1a;NVIDIA 400Gb/s QSFP-DD 线缆 详细&#xff1a;NVIDIA 400…...

使用ip池后,爬虫还被封,是什么原因呢?

嘿&#xff0c;亲爱的小伙伴们&#xff01;今天我们聊一个让很多爬虫工程师抓狂的问题&#xff1a;明明用上了IP池&#xff0c;结果爬虫还是被封了&#xff01;怎么回事呢&#xff1f;如果你也曾在爬虫与反爬的“猫鼠游戏”里痛苦“翻车”&#xff0c;别着急&#xff0c;这篇文…...

C++23 新利器:深入解析栈踪迹库 (P0881R7)

文章目录 为何需要标准化的栈踪迹&#xff1f;P0881R7 的核心组件与使用基本用法示例与异常处理的集成优势与价值潜在的考量总结 对于 C 开发者而言&#xff0c;调试和错误诊断一直是开发周期中不可或缺但又充满挑战的一环。当程序崩溃或发生未预期行为时&#xff0c;获取清晰、…...

2025-05-06 事业-独立开发项目-记录

摘要: 2025-05-06 事业-独立开发项目-记录 独立开发项目记录 Product Hunt | InDev 独立开发者导航站https://www.producthunt.com/ Nomads.com - Best Places to Live for Digital Nomads (formerly Nomad List)https://nomads.com/ InDev 独立开发者导航站https://indev.bei…...

【Linux系统】探索进程等待与程序替换的奥秘

文章目录 前言一、重谈进程创建1.1 fork 函数1.2 写时拷贝1.3 fork 的常规用法1.4 fork 调用失败的原因1.5 创建一批进程 二、进程终止2.1 进程退出场景2.2 strerror 函数的作用2.3 errno 全局变量2.4 程序异常机制2.5 进程退出方式 三、进程等待3.1 进程等待必要性3.2 进程等待…...

Github 2025-05-06Python开源项目日报 Top10

根据Github Trendings的统计,今日(2025-05-06统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Python项目10C++项目2TypeScript项目1系统设计指南 创建周期:2507 天开发语言:Python协议类型:OtherStar数量:241693 个Fork数量:42010 次…...

【愚公系列】《Manus极简入门》021-音乐创作助手:“音符魔术师”

&#x1f31f;【技术大咖愚公搬代码&#xff1a;全栈专家的成长之路&#xff0c;你关注的宝藏博主在这里&#xff01;】&#x1f31f; &#x1f4e3;开发者圈持续输出高质量干货的"愚公精神"践行者——全网百万开发者都在追更的顶级技术博主&#xff01; &#x1f…...

【Azure Redis】Redis导入备份文件(RDB)失败的原因

问题描述 在测试Azure Redis的导入/导出备份文件的功能中&#xff0c;突然发现在Redis 4.0上导入的时候&#xff0c;一直报错。 image.png 问题解答 因为门户上只是显示导入失败&#xff0c;没有任何错误消息说明。根据常理推断&#xff0c;Redis 的RDB文件格式都具有一致性。居…...

git “分离头指针”(detached HEAD) 状态。

在 Git 中&#xff0c;当你运行 git branch 命令时&#xff0c;看到如下输出&#xff1a; * (detached from 5b596b5)master 其中的&#xff1a; * (detached from 5b596b5) 表示你当前处于 “分离头指针”&#xff08;detached HEAD&#xff09; 状态。 &#x1f9e0; 什…...

Gitee的介绍

目录 1.Gitee介绍&#xff1a; 1.1 代码托管 1.2 本土化优势 1.3 企业级服务 1.4 开源生态 1.5 多形态适配 定位&#xff1a;国内开发者首选的高效代码协作平台&#xff0c;兼顾个人开源与企业级私有开发需求。 2.Gitee和GitHub区别 3.Gitee使用教程 4.Gitee相关…...

NoUniqueKey问题和Regular join介绍

问题背景 在flink任务中&#xff0c;遇到了 NoUniqueKey Join的情况&#xff0c;导致了数据膨胀&#xff0c;和下游结果与数据库数据不一致问题 那NoUniqueKey Join为什么会导致问题呢&#xff0c;下面是其中一种场景示例&#xff1a; 为什么会出现 NoUniqueKey &#xff1a;…...

TC8:SOMEIP_ETS_027-028

SOMEIP_ETS_027: echoUINT8 目的 检查method方法echoUINT8的参数及其顺序能够被顺利地发送和接收 说白了就是检查UINT8数据类型参数在SOME/IP协议层的序列化与反序列化是否正常。 UINT8相比于测试用例SOMEIP_ETS_021: echoINT8中的SINT8数据类型来说,属于无符号整数,也就是…...

小微企业SaaS ERP管理系统,SpringBoot+Vue+ElementUI+UniAPP

小微企业的SaaS ERP管理系统&#xff0c;ERP系统源码&#xff0c;ERP管理系统源代码 一款适用于小微企业的SaaS ERP管理系统, 采用SpringBootVueElementUIUniAPP技术栈开发&#xff0c;让企业简单上云。 专注于小微企业的应用需求&#xff0c;如企业基本的进销存、询价&#…...

css filter 常用方法函数和应用实例

1. blur() 模糊 filter: blur(半径);参数&#xff1a;模糊半径&#xff08;像素&#xff09;&#xff0c;值越大越模糊 示例&#xff1a;filter: blur(5px);2. brightness() 亮度 filter: brightness(百分比); 参数&#xff1a;1原始对比度&#xff0c;0全灰&#xff0c;>…...

chrome inspect 调试遇到的问题

1、oppp 手机打开webview 的时候&#xff0c; 报错这个并没有页面 Offline #V8FIG6SGLN75M7FY Pending authentication: please accept debugging session on the device. 解决方法&#xff0c;保持chrome 浏览器在显示的状态 去设置里开启usb 调试再关闭&#xff0c;反复重…...