string类详解(上)
文章目录
- 目录
- 1. STL简介
- 1.1 什么是STL
- 1.2 STL的版本
- 1.3 STL的六大组件
- 2. 为什么学习string类
- 3. 标准库中的string类
- 3.1 string类
- 3.2 string类的常用接口说明
目录
- STL简介
- 为什么学习string类
- 标准库中的string类
- string类的模拟实现
- 现代版写法的String类
- 写时拷贝
1. STL简介
1.1 什么是STL
STL(standard template libaray-标准模板库):是C++标准库的重要组成部分,不仅是一个可复用的组件库,而且是一个包罗数据结构与算法的软件框架。
1.2 STL的版本
- 原始版本
Alexander Stepanov、Meng Lee 在惠普实验室完成的原始版本,本着开源精神,他们声明允许任何人任意运用、拷贝、修改、传播、商业使用这些代码,无需付费。唯一的条件就是也需要向原始版本一样做开源使用。HP 版本–所有STL实现版本的始祖。
- P. J. 版本
由P. J. Plauger开发,继承自HP版本,被Windows Visual C++采用,不能公开或修改,缺陷:可读性比较低,符号命名比较怪异。
- RW版本
由Rouge Wage公司开发,继承自HP版本,被C+ + Builder 采用,不能公开或修改,可读性一般。
- SGI版本
由Silicon Graphics Computer Systems,Inc公司开发,继承自HP版本。被GCC(Linux)采用,可移植性好,可公开、修改甚至贩卖,从命名风格和编程风格上看,阅读性非常高。我们后面学习STL要阅读部分源代码,主要参考的就是这个版本。
1.3 STL的六大组件

2. 为什么学习string类
C语言中,字符串是以’\0’结尾的一些字符的集合,为了操作方便,C标准库中提供了一些str系列的库函数,但是这些库函数与字符串是分离开的,不太符合OOP的思想,而且底层空间需要用户自己管理,稍不留神可能还会越界访问。
3. 标准库中的string类
3.1 string类
string类的具体信息可以通过cplusplus网站进行查阅
在使用string类时,必须包含#include头文件以及using namespace std;
3.2 string类的常用接口说明
我们先来总的看一下string类的常用接口:
- string类对象的常见构造

- string类对象的容量操作

- string类对象的访问及遍历操作

- string类对象的修改操作

- string类非成员函数

接下来,我们通过一些具体的场景来学习如何使用这些接口:
- 如何构造一个string类对象

