【C++】string模拟
string讲解:【C++】String类-CSDN博客
基本框架
#pragma once
#include <iostream>
using namespace std;
namespace wzf
{class string{public:// 默认构造函数string(): _str(new char[1]), _size(0), _capacity(0){_str[0] = '\0'; // 在没有内容时仍要有终止符'\0'}
// 构造函数,接收一个 C 风格字符串// 注意:假设传入的字符串以终止符'\0'结尾,否则可能导致程序崩溃string(const char *str): _size(strlen(str)){_capacity = _size;//new 一个capacity+1的空间_str = new char[_capacity + 1]; // +1 是为了容纳终止符'\0'strcpy(_str, str);//拷贝}
/*td::string 类型使用内部管理字符串的长度,并且在内部存储中维护了字符串的长度信息,不需要依赖 null 字符来表示字符串的结束,而在 C 语言中,字符串是作为 null 结尾的字符数组进行存储的,每个字符串最后都以一个值为 0 的字符 ‘\0’ 结尾
*/// 返回字符串的 C 风格表示const char *c_str(){return _str;}//返回字符串长度size_t size() const{return _size;}size_t capcacity() const{return _capacity;}
private:char *_str; // 存储字符串的字符数组指针size_t _size; // 字符串的长度(不包括终止符'\0')size_t _capacity; // 字符数组的容量};
}
将string()与string(const)进行复用:
string(const char *str=nulptr);//❌
string应该是遇到'\0'停止否则会崩
string(const char* str='\0');//❌
默认参数值是 '\0',即空字符。
然而,由于 str 是 const char* 类型,而不是 char 类型,因此在这种情况下,'\0' 被解释为一个整数 0,
而不是一个空字符。这可能导致编译错误或未定义行为。
string(const char *str="\0")// ≠‘\0’
一个空字符串也是一个有效的字符串,它不需要以 '\0' 的形式进行显式表示,也就是说,一个空字符串已经包含了一个空字符。
因此,当我们在下面的类构造函数中将空字符串 "" 传递给 const char* 类型的形参 str 时 , 编译器会自动将其转换为一个空字符 '\0'。->
string(const char *str = "") // 可以不写 "\0": _size(strlen(str))
{_capacity = _size== 0 ? 3 : _size;_str = new char[_capacity + 1]; //+1-> '\0'strcpy(_str, str);
}
成员函数重载 operator[]
对[ ]进行重载,以便直接用[]进行调用
//给const对象调用
const char &operator[](size_t pos) const
{assert(pos < _size);return _str[pos];
}
//给普通对象,构成函数重载
char &operator[](size_t pos)
{assert(pos < _size);return _str[pos];
}
对此处const使用有疑问的可转看改文章,文章中详细讲解了const在类中的用法: 【C++】const与类(const修饰函数的三种位置)-CSDN博客
成员函数重载 operator=
//string s3=s1
string &operator=(const string &s) // string& 为返回类型,表示返回值是当前实例的引用
{if (this != &s) //s1≠s1 避免自我赋值{char *tmp = new char[s._capacity + 1]; // 申请新的字符数组strcpy(tmp, s._str); // 复制待赋值字符串// 释放原来的空间,销毁原来空间,防止s1空间小于s2,或s1>s2造成空间浪费,避免内存泄漏和空间浪费 delete[] _str; _str = tmp; // 更新字符串指针_size = s._size; // 更新字符串长度_capacity = s._capacity; // 更新字符串容量}return *this; // 返回当前实例的引用
}
测试:
void test_string2()
{string s1;string s2("Hello Word");/*string s3(s2); // 拷贝构造(浅拷贝/值拷贝) 用系统自动生成的拷贝构造1.两个用的是同一个空间. 2.会析构两次*/// 深拷贝:string s3(s2);
cout << s2.c_str() << endl;cout << s3.c_str() << endl;s2[0]++;cout << s2.c_str() << endl;cout << s3.c_str() << endl;cout << "===" << endl;
s1 = s3; // 调用 s1 的 operator= 函数,将 s2 赋值给 s1cout << s3.c_str() << endl;cout << s1.c_str() << endl;
}
拷贝构造:
深浅拷贝的区别:
浅拷贝是指在进行复制操作时,只复制对象的引用或指针,而不复制对象本身。这意味着原对象和拷贝对象共享同一份数据,当其中一个对象修改了数据时,另一个对象也会受到影响。
深拷贝是指在进行复制操作时,完全复制对象和对象的数据,创建一个新的对象并复制数据。这意味着原对象和拷贝对象拥有各自独立的数据,彼此之间互不影响。
// 深拷贝 s3
string(const string &s): _size(s._size), _capacity(s._capacity)
{_str = new char[s._capacity + 1];strcpy(_str, s._str);
}
测试:
void test_string1()
{string s1;string s2("HelloWord");
cout << s1.c_str() << endl;cout << s2.c_str() << endl;
s2[0]++;cout << s1.c_str() << endl;cout << s2.c_str() << endl;
}
迭代器
begin() && end()
typedef char* iterator; // 定义了名为 iterator 的 char* 类型别名
typedef const char* const_iterator; // 定义了名为 const_iterator 的 const char* 类型别名
iterator begin() // 返回指向首字符的迭代器
{return _str;
}
iterator end() // 返回指向尾字符(终止符)后面的迭代器
{return _str + _size;
}
const_iterator rbegin() const // 返回指向尾字符(终止符)的迭代器
{return _str;
}
const_iterator rend() const // 返回指向首字符前面位置的迭代器
{return _str + _size;
}
调用:
string::iterator it=s1.begin();
while (it!=s1.end())
{cout<<*it<<" ";++it;
}
cout<<endl;
const_iterator rit = s.begin();
while (rit != s.end())
{cout << *rit << " ";++rit;
}
运算符重载
字符串比较的是相对应字符相应的asscall值
// 不改变数据的都建议加上const
bool operator>(const string &s) const
{return strcmp(_str, s._str) > 0;
}
bool operator==(const string &s) const
{return strcmp(_str, s._str) == 0;
}
bool operator>=(const string &s) const
{return *this > s || *this == s;
}
bool operator<(const string &s) const
{return !(*this >= s);
}
bool operator<=(const string &s) const
{return !(*this > s);
}
bool operator!=(const string &s) const
{return !(*this == s);
}
测试:
string s1("Hello Word");
string s2("Hello Word");
string s3("Iello Word");
cout<<(s1==s2)<<endl;//1
cout<<(s1>=s3)<<endl;//0
cout<<(s1<=s3)<<endl;//1
cout<<(s1!=s3)<<endl;//1
+= :
string &operator+=(char ch)
{push_back(ch);return *this;
}
string &operator+=(const char *str)
{append(str);return *this;
}
测试:
string s2("HelloWord");
s2 += ' ';
s2 += "xxxxxxxxxx";
cout << s2.c_str() << endl;
遍历string
-
用下标的方式遍历
void _Print(const string &s)
{for (size_t i = 0; i < s.size(); i++){cout << s[i] << " ";}cout << endl;
}
调用:
_print(s1);
-
用迭代器
string::iterator it = s1.begin();
while (it != s1.end())
{cout << *it << " ";++it;
}
cout << endl;
string类对象的修改操作
reserve 开空间
void reserve(size_t n)
{if (n > _capacity){char *tmp = new char[n + 1]; //+1是为了存放"\0"strcpy(tmp, _str); // 拷贝delete[] _str; // 销毁_str空间_str = tmp;_capacity = n;}
}
push_back 头插
void push_back(char ch)
{if (_size + 1 > _capacity){reserve(_capacity * 2);}_str[_size] = ch; // 将字符插入++_size;_str[_size] = '\0';
}
append 头插
void append(char *str)
{size_t len = strlen(str); // 计算要插入字符的长度
if (_size + len > _capacity){reserve(_size + len);}
strcpy(_str + _size, str); // _str 指针所指向的内存块中找到要插入字符串的位置(+_size)_size += len;
}
insert 任意位置插入
// 任意位置插入 //string& 可用于获取对象
string &insert(size_t pos, char ch)//与void &insert(size_t pos, char ch)效果差不多,
{assert(pos <= _size);if (_size + 1 > _capacity){reserve(2 * _capacity);}size_t end = _size + 1; // 防止size_t end=-1->整形最大值while (end > pos){_str[end] = _str[end - 1];--end;}_str[pos] = ch;++_size;return *this;
}
string &insert(size_t pos, const char *str)
{assert(pos <= _size);size_t len = strlen(str);
if (_size + len > _capacity){reserve(_size + len);}
// 挪动数据
// 方法一size_t end = _size + len;while (end > pos + len - 1){_str[end - len] = _str[end];--end;}/*//方法二size_t n=_size+1;size_t end=_size;for (size_t i = 0; i < n; ++i){_str[end+len]=_str[end];--end;}*/// 拷贝插入strncpy(_str + pos, str, end);_size += len;
return *this;
}
push_back复用insert
void push_back(char ch)
{insert(_size,ch);
}
append复用insert
void append(const char *str)
{insert(_size,str);
}
erase删除
在private出定义静态变量 npos
static size_t npos;
类外进行赋值:
size_t string::npos = -1;
或者是直接在private里定义:
static const size_t npos=-1;//该语法只支持整形
// 任意位置删除
string &erase(size_t pos, size_t len = npos)
{ assert(pos<_size);
if (len == npos || pos + len >= _size){_str[pos] = '\0';_size = pos;}else{strcpy(_str + pos, _str + pos + len);_size -= len;}return *this;
}
resize缩容
void resize(size_t n, char ch = '\0')
{if (n < _size) // 当 n 小于当前字符串长度时,删除多余的字符,即保留前 n 个字符{_size = n;_str[_size] = '\0'; // 更新字符串结束符}else if (n > _size) //当 n 大于当前字符串长度时,根据情况填充待求个字符,直到字符串长度为 n 为止{if (n > _capacity) // 如果需要的容量超出已分配的容量,则进行扩容操作{reserve(n);}
size_t i = _size;while (i < n) // 将新插入的字符填充到字符串中,直到字符串长度为 n 为止{_str[i] = ch;++i;}
_size = n; // 更新字符串长度_str[_size] = '\0'; // 更新字符串结束符}
}
find 查找
// 在字符串中查找字符 ch,从 pos 位置开始查找
// 如果找到,返回该字符在字符串中的下标
// 如果没找到,返回 npos
size_t find(char ch, size_t pos = 0)
{assert(pos < _size); // 断言:pos 不能大于字符串长度
for (size_t i = pos; i < _size; ++i) // 从 pos 位置开始查找{if (_str[i] == ch) // 如果找到字符 ch,返回该字符在字符串中的下标{return i;}}
return npos; // 没找到,返回 npos
}
// 在字符串中查找字符串 str,从 pos 位置开始查找
// 如果找到,返回该字符串在原字符串中的第一个字符的下标
// 如果没找到,返回 npos
size_t find(const char* str, size_t pos = 0)
{assert(pos < _size); // 断言:pos 不能大于字符串长度
char* p = strstr(_str + pos, str); // 在字符串中查找字符串 str,并返回第一次出现该字符串的指针if (p == nullptr) // 如果没找到,返回 npos{return npos;}else // 找到,则返回该字符串在原字符串中的第一个字符的下标{return p - _str;}
}
clear清除
void clear()
{_str[0] = '\0';_size = 0;
}
swap交换
void swap(string &s)
{std::swap(_str, s._str);std::swap(_capacity, s._capacity);std::swap(_size, s._size);
}
流
流插入
// 流插入
ostream &operator<<(ostream &out, const string &s)
{for (size_t i = 0; i < s.size(); ++i){out << s[i];}return out;
}
流提取
istream &operator>>(istream &in, string &s)
{s.clear();char ch = in.get(); // 获取一个字符char buff[128];size_t i = 0;
while (ch != ' ' && ch != '\n'){buff[i++] = ch;if (i == 127) // 若已存满{buff[127] = '\0'; // 在末尾添加字符串结束符s += buff; // 添加到输出字符串i = 0; // 重置计数器,从buff[0]开始}
ch = in.get(); // 读入下一个字符}
if (i != 0) // 防止循环结束还有数据没有增加到buff中{buff[i] = '\0'; // 在末尾添加字符串结束符s += buff; // 添加到输出字符串}
return in;
}
测试:
string s1("0123456789");
cout << s1.c_str() << endl;
cout << s1 << endl;
cin >> s1;
cout << s1 << endl;
示例代码:
string.cpp
#include "string.h"
int main()
{try // char* tmp = new char[s._capacity + 1];是否开辟异常{wzf::test_string9();}catch (const std::exception &e){std::cerr << e.what() << '\n';}
return 0;
}
string.h
#pragma once
#include <iostream>
#include <assert.h>
using namespace std;
namespace wzf
{class string{public:typedef char *iterator;typedef const char *const_iterator;iterator begin(){return _str;}iterator end(){return _str + _size;}
const_iterator begin() const{return _str;}const_iterator end() const{return _str + _size;}
string(const char *str = "") // 可以不写 "\0": _size(strlen(str)){_capacity = _size == 0 ? 3 : _size;_str = new char[_capacity + 1]; //+1-> '\0'strcpy(_str, str);}
// 深拷贝 s3string(const string &s): _size(s._size), _capacity(s._capacity){_str = new char[s._capacity + 1];strcpy(_str, s._str);}
// 赋值重载string &operator=(const string &s) // string&为返回类型{if (this != &s) // s1≠s1{char *tmp = new char[s._capacity + 1];strcpy(tmp, s._str);delete[] _str; // 销毁原来空间,防止s1空间小于s2,或s1>s2造成空间浪费_str = tmp;_size = s._size;_capacity = s._capacity;}
return *this; // s1}// 析构~string(){delete[] _str;_str = nullptr;_size = _capacity = 0;}
const char *c_str(){return _str;}
size_t size() const{return _size;}
size_t capcacity() const{return _capacity;}
// 给const对象调用const char &operator[](size_t pos) const{assert(pos < _size);return _str[pos];}// 给普通对象,构成函数重载char &operator[](size_t pos){assert(pos < _size);return _str[pos];}
// 不改变数据的都建议加上constbool operator>(const string &s) const{return strcmp(_str, s._str) > 0;}
bool operator==(const string &s) const{return strcmp(_str, s._str) == 0;}
bool operator>=(const string &s) const{return *this > s || *this == s;}
bool operator<(const string &s) const{return !(*this >= s);}bool operator<=(const string &s) const{return !(*this > s);}
bool operator!=(const string &s) const{return !(*this == s);}
string &operator+=(char ch){push_back(ch);return *this;}
string &operator+=(const char *str){append(str);return *this;}
// 缩容void resize(size_t n, char ch = '\0'){if (n < _size){// 删除数据 -- 保留前n个_size = n;_str[_size] = '\0';}else if (n > _size) // n=_size不处理{if (n > _capacity){reserve(n);}
size_t i = _size;while (i < n) // 从size位置开始填字符{_str[i] = ch;++i;}_size = n;_str[_size] = '\0';}}
// 开空间void reserve(size_t n){if (n > _capacity){char *tmp = new char[n + 1]; //+1是为了存放"\0"strcpy(tmp, _str); // 拷贝delete[] _str; // 销毁_str空间_str = tmp;_capacity = n;}}
void push_back(char ch){// if (_size + 1 > _capacity)// {// reserve(_capacity * 2);// }// _str[_size] = ch; // 将字符插入// ++_size;// _str[_size] = '\0';insert(_size, ch);}
void append(const char *str){// size_t len = strlen(str); // 计算要插入字符的长度
// if (_size + len > _capacity)// {// reserve(_size + len);// }
// strcpy(_str + _size, str); // _str 指针所指向的内存块中找到要插入字符串的位置(+_size)// _size += len;
insert(_size, str);}
// 任意位置插入string &insert(size_t pos, char ch) // 与void &insert(size_t pos, char ch)效果差不多,string& 可用于获取对象{assert(pos <= _size);if (_size + 1 > _capacity){reserve(2 * _capacity);}size_t end = _size + 1; // 防止size_t end=-1->整形最大值while (end > pos){_str[end] = _str[end - 1];--end;}_str[pos] = ch;++_size;return *this;}
string &insert(size_t pos, const char *str){assert(pos <= _size);size_t len = strlen(str);
if (_size + len > _capacity){reserve(_size + len);}
// 挪动数据
// 方法一size_t end = _size + len;while (end > pos + len - 1){_str[end - len] = _str[end];--end;}/*//方法二size_t n=_size+1;size_t end=_size;for (size_t i = 0; i < n; ++i){_str[end+len]=_str[end];--end;}*/// 拷贝插入strncpy(_str + pos, str, end);_size += len;
return *this;}
// 任意位置删除string &erase(size_t pos, size_t len = npos){assert(pos < _size);if (len == npos || pos + len >= _size){_str[pos] = '\0';_size = pos;}else{strcpy(_str + pos, _str + pos + len);_size -= len;}return *this;}
size_t find(char ch, size_t pos = 0){assert(pos < _size);
for (size_t 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);
char *p = strstr(_str + pos, str);if (p == nullptr){return npos;}else{return p - _str;}}
// 交换void swap(string &s){std::swap(_str, s._str);std::swap(_capacity, s._capacity);std::swap(_size, s._size);}
void Print(const string &s){for (size_t i = 0; i < s.size(); i++){cout << s[i] << " ";}cout << endl;
const_iterator rit = s.begin();while (rit != s.end()){cout << *rit << " ";++rit;}}
void clear(){_str[0] = '\0';_size = 0;}
private:char *_str;size_t _size;size_t _capacity;
static size_t npos;};
size_t string::npos = -1;
// 流插入ostream &operator<<(ostream &out, const string &s){for (size_t i = 0; i < s.size(); ++i){out << s[i];}return out;}
// 流提取istream &operator>>(istream &in, string &s){s.clear();char ch = in.get(); // 获取一个字符char buff[128];size_t i = 0;
while (ch != ' ' && ch != '\n'){buff[i++] = ch;if (i == 127) // 若已存满{buff[127] = '\0';s += buff;i = 0; // 再次从buff[0]开始}
ch = in.get();}
if (i != 0) // 防止循环结束还有数据没有进行增加{buff[i] = ch;buff[i + 1] = '\0';s += buff;}
return in;}
void test_string1(){string s1;string s2("HelloWord");
cout << s1.c_str() << endl;cout << s2.c_str() << endl;
s2[0]++;cout << s1.c_str() << endl;cout << s2.c_str() << endl;}void test_string2(){string s1;string s2("Hello Word");/*string s3(s2); // 拷贝构造(浅拷贝/值拷贝) 用系统自动生成的拷贝构造1.两个用的是同一个空间. 2.会析构两次*/// 深拷贝:string s3(s2);
cout << s2.c_str() << endl;cout << s3.c_str() << endl;s2[0]++;cout << s2.c_str() << endl;cout << s3.c_str() << endl;cout << "===" << endl;
s1 = s3; // 调用 s1 的 operator= 函数,将 s2 赋值给 s1cout << s3.c_str() << endl;cout << s1.c_str() << endl;}
void test_string3(){string s1("Hello Word");for (size_t i = 0; i < s1.size(); i++){s1[i]++;}cout << endl;
for (size_t i = 0; i < s1.size(); i++){cout << s1[i] << " ";}cout << endl;
// Print(s1);
string::iterator it = s1.begin();while (it != s1.end()){cout << *it << " ";++it;}cout << endl;}
void test_string4(){string s1("Hello Word");string s2("Hello Word");string s3("Iello Word");
cout << (s1 == s2) << endl;cout << (s1 >= s3) << endl;cout << (s1 <= s3) << endl;cout << (s1 != s3) << endl;}void test_string5(){string s1("HelloWord");s1.push_back(' ');s1.append("*******************");cout << s1.c_str() << endl<< endl;
string s2("HelloWord");s2 += ' ';s2 += "xxxxxxxxxx";
cout << s2.c_str() << endl<< endl;
string s3;s3 += 'a';s3 += 'a';s3 += 'a';cout << s3.c_str() << endl;}void test_string6(){string s1("HelloWord");s1.insert(5, 'x');cout << s1.c_str() << endl;}void test_string7(){string s1;s1.resize(20, 'x');cout << s1.c_str() << endl;
s1.resize(30, 'y');cout << s1.c_str() << endl;
s1.resize(10);cout << s1.c_str() << endl;}void test_string8(){string s1("0123456789");
cout << s1.c_str() << endl;
s1.erase(2, 3);cout << s1.c_str() << endl;
s1.erase(4, 30);cout << s1.c_str() << endl;s1.erase(2);cout << s1.c_str() << endl;}void test_string9(){string s1("0123456789");cout << s1.c_str() << endl;cout << s1 << endl;
cin >> s1;cout << s1 << endl;}
}
感谢收看,创作不易,喜欢的话留下一个免费的赞吧🥰
相关文章:

【C++】string模拟
string讲解:【C】String类-CSDN博客 基本框架 #pragma once #include <iostream> using namespace std; namespace wzf {class string{public:// 默认构造函数string(): _str(new char[1]), _size(0), _capacity(0){_str[0] \0; // 在没有内容时仍要有终…...

python高级练习题库实验1(A)部分
文章目录 题目1代码实验结果题目2代码实验结果题目3代码实验结果题目4代码实验结果题目总结题目1 输入一个整数,用于控制输出*的个数,输入日期,按照特定格式输出 研究下面的例子,并编写一个与这些例子完全相同的程序。 代码 import datetime# ask user for length of b…...

数据库应用:MongoDB 数据备份与恢复
目录 一、实验 1.MongoDB 数据库备份与恢复 2.MongoDB 数据表备份与恢复 二、问题 1.MongoDB有哪些命令行工具实现数据备份与恢复 一、实验 1.MongoDB 数据库备份与恢复 (1)查看版本 rootnode1:~# mongo --version(2)准备…...

MySQL-函数
一、统计函数 CREATE TABLE student (id INT NOT NULL DEFAULT 1,name varchar(20) not null default ,chinese float not null default 0.0,english float not null default 0.0,math float not null default 0.0 );insert into student values (1,曹操,77,89,85);insert int…...
【12】Python函数专题(下)
文章目录 1. 高阶函数1.1 以函数为参数1.2 以函数为返回值1.3 以函数为 参数和返回值2. 闭包3. 装饰器3.1 装饰器的引入3.2. 装饰器的使用3.3 装饰器强化练习🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔…...

国标GB28181协议/RTSP视频监控汇聚平台EasyCVR(V.3.4)页面UI大更新
为提高用户体验,增强平台功能,旭帆科技的Easy系列平台也在不断优化更新中。在最新的EasyCVR(V.3.4)中,其最显著的区别即为首页UI的调整。 其亮点是在【配置中心】-【基础配置】-【展示信息】中,首页UI可分…...

生成式AI与预测式AI的主要区别与实际应用
近年来,预测式人工智能(Predictive AI)通过先进的推荐算法、风险评估模型、以及欺诈检测工具,一直在推高着该领域公司的投资回报率。然而,今年初突然杀出的生成式人工智能(Generative AI)突然成…...

【JavaEE】多线程 -- 死锁问题
目录 1. 问题引入 2.死锁问题的概念和原因 3. 解决死锁问题 1. 问题引入 在学习死锁之前, 我们先观察下面的代码能否输出正确的结果: 运行程序, 能正常输出结果: 这个代码只管上看起来, 好像是有锁冲突的, 此时的 locker 对象已经是加锁的状态, 在尝试对 locker 加锁, 不应该…...

XTU OJ 1339 Interprime 学习笔记
链接 传送门 代码 #include<bits/stdc.h> using namespace std;const int N1e610; //78498 我计算了一下,6个0的范围内有这么多个素数,所以开这么大的数组存素数 //计算的代码是一个循环 int prime[80000]; int a[N],s[N];//s数组是前缀和数组b…...
【Web安全】xss攻击方式与绕过
xss攻击方式与绕过 文章目录 xss攻击方式与绕过XSS攻击方式1. script标签2. img标签3. input标签4. details标签5. svg标签6. select标签7. iframe标签8. video标签9. audio标签10. body标签11. textarea标签 常见绕过方式1. 空格过滤2. 引号过滤3. 括号过滤4. 关键词过滤5. 编…...

文件夹重命名技巧:用关键词替换文件夹名称指定内容的右侧文字
在日常生活中,经常要管理大量的文件夹,这时候掌握一些文件夹重命名的技巧就非常实用。例如文件夹重命名时,经常要将一些通用的文字替换成其他关键词,以便更好地标识和分类文件夹。而用关键词替换文件夹名称指定内容的右侧文字&…...

python pip安装第三方包时报错 error: Microsoft Visual C++ 14.0 or greater is required.
文章目录 1.问题2.原因3.解决办法 1.问题 pip install 的时候报错一大堆,其中有这么一段话 👇 error: Microsoft Visual C 14.0 or greater is required. Get it with "Microsoft C Build Tools": https://visualstudio.microsoft.com/visua…...

对 .NET程序2G虚拟地址紧张崩溃 的最后一次反思
一:背景 1. 讲故事 最近接连遇到了几起 2G 虚拟地址紧张 导致的程序崩溃,基本上 90% 都集中在医疗行业,真的很无语,他们用的都是一些上古的 XP,Windows7 x86,我也知道技术人很难也基本无法推动硬件系统和…...

HCIA-RS基础-静态路由协议
摘要:静态路由是一种在网络中广泛应用的路由选择方案,它以其简单的配置和低开销而备受青睐。本文将介绍静态路由的配置方法、默认路由的设置、路由的负载分担和备份策略。通过学习本文,希望可以你能够掌握静态路由的基本概念和在华为模拟器中…...

LeetCode(46)汇总区间【区间】【简单】
目录 1.题目2.答案3.提交结果截图 链接: 汇总区间 1.题目 给定一个 无重复元素 的 有序 整数数组 nums 。 返回 恰好覆盖数组中所有数字 的 最小有序 区间范围列表 。也就是说,nums 的每个元素都恰好被某个区间范围所覆盖,并且不存在属于某…...

数据预处理:随机裁剪放缩
随机裁剪放缩是一种数据增强技术,可以在训练神经网络时增加数据的多样性,提高模型的泛化能力。具体来说,随机裁剪放缩可以通过随机裁剪和缩放原始图片来生成多个不同的训练样本,从而增加数据集的大小和多样性。这种技术在图像分类…...

RabbitMQ 搭建和工作模式
MQ基本概念 1. MQ概述 MQ全称 Message Queue([kjuː])(消息队列),是在消息的传输过程中保存消息的容器。多用于分布式系统之间进行通信。 (队列是一种容器,用于存放数据的都是容器࿰…...

一起学docker系列之七docker容器卷技术
目录 1 为什么使用容器数据卷?2 数据卷的特点和优势3 使用数据卷的方法3.1 创建容器并挂载数据卷3.2 容器间数据卷的共享与继承 4 数据卷的权限设置5 注意事项5.1 解决权限问题5.2 路径自动创建 结语 对于容器化应用程序的数据管理和持久化,Docker 数据卷…...

Loki安装部署
Loki安装部署 1、Loki介绍 Loki 是受 Prometheus 启发由 Grafana Labs 团队开源的水平可扩展,高度可用的多租户日志聚合系统。开发语 言: Google Go。它的设计具有很高的成本效益,并且易于操作。使用标签来作为索引,而不是对全文进行检索&…...
php如何实现文件上传
php实现文件上传需要通过全局变量(数组):$_FILES 结合 move_uploaded_file 函数来实现。 move_uploaded_file函数(只对POST方式生效): 其中move_uploaded_file函数语法:move_uploaded_file(需要…...

Flask RESTful 示例
目录 1. 环境准备2. 安装依赖3. 修改main.py4. 运行应用5. API使用示例获取所有任务获取单个任务创建新任务更新任务删除任务 中文乱码问题: 下面创建一个简单的Flask RESTful API示例。首先,我们需要创建环境,安装必要的依赖,然后…...

为什么需要建设工程项目管理?工程项目管理有哪些亮点功能?
在建筑行业,项目管理的重要性不言而喻。随着工程规模的扩大、技术复杂度的提升,传统的管理模式已经难以满足现代工程的需求。过去,许多企业依赖手工记录、口头沟通和分散的信息管理,导致效率低下、成本失控、风险频发。例如&#…...

STM32标准库-DMA直接存储器存取
文章目录 一、DMA1.1简介1.2存储器映像1.3DMA框图1.4DMA基本结构1.5DMA请求1.6数据宽度与对齐1.7数据转运DMA1.8ADC扫描模式DMA 二、数据转运DMA2.1接线图2.2代码2.3相关API 一、DMA 1.1简介 DMA(Direct Memory Access)直接存储器存取 DMA可以提供外设…...
Matlab | matlab常用命令总结
常用命令 一、 基础操作与环境二、 矩阵与数组操作(核心)三、 绘图与可视化四、 编程与控制流五、 符号计算 (Symbolic Math Toolbox)六、 文件与数据 I/O七、 常用函数类别重要提示这是一份 MATLAB 常用命令和功能的总结,涵盖了基础操作、矩阵运算、绘图、编程和文件处理等…...

Ascend NPU上适配Step-Audio模型
1 概述 1.1 简述 Step-Audio 是业界首个集语音理解与生成控制一体化的产品级开源实时语音对话系统,支持多语言对话(如 中文,英文,日语),语音情感(如 开心,悲伤)&#x…...
在鸿蒙HarmonyOS 5中使用DevEco Studio实现录音机应用
1. 项目配置与权限设置 1.1 配置module.json5 {"module": {"requestPermissions": [{"name": "ohos.permission.MICROPHONE","reason": "录音需要麦克风权限"},{"name": "ohos.permission.WRITE…...

多种风格导航菜单 HTML 实现(附源码)
下面我将为您展示 6 种不同风格的导航菜单实现,每种都包含完整 HTML、CSS 和 JavaScript 代码。 1. 简约水平导航栏 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport&qu…...
Python ROS2【机器人中间件框架】 简介
销量过万TEEIS德国护膝夏天用薄款 优惠券冠生园 百花蜂蜜428g 挤压瓶纯蜂蜜巨奇严选 鞋子除臭剂360ml 多芬身体磨砂膏280g健70%-75%酒精消毒棉片湿巾1418cm 80片/袋3袋大包清洁食品用消毒 优惠券AIMORNY52朵红玫瑰永生香皂花同城配送非鲜花七夕情人节生日礼物送女友 热卖妙洁棉…...

使用Spring AI和MCP协议构建图片搜索服务
目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式(本地调用) SSE模式(远程调用) 4. 注册工具提…...
SQL慢可能是触发了ring buffer
简介 最近在进行 postgresql 性能排查的时候,发现 PG 在某一个时间并行执行的 SQL 变得特别慢。最后通过监控监观察到并行发起得时间 buffers_alloc 就急速上升,且低水位伴随在整个慢 SQL,一直是 buferIO 的等待事件,此时也没有其他会话的争抢。SQL 虽然不是高效 SQL ,但…...