#include <iostream>
#include <string>using namespace std;void test_string1()
{//常用string s1;string s2("hello world");string s3(s2);//不常用 了解string s4(s2, 3, 5);string s5(s2, 3);string s6(s2, 3, 30);string s7("hello world", 5);string s8(10, 'x');cout << s1 << endl;cout << s2 << endl;cout << s3 << endl;cout << s4 << endl;cout << s5 << endl;cout << s6 << endl;cout << s7 << endl;cout << s8 << endl;cin >> s1;cout << s1 << endl;
}int main()
{test_string1();return 0;
}
补充:
void push_back(const string& s)
{}void test_string2()
{//构造string s1("hello world");//隐式类型转换string s2 = "hello world";const string& s3 = "hello world";push_back(s1);push_back("hello world");
}int main()
{test_string2();return 0;
}
- string的遍历
第一种方法:
//class string
//{
//public:
// //引用返回
// //1. 减少拷贝
// //2. 修改返回对象
// char& operator[](size_t i)
// {
// assert(i < _size);
//
// return _str[i];
// }
//private:
// char* _str;
// size_t _size;
// size_t _capacity;
//};void test_string3()
{string s1("hello world");cout << s1.size() << endl;//11//cout << s1.length() << endl;//11for (size_t i = 0; i < s1.size(); i++){s1[i]++;}s1[0] = 'x';//越界检查//s1[20];for (size_t i = 0; i < s1.size(); i++){//cout << s1.operator[](i) << " ";cout << s1[i] << " ";}cout << endl;const string s2("hello world");//不能修改//s2[0] = 'x';
}int main()
{test_string3();return 0;
}
![size和operator[]](https://i-blog.csdnimg.cn/direct/1f12491420704b43b4e50bb999fd100a.png)
注: size() 与 length() 方法底层实现原理完全相同,引入 size() 的原因是为了与其他容器的接口保持一致,一般情况下基本都是用 size() 。
第二种方法:

void test_string4()
{string s1("hello world");//遍历方式2:迭代器string::iterator it1 = s1.begin();while (it1 != s1.end()){*it1 += 3;cout << *it1 << " ";++it1;}cout << endl;//cout << typeid(it1).name() << endl;
}int main()
{test_string4();return 0;
}

void test_string4()
{list<int> lt1;lt1.push_back(1);lt1.push_back(2);lt1.push_back(3);list<int>::iterator it = lt1.begin();while (it != lt1.end()){cout << *it << " ";++it;}cout << endl;
}int main()
{test_string4();return 0;
}
第三种方法:
void test_string4()
{string s1("hello world");//遍历方式3:范围for(通用的)//底层角度,它就是迭代器for (auto& e : s1){e++;//不会影响s1中的数据,它是一个赋值拷贝;要加上引用才会改变s1中的数据cout << e << " ";}cout << endl;cout << s1 << endl;list<int> lt1;lt1.push_back(1);lt1.push_back(2);lt1.push_back(3);for (auto& e : lt1){cout << e << " ";}cout << endl;
}int main()
{test_string4();return 0;
}
注: 除了普通迭代器之外,还有
- const迭代器

void test_string5()
{const string s1("hello world");//string::const_iterator it1 = s1.begin();auto it1 = s1.begin();while (it1 != s1.end()){//不能修改//*it1 += 3;cout << *it1 << " ";++it1;}cout << endl;
}int main()
{test_string5();return 0;
}
- 反向迭代器

void test_string5()
{string s2("hello world");string::reverse_iterator it2 = s2.rbegin();//auto it2 = s2.rbegin();while (it2 != s2.rend()){*it2 += 3;cout << *it2 << " ";++it2;}cout << endl;const string s3("hello world");string::const_reverse_iterator it3 = s3.rbegin();//auto it3 = s3.rbegin();while (it3 != s3.rend()){//不能修改//*it3 += 3;cout << *it3 << " ";++it3;}cout << endl;
}int main()
{test_string5();return 0;
}
- 按字典序排序

#include <algorithm>void test_string6()
{string s1("hello world");cout << s1 << endl;//s1按字典序(ASCII码)排序//sort(s1.begin(), s1.end());//第一个和最后一个不参与排序//sort(++s1.begin(), --s1.end());//前5个排序sort(s1.begin(), s1.begin() + 5);cout << s1 << endl;
}int main()
{test_string6();return 0;
}
- 插入字符

void test_string7()
{string s1("hello world");cout << s1 << endl;s1.push_back('x');cout << s1 << endl;s1.append(" yyyyyy!!");cout << s1 << endl;string s2("111111");s1 += 'y';s1 += "zzzzzzzz";s1 += s2;cout << s1 << endl;
}int main()
{test_string7();return 0;
}
注: 在string尾部追加字符时,s.push_back(‘c’) / s.append(1, ‘c’) / s += ‘c’ 三种的实现方式差不多,一般情况下string类的 += 操作用的比较多,+= 操作不仅可以连接单个字符,还可以连接字符串。
- 关于修改的一些接口

void test_string8()
{string s1("hello world");cout << s1 << endl;s1.assign("111111");cout << s1 << endl;//慎用,因为效率不高 -> O(N)//实践中需求也不高string s2("hello world");s2.insert(0, "xxxx");cout << s2 << endl;s2.insert(0, 1, 'y');cout << s2 << endl;s2.insert(s2.begin(), 'y');cout << s2 << endl;s2.insert(s2.begin(), s1.begin(), s1.end());cout << s2 << endl;
}int main()
{test_string8();return 0;
}
void test_string9()
{string s1("hello world");cout << s1 << endl;//erase效率不高,慎用,和insert类似,要挪动数据s1.erase(0, 1);cout << s1 << endl;//s1.erase(5);s1.erase(5, 100);cout << s1 << endl;//replace效率不高,慎用,和insert类似,要挪动数据string s2("hello world");s2.replace(5, 1, "%20");cout << s2 << endl;string s3("hello world hello bit");for (size_t i = 0; i < s3.size(); ){if (' ' == s3[i]){s3.replace(i, 1, "%20");i += 3;}else{i++;}}cout << s3 << endl;string s4("hello world hello bit");string s5;for (auto ch : s4){if (ch != ' '){s5 += ch;}else{s5 += "%20";}}cout << s5 << endl;
}int main()
{test_string9();return 0;
}
我们来做几个题目:
- 仅仅反转字母

class Solution
{
public:bool isLetter(char ch){if (ch >= 'a' && ch <= 'z'){return true;}if (ch >= 'A' && ch <= 'Z'){return true;}return false;}string reverseOnlyLetters(string s){if (s.empty()){return s;}size_t begin = 0, end = s.size() - 1;while (begin < end){while (begin < end && !isLetter(s[begin])){++begin;}while (begin < end && !isLetter(s[end])){--end;}swap(s[begin], s[end]);++begin;--end;}return s;}
};
- 字符串中的第一个唯一字符

class Solution
{
public:int firstUniqChar(string s){int count[26] = { 0 };//统计次数for (auto ch : s){count[ch - 'a']++;}for (size_t i = 0; i < s.size(); ++i){if (1 == count[s[i] - 'a']){return i;}}return -1;}
};
- 验证回文串

class Solution
{
public:bool isLetterOrNumber(char ch){return (ch >= '0' && ch <= '9')|| (ch >= 'a' && ch <= 'z');}bool isPalindrome(string s){for (auto& ch : s){if (ch >= 'A' && ch <= 'Z'){ch += 32;}}int begin = 0, end = s.size() - 1;while (begin < end){while (begin < end && !isLetterOrNumber(s[begin])){++begin;}while (begin < end && !isLetterOrNumber(s[end])){--end;}if (s[begin] != s[end]){return false;}else{++begin;--end;}}return true;}
};
- 字符串相加

法一:
//时间复杂度:O(N^2) 因为头插的效率太低
class Solution
{
public:string addStrings(string num1, string num2){int end1 = num1.size() - 1;int end2 = num2.size() - 1;string str;int next = 0;//进位while (end1 >= 0 || end2 >= 0){int x1 = end1 >= 0 ? num1[end1--] - '0': 0;int x2 = end2 >= 0 ? num2[end2--] - '0': 0;int x = x1 + x2 + next;//处理进位next = x / 10;x = x % 10;//头插//str.insert(0, 1, '0' + x);str.insert(str.begin(), '0' + x);}if (1 == next){str.insert(str.begin(), '1');}return str;}
};
法二:
//时间复杂度:O(N)
class Solution
{
public:string addStrings(string num1, string num2){int end1 = num1.size() - 1;int end2 = num2.size() - 1;string str;int next = 0;//进位while (end1 >= 0 || end2 >= 0){int x1 = end1 >= 0 ? num1[end1--] - '0': 0;int x2 = end2 >= 0 ? num2[end2--] - '0': 0;int x = x1 + x2 + next;//处理进位next = x / 10;x = x % 10;//尾插str += ('0' + x);}if (1 == next){str += '1';}reverse(str.begin(), str.end());return str;}
};
- string类对象的容量操作
void TestPushBack()
{string s;size_t sz = s.capacity();cout << "capacity changed: " << sz << '\n';cout << "making s grow:\n";for (int i = 0; i < 200; ++i){s.push_back('c');if (sz != s.capacity()){sz = s.capacity();cout << "capacity changed: " << sz << '\n';}}
}void test_string10()
{string s1("hello world hello bit");cout << s1.size() << endl;cout << s1.capacity() << endl;cout << s1.max_size() << endl;TestPushBack();string s1("111111111");string s2("11111111111111111111111111111111111111111111111111");
}int main()
{test_string10();return 0;
}

void TestPushBack()
{string s;//知道需要多少空间,提前开好s.reserve(200);size_t sz = s.capacity();cout << "capacity changed: " << sz << '\n';cout << "making s grow:\n";for (int i = 0; i < 200; ++i){s.push_back('c');if (sz != s.capacity()){sz = s.capacity();cout << "capacity changed: " << sz << '\n';}}
}void test_string10()
{ TestPushBack();string s1("111111111");string s2("11111111111111111111111111111111111111111111111111");cout << s1.capacity() << endl;s1.reserve(100);cout << s1.capacity() << endl;s1.reserve(20);cout << s1.capacity() << endl;
}int main()
{test_string10();return 0;
}

void test_string11()
{string s1;//s1.resize(5, '0');s1.resize(5);s1[4] = '3';s1[3] = '4';s1[2] = '5';s1[1] = '6';s1[0] = '7';//76543//插入(空间不够会扩容)string s2("hello world");s2.resize(20, 'x');//删除s2.resize(5);//s2[10];try{s2.at(10);}catch (const exception& e){cout << e.what() << endl;}
}int main()
{test_string11();return 0;
}
注:
- clear()只是将string中有效字符清空,不改变底层空间大小。(代码中没有演示)
- resize(size_t n) 与 resize(size_t n, char c)都是将字符串中有效字符个数改变到n个,不同的是当字符个数增多时:resize(n)用0来填充多出的元素空间,resize(size_t n, char c)用字符c来填充多出的元素空间。注意:resize在改变元素个数时,如果是将元素个数增多,可能会改变底层容量的大小,如果是将元素个数减少,底层空间总大小不变。
- reserve(size_t res_arg=0):为string预留空间,不改变有效元素个数,当reserve的参数小于string的底层空间总大小时,reserver不会改变容量大小。
- 对string操作时,如果能够大概预估到放多少字符,可以先通过reserve把空间预留好。
- string类的一些其他操作
#define _CRT_SECURE_NO_WARNINGS 1void test_string12()
{string file("test.cpp");FILE* fout = fopen(file.c_str(), "r");char ch = fgetc(fout);while (ch != EOF){cout << ch;ch = fgetc(fout);}
}int main()
{test_string12();return 0;
}
void test_string12()
{string file("string.cpp.zip");size_t pos = file.rfind('.');//string suffix = file.substr(pos, file.size() - pos);string suffix = file.substr(pos);cout << suffix << endl;
}int main()
{test_string12();return 0;
}
void test_string12()
{string url("https://gitee.com/ailiangshilove/cpp-class/blob/master/%E8%AF%BE%E4%BB%B6%E4%BB%A3%E7%A0%81/C++%E8%AF%BE%E4%BB%B6V6/string%E7%9A%84%E6%8E%A5%E5%8F%A3%E6%B5%8B%E8%AF%95%E5%8F%8A%E4%BD%BF%E7%94%A8/TestString.cpp");size_t pos1 = url.find(':');string url1 = url.substr(0, pos1 - 0);cout << url1 << endl;size_t pos2 = url.find('/', pos1 + 3);string url2 = url.substr(pos1 + 3, pos2 - (pos1 + 3));cout << url2 << endl;string url3 = url.substr(pos2 + 1);cout << url3 << endl;
}int main()
{test_string12();return 0;
}
void test_string13()
{string str("Please, replace the vowels in this sentence by asterisks.");size_t found = str.find_first_of("aeiou");while (found != string::npos){str[found] = '*';found = str.find_first_of("aeiou", found + 1);}cout << str << '\n';
}int main()
{test_string13();return 0;
}
void SplitFilename(const string& str)
{cout << "Splitting: " << str << '\n';size_t found = str.find_last_of("/\\");cout << " path: " << str.substr(0, found) << '\n';cout << " file: " << str.substr(found + 1) << '\n';
}int main()
{string str1("/usr/bin/man");string str2("c:\\windows\\winhelp.exe");SplitFilename(str1);SplitFilename(str2);return 0;
}
void test_string14()
{string s1 = "hello";string s2 = "world";string ret1 = s1 + s2;cout << ret1 << endl;string ret2 = s1 + "xxxxx";cout << ret2 << endl;string ret3 = "xxxxx" + s1;cout << ret3 << endl;//字典序比较cout << (s1 < s2) << endl;
}int main()
{test_string14();return 0;
}
一个题目:
- 字符串最后一个单词的长度

#include <iostream>
using namespace std;int main()
{string str;//默认规定空格或者换行是多个值之间分割//cin >> str;//获取一行中包含空格,不能用>>getline(cin, str);size_t pos = str.rfind(' ');cout << str.size() - (pos + 1) << endl;return 0;
}
- 输入多行字符依次打印:
int main()
{//默认规定空格或者换行是多个值之间分割string str;//ctrl + z 就可以结束while (cin >> str){cout << str << endl;}return 0;
}
- 字符串转整形,整形转字符串
int main()
{//atoi itoa//to_stringint x = 0, y = 0;cin >> x >> y;string str = to_string(x + y);cout << str << endl;int z = stoi(str);return 0;
}
相关文章:
string类详解(上)
文章目录 目录1. STL简介1.1 什么是STL1.2 STL的版本1.3 STL的六大组件 2. 为什么学习string类3. 标准库中的string类3.1 string类3.2 string类的常用接口说明 目录 STL简介为什么学习string类标准库中的string类string类的模拟实现现代版写法的String类写时拷贝 1. STL简介 …...
DeepSeek教unity------Dotween
1、命名法 Tweener(补间器):一种控制某个值并对其进行动画处理的补间。 Sequence(序列):一种特殊的补间,它不直接控制某个值,而是控制其他补间并将它们作为一个组进行动画处理。 Tw…...
AIP-146 泛化域
编号146原文链接AIP-146: Generic fields状态批准创建日期2019-05-28更新日期2019-05-28 API中的大多数域,无论是在请求、资源还是自定义应答中,都有具体的类型或模式。这个模式是约定的一部分,开发者依此约定进行编码。 然而,偶…...
【Go并发编程】Goroutine 调度器揭秘:从 GMP 模型到 Work Stealing 算法
每天一篇Go语言干货,从核心到百万并发实战,快来关注魔法小匠,一起探索Go语言的无限可能! 在 Go 语言中,Goroutine 是一种轻量级的并发执行单元,它使得并发编程变得简单高效。而 Goroutine 的高效调度机制是…...
【前端】Vue组件库之Element: 一个现代化的 UI 组件库
文章目录 前言一、官网1、官网主页2、设计原则3、导航4、组件 二、核心功能:开箱即用的组件生态1、丰富的组件体系2、特色功能亮点 三、快速上手:三步开启组件化开发1、安装(使用Vue 3)2、全局引入3、按需导入(推荐&am…...
第十五天 学习并实践HarmonyOS应用的基本结构、页面导航和状态管理
HarmonyOS应用开发入门:从基本结构到状态管理实战指南 前言 (约300字,说明HarmonyOS的发展前景,应用开发的市场需求,以及本教程的核心价值。强调手把手教学特点,降低学习门槛) 一、HarmonyOS应…...
Cursor生成JAVA相关的关键词提示规则
在项目根目录创建一个.curstorrules文件(注意有个小数点),之后在该文件内填入下面内容 你是 Java 编程、Spring Boot、Spring Framework、Maven、JUnit 及相关 Java 技术的专家。 代码风格与结构 编写整洁、高效且文档完善的 Java 代码&am…...
数据结构:队列(Queue)及其实现
队列(Queue)是一种广泛使用的线性数据结构,它遵循先进先出(FIFO,First In, First Out)的原则。也就是说,最早插入队列的元素会最先被移除。队列是一种典型的顺序存取结构,它与栈&…...
MoE架构中的专家选择门控机制:稀疏激活如何实现百倍效率突破?
技术原理(数学公式与核心逻辑) 核心公式 门控网络输出: G ( x ) Softmax ( W g ⋅ x b g ) G(x) \text{Softmax}(W_g \cdot x b_g) G(x)Softmax(Wg⋅xbg) 最终输出: y ∑ i 1 n G i ( x ) ⋅ E i ( x ) (仅保留Top-…...
坐井说天阔---DeepSeek-R1
前言 DeepSeek-R1这么火,虽然网上很多介绍和解读,但听人家的总不如自己去看看原论文。于是花了大概一周的时间,下班后有进入了研究生的状态---读论文。 DeepSeek这次的目标是探索在没有任何监督数据的情况下训练具有推理能力的大模型&#…...
UART(一)——UART基础
一、定义 UART(Universal Asynchronous Receiver/Transmitter)是一种广泛使用的串行通信协议,用于在设备间通过异步方式传输数据。它无需共享时钟信号,而是依赖双方预先约定的参数(如波特率)完成通信。 功能和特点 基本的 UART 系统只需三个信号即可提供稳健的中速全双工…...
DeepSeek 的创新融合:多行业应用实践探索
引言 在数字化转型的浪潮中,技术的融合与创新成为推动各行业发展的关键力量。蓝耘平台作为行业内备受瞩目的创新平台,以其强大的资源整合能力和灵活的架构,为企业提供了高效的服务支持。而 DeepSeek 凭借先进的人工智能技术,在自然…...
C语言中的常量与只读变量,#define与const的区别
#include中的#表明C处理器需要在编译器接手工作之前先处理这条指令。 #define 这条定义宏的语句,是不是很熟悉,这条预处理指令会在编译器编译前把源文件中使用到这个宏的地方都先展开。 #define NUM 12 这个定义了一个宏常量,它的处理发生编…...
Python常见面试题的详解6
1. 按字典 value 值排序 要点:对于给定字典,使用 sorted() 函数结合 items() 方法,依据 value 进行排序,也可以定义一个通用函数,支持按 value 升序或降序排序。示例: python d {a: 1, b: 2, c: 3, d: …...
CentOS 7超详细安装教程(含镜像)
1. 安装前准备 1.1 CentOS简介 CentOS(Community Enterprise Operating System,中文意思是:社区企业操作系统)是一种基于 Red Hat Enterprise Linux(RHEL)源代码构建的免费开源操作系统。它在稳定性、安全…...
代码随想录day12
144.二叉树的前序遍历 //明确递归的函数,结束边界,单层逻辑 void traversal(TreeNode* node, vector<int>& list){if(node nullptr){return;}list.push_back(node->val);traversal(node->left, list);traversal(node->right, list)…...
langchain学习笔记之消息存储在内存中的实现方法
langchain学习笔记之消息存储在内存中的实现方法 引言背景消息存储在内存的实现方法消息完整存储:完整代码 引言 本节将介绍 langchain \text{langchain} langchain将历史消息存储在内存中的实现方法。 背景 在与大模型交互过程中,经常出现消息管理方…...
布隆过滤器(简单介绍)
布隆过滤器(Bloom Filter) 是一种高效的概率型数据结构,用于快速判断一个元素是否可能存在于某个集合中。它的核心特点是空间效率极高,但存在一定的误判率(可能误报存在,但不会漏报)。 核心原理…...
Qt中基于开源库QRencode生成二维码(附工程源码链接)
目录 1.QRencode简介 2.编译qrencode 3.在Qt中直接使用QRencode源码 3.1.添加源码 3.2.用字符串生成二维码 3.3.用二进制数据生成二维码 3.4.界面设计 3.5.效果展示 4.注意事项 5.源码下载 1.QRencode简介 QRencode是一个开源的库,专门用于生成二维码&…...
SpringBoot教程(三十二) SpringBoot集成Skywalking链路跟踪
SpringBoot教程(三十二) | SpringBoot集成Skywalking链路跟踪 一、Skywalking是什么?二、Skywalking与JDK版本的对应关系三、Skywalking下载四、Skywalking 数据存储五、Skywalking 的启动六、部署探针 前提: Agents 8.9.0 放入 …...
IntelliJ IDEA 接入 AI 编程助手(Copilot、DeepSeek、GPT-4o Mini)
IntelliJ IDEA 接入 AI 编程助手(Copilot、DeepSeek、GPT-4o Mini) 📊 引言 近年来,AI 编程助手已成为开发者的高效工具,它们可以加速代码编写、优化代码结构,并提供智能提示。本文介绍如何在 IntelliJ I…...
【机器学习】深入浅出KNN算法:原理解析与实践案例分享
在机器学习中,K-最近邻算法(K-Nearest Neighbors, KNN)是一种既直观又实用的算法。它既可以用于分类,也可以用于回归任务。本文将简单介绍KNN算法的基本原理、优缺点以及常见应用场景,并通过一个简单案例帮助大家快速入…...
vscode的一些实用操作
1. 焦点切换(比如主要用到使用快捷键在编辑区和终端区进行切换操作) 2. 跳转行号 使用ctrl g,然后输入指定的文件内容,即可跳转到相应位置。 使用ctrl p,然后输入指定的行号,回车即可跳转到相应行号位置。...
JavaEE基础 Tomcat与Http (下)
目录 1.HTTP 协议 1.1 HTTP 协议概念 1.2. 无状态协议 1.3. HTTP1.0 和 HTTP1.1 1.4 请求协议和响应协议 编辑 1.5 请求协议 1.5.1 常见的请求协议 1.5.2 GET 请求 1.5.3 POST请求 1.5.4 响应协议 1.HTTP 协议 Http浏览器访问东西都是遵循的Http协议。 1.1 HTTP 协议…...
【Linux】【进程】epoll内核实现总结+ET和LT模式内核实现方式
【Linux】【网络】epoll内核实现总结ET和LT模式内核实现方式 1.epoll的工作原理 eventpoll结构 当某一进程调用epoll_create方法时,Linux内核会创建一个eventpoll结构体,这个结构体中有两个成员与epoll的使用方式密切相关. struct eventpoll{..../*红…...
英码科技基于昇腾算力实现DeepSeek离线部署
DeepSeek-R1 模型以其创新架构和高效能技术迅速成为行业焦点。如果能够在边缘进行离线部署,不仅能发挥DeepSeek大模型的效果,还能确保数据处理的安全性和可控性。 英码科技作为AI算力产品和AI应用解决方案服务商,积极响应市场需求࿰…...
测试常见问题汇总-检查表(持续完善)
WEB页面常见的问题 按钮功能的实现:返回按钮是否可以正常返回 信息保存提交后,系统是否给出“成功”的提示信息,列表数据是否自动刷新 没有勾选任何记录直接点【删除】,是否给出“请先选择记录”的提示 删除是否有删除确认框 …...
【SQL】SQL约束
🎄约束 📢作用:是用于限制存储再表中的数据。可以再创建表/修改表时添加约束。 📢目的:保证数据库中数据的正确、有效性和完整性。 📢对于一个字段可以同时添加多个约束。 🎄常用约束: 约束分类 约束 描述关键字非…...
解决 `pip is configured with locations that require TLS/SSL` 错误
问题描述 在使用 pip 安装 Python 包时,可能会遇到以下错误: WARNING: pip is configured with locations that require TLS/SSL, however the ssl module in Python is not available.这意味着 Python 的 ssl 模块未正确安装或配置,导致 p…...
如何commit后更新.gitignore实现push
目录 步骤 1: 更新 .gitignore 文件 步骤 2: 移除已追踪的大文件 步骤 3: 提交更改 步骤 4: 尝试推送 注意事项 如果已经执行了git commit,但后来意识到需要更新.gitignore文件以排除某些不应该被追踪的大文件或目录,并希望在不丢失现有提交记录的情…...
