C++ —— string类(上)
目录
string的介绍
string类功能的使用介绍
constructor —— 构造
介绍使用(1)(2)(4) :构造、拷贝构造、带参构造
介绍(3):拷贝string类对象的一部分字符,从pos位置开始,拷贝len个字符
npos
介绍(5):取字符串的前n个字符拷贝
介绍(6) :连续n个C字符初始化
介绍(7):用迭代器区间构造
destructor —— 析构
operator= —— 赋值重载
string类对象的容量操作
size() length() max_size()
capacity()
reserve() 和 resize()
clear()
empty()
遍历及访问string所需的一些接口
operator[] —— []运算符重载
iterator —— 迭代器 (正向)
begin()
end()
reverse_iterator —— 反向迭代器
rbegin和rend
const修饰的迭代器
范围for
auto
typeid().name()
string的介绍
string严格来说是属于C++标准库的,不是属于STL(标准模板库)。
STL:
我们看到里面其实是没有string的,string产生的比STL较早的,在头文件中,会单独看到一个string的头文件。C++文档
所谓的string其实就是一个字符串 ,它要解决的就是要管理字符串。(日常当中字符串是很多的,如:身份证号码,家庭地址,电话号码等等)
打开string头文件可以看到:
有4种,这个与所谓的编码有关系,这里我们先看string:
由于编码的原因,string是typedef出来的,它的原生类型是:
//原生类型
basic_string<char>
除了char,还有其他字符的类型(编码的原因)
//原生类型
basic_string<char16_t>
//原生类型
basic_string<char32_t>basic_string<wchar_t>
注意:basic_string其实是一个模板,所以string底层还是一个模板。
所以,string是一个管理字符串的类。
string的介绍:
总的来说,string是一个对象,是用一个字符的顺序表实现的(也就是字符数组实现的),所以它就是一个字符顺序表(或字符数组),它可以动态的增长。(可以主要兼容UTF-8)
string底层大致成员变量如下:
class string
{
public:/*成员函数(功能接口)*/
private:char* str; //指针指向堆上的空间,这些空间存储对应字符串size_t size; //有效字符个数size_t capacity; //容量
};
下面将介绍string类的常用接口说明。
string类功能的使用介绍
string主要包含接口如下:
我们要使用string类要记得包含一个头文件:
#include <string> //C++//C语言的是
#include<string.h> //注意两者区分
constructor —— 构造
(constructor)函数名称 | 功能说明 |
string() | 构造空的string类对象,即空字符串 |
string(const char* s) | 用C-string来构造string类对象 |
string(size_t n, char c) | string类对象中包含n个字符c |
string(const string&s) | 拷贝构造函数 |
但string构造总的来说是有七种构造方式的:
我们来看C++98版本的,string它有七种构造方式 ,下面来介绍一下:
default (1)
string(); //无参构造(也是默认构造,构造一个空字符串,长度为0个字符)copy (2)
string (const string& str); //拷贝构造substring (3)
string (const string& str, size_t pos, size_t len = npos); //子串构造函数(复制str中,从字符位置pos开始,到len位置字符的部分)from c-string (4)
string (const char* s); //带参构造(用一个常量字符串构造)from sequence (5)
string (const char* s, size_t n); //拷贝前n个字符初始化fill (6)
string (size_t n, char c); //连续n个C的字符去初始化range (7)
template <class InputIterator>
string (InputIterator first, InputIterator last); //迭代器区间初始化
介绍使用(1)(2)(4) :构造、拷贝构造、带参构造
我们先来介绍使用(1)(2)(4):
(string重载了流插入、流提取)
#include<iostream>
#include<string>using namespace std;int main()
{string s1; //默认构造string s2("12345"); //带参构造string s3(s2); //拷贝构造//string也重载了流插入流提取(>>,<<)cout << s1 << endl;cout << s2 << endl;cout << s3 << endl;cin >> s1;cout << s1 << endl;return 0;
}
介绍(3):拷贝string类对象的一部分字符,从pos位置开始,拷贝len个字符
substring (3)
string (const string& str, size_t pos, size_t len = npos); //拷贝构造的一个变形//也就是拷贝一部分字符,从pos位置开始,拷贝len个字符
//接着上面演示的构造代码
int main()
{string s1; //默认构造string s2("1234567"); //带参构造string s3(s2); //拷贝构造//string也重载了流插入流提取(cout,cin)cout << s1 << endl;cout << s2 << endl;cout << s3 << endl;cin >> s1;cout << s1 << endl;string s4(s2, 2, 4); //这里就是让s4去拷贝s2的下标为2的位置开始,拷贝4个字符cout << s4 << endl;return 0;
}
我们观察输出结果,看到从3开始拷贝四个字符到6,3456四个字符就到s4里去了。若此时这里给的字符超过字符串长度,会不会报错呢?
string s2("1234567");
string s4(s2, 2, 15); //让它从pos=2开始拷贝15个字符
我们观察结果,是没有报错的:
文档中:
也就是说string太短了,不够len个字符,它就直到它结束为止(有多少拷贝多少 );这里还说或者为npos也是拷到它的结束。
第三个构造它的len是有缺省值npos的,如果不传第三个参数len,那么它就用这个缺省值,直到拷贝它的结束为止。
string s2("1234567");
string s4(s2, 2);
cout<<s2<<endl;
cout<<s4<<endl;
运行结果:
下面对npos介绍一下
npos
npos是一个string的const静态的成员变量,它可以直接在类里面用,若在外面用的时候,需要指定类域。
npos的值真实的值其实不是-1,在这里-1存的就是补码(-1补码是全1) ,这里又赋值给size_t类型,size_t是unsigned int(无符号整型),-1就会变成整型最大值。
所以这里npos要表达的是:从pos位置取len个字符,如果len给npos,就是要取整型的最大值,
字符串不可能有这么长(字符串中遇到\0会停止),且又给了整型的最大值了,就是要让它拷贝到字符串的结束。
介绍(5):取字符串的前n个字符拷贝
string (const char* s, size_t n); //第(4)个(带参构造)的变形//取字符串的前n个字符拷贝
也就是取一个字符串的前n个字符初始化。
测试一下:
int main()
{string s6("hello world", 5);cout << s6 << endl;return 0;
}
运行结果:
介绍(6) :连续n个C字符初始化
string (size_t n, char c); //n个C字符初始化
也就是连续n个C的字符初始化,例如:'X'就是一个C字符。
int main()
{string s7(10, 'X'); //用10个X字符初始化cout << s7 << endl;return 0;
}
运行结果:
介绍(7):用迭代器区间构造
int main()
{string s0("Initial string");string s8(s0.begin(), s0.begin() + 7); //迭代器区间构造cout <<"s0: "<< s0 << endl;cout <<"s8: " << s8 << endl;
}
运行结果:
可以看到s8中用了s0起始位置开始的7个字符初始化了 。
destructor —— 析构
string的析构函数会自动调用,string的底层是一个动态开辟的数组,构造和析构函数是自动调用的(类和对象这里有介绍)。
operator= —— 赋值重载
赋值运算符重载也是默认成员函数(类和对象有介绍)。
string (1)
string& operator= (const string& str); //支持string的赋值c-string (2)
string& operator= (const char* s); //支持char*的赋值character (3)
string& operator= (char c); //支持一个字符的赋值
测试:
int main()
{string s1; string s6("hello world", 5);s1 = s6;//本质就是调用了operator=cout << s1 << endl;s1 = "abcde";cout << s1 << endl;s1 = 'x';cout << s1 << endl;return 0;
}
运行结果:
string类对象的容量操作
函数名称 | 功能说明 |
size | 返回字符串有效字符长度 |
length | 返回字符串有效字符长度 |
max_size | 获取最大长度(能最大开多长) |
capacity | 返回空间容量的大小 |
empty | 检查字符串释放为空串,若是空串返回true,否则返回false |
clear | 清空有效字符 |
reserve | 为字符串预留空间 |
resize | 将有效字符的个数改成n个,多出的空间用字符c填充 |
size() length() max_size()
size()和 length()它们两个功能上完全一致,只是一般size用的比较多,是为了与其他容器接口保持一致。
这里拿size()来说,string提供了一个size的接口,它是用来获取string的长度(有多少个字符)。
max_size()是用来获取它最大的长度,就是它最大能开多长
int main()
{string s("FFDUST");cout << s.length() << endl;cout << s.size() << endl;cout << s.max_size() << endl;
}
capacity()
capacity()接口也就是返回该string当前空间容量的大小是多少
int main()
{string s("FFDUST");cout << "s的空间大小为:"<<s.capacity() << endl;
}
(注意它和size,length接口的区别)
这里还要注意容量扩容问题(每个编译器处理扩容几倍不一致),观察下面程序:
int main()
{string s;size_t sz = s.capacity();cout << "capacity : " << sz << '\n';cout << "making s grow:\n";for (int i = 0; i < 100; ++i){s.push_back('c');if (sz != s.capacity()){sz = s.capacity();cout << "capacity changed: " << sz << '\n';}}return 0;
}
VS下结果:
所以VS下,扩容是先扩2倍,再后面扩1.5倍。
reserve() 和 resize()
reserve()接口就是先给该对象预留多少空间,不改变有效元素个数,若reserve的参数小于string的底层空间总大小时,reserve不会改变容量大小(这里VS下不会缩容,其他编译器可能会缩容,C++规定没有约束)。
int main()
{string s("FFDUST");cout << "s的空间大小为:" << s.capacity() << endl;s.reserve(100);cout << "s的空间大小为:" << s.capacity() << endl;s.reserve(1);cout << "s的空间大小为:" << s.capacity() << endl;return 0;
}
VS这里会做整数倍对齐,所以这里capacity可能会比传的参数较大一些。
注意:谈string容量的时候默认不包含\0的,所以开空间实际上会多1位用来放\0,但capacity返回的是不带\0的。
reserve的用法:提前开空间,避免扩容,提高效率。
int main()
{string s;s.reserve(100);size_t sz = s.capacity();cout << "making s grow:\n";for (int i = 0; i < 100; ++i){s.push_back('c');if (sz != s.capacity()){sz = s.capacity();cout << "capacity changed: " << sz << '\n';}}return 0;
}
这里就是给s预留了足够大的空间,再插入时候不会发生扩容。
resize()接口(将有效字符的个数改成n个,多出的空间用字符c填充),相当于扩容插入。
这里它是有两个版本的:resize(size_t n) 与 resize(size_t n, char c)都是将字符串中有效字符个数改变到n个,不同的是当字符个数增多时:resize(n)用0(也就是\0)来填充多出的元素空间,resize(size_t n, char c)用字符c来填充多出的元素空间。注意的是:resize若比size小的话会删除数据(缩容不确定),比capacity大就会扩容。
int main()
{string s("ffdust");cout << s << endl;cout << "s的空间大小为:" << s.capacity() << endl;s.resize(100); //默认插入\0cout << s << endl;cout << "s的空间大小为:" << s.capacity() << endl;
}
int main()
{string s("ffdust");cout << s << endl;cout << "s的空间大小为:" << s.capacity() << endl;s.resize(100,'1'); //用字符1填充多出的元素空间,注意这里会扩容cout << s << endl;cout << "s的空间大小为:" << s.capacity() << endl;}
clear()
clear()也就是清空有效字符,一般严格来说不会清理掉容量,只是把数据清理掉了
int main()
{string s("ffdust");cout << s << endl;cout << &s << endl;cout << "s的空间大小为:" << s.capacity() << endl;s.clear();cout << s << endl;cout << &s << endl;cout << "s的空间大小为:" << s.capacity() << endl;return 0;
}
运行结果:
empty()
empty()接口时用来判空的(有没有字符),也就是检测字符串是否为空串,若是返回true,否则返回false。
int main()
{string s("ffdust");cout << s << endl;if (s.empty()){cout << s << ",是空串" << endl;}else{cout << s << ",不是空串" << endl;}cout << "s的空间大小为:" << s.capacity() << endl;s.clear();cout << s << endl;if (s.empty()){cout << s << ",是空串" << endl;}else{cout << s << ",不是空串" << endl;}cout << "s的空间大小为:" << s.capacity() << endl;return 0;
}
运行结果:
遍历及访问string所需的一些接口
函数功能 | 功能说明 |
operator[] | 返回pos位置的字符,const string类对象也以调用 |
begin()+end() | begin获取第一个字符的迭代器 + end获取最后一个字符下一个位置的迭代器 |
rbegin()+rend() | rbegin获取最后一个字符迭代器 + rend获取第一个字符前一个位置的迭代器 |
范围for | C++11支持更简洁的范围for的新遍历方式 |
遍历string有三种方式:
- 下标+[]
- 迭代器
- 范围for
operator[] —— []运算符重载
string重载operator[],访问pos位置的字符,返回这个字符的引用。 (可以读和修改)
string重载了[],这样就可以让string当成数组一样使用下标访问。string底层意思大致理解是有一个指针,指针指向一个数组,是动态开辟的,它还要有size和capacity,重载operator[],就可以让它去访问第i个位置的字符:
class string
{
public:char& operator[](size_t i){return _str[i]; //返回第i字符的引用(这里引用返回,不只是可以减少拷贝,还能让它被修改)}
private:char* str;size_t size;size_t capacity;
};
使用如下:
int main()
{string s6("hello world");cout << s6 << endl;s6[5] = 'a'; //将下标为5的字符修改成acout << s6 << endl;return 0;
}
运行结果:
就相当于用数组一样,可以获取这个位置的字符,也可以修改这个位置的字符,但这里的底层就是函数调用,调用的operator[],注意:这里越界了可以检查出来的。
char& operator[](size_t i)
{assert(i < _size); //这里断言,只要越界了就直接报错return _str[i];
}
我们看到这里15位置越界访问了,就报错了。
所以,我们可以搭配着size接口防止越界访问来一个一个字符的遍历:
int main()
{string s6("hello world1111");//下标+[]for (int i = 0; i < s6.size(); i++){cout << s6[i] << " ";}cout << endl;return 0;
}
运行结果:
iterator —— 迭代器 (正向)
迭代器遍历:
int main()
{string s6("hello world");//迭代器遍历——正向string::iterator it = s6.begin();while (it != s6.end()){cout << *it << " ";++it;}cout << endl;return 0;
}
正向遍历(begin+end) :
注:迭代器是STL六大组件之一,迭代器是用来遍历和访问这些容器的 。(迭代器有可能是原生指针,也有可能不是)。
迭代器是类似于一个指针一样的东西,通过解引用可以访问对应位置的数据,迭代器还规定,不管它底层是怎么定义的,它是属于对应容器的类域。(上面string的迭代器属于string的类域,所以要写成 string::iterator),所以所有的容器都可以通过迭代器来访问(通用的访问容器的方式)。
begin()
begin()就是返回开始位置的迭代器。
string这里就是返回的是第一个有效字符的位置的迭代器。
注:这里有两个版本,第一个就是普通对象用来调用的,第二个是const修饰的对象的const迭代器所调用(这里普通对象也能调用,但是只能读,不能写)。
end()
end()返回的是最后一个有效数据的下一个位置的迭代器。
string这里就是返回最后一个有效字符的下一个位置的迭代器。
注:这里有两个版本,第一个就是普通对象用来调用的,第二个是const修饰的对象的const迭代器所调用(这里普通对象也能调用,但是只能读,不能写)。
reverse_iterator —— 反向迭代器
这里就与iterator完全相反着了
反向遍历(rbegin+rend):
int main()
{//反向迭代器遍历// string::reverse_iterator rit = s6.rbegin();// C++11之后,直接使用auto定义迭代器,让编译器推到迭代器的类型auto rit = s6.rbegin();while (rit != s6.rend()){cout << *rit <<" ";++rit;}cout << endl;
}
运行结果:
rbegin和rend
这两个接口就相当于begin与end接口相反的。
也就是rbegin获取最后一个字符迭代器 , rend获取第一个字符前一个位置的迭代器。
const修饰的迭代器
const修饰的对象,要用迭代器遍历时,是需要const修饰的迭代器的,它不能使用普通迭代器,
const迭代器修饰的是迭代器的指向,而不是迭代器的本身(类似于const修饰指针)
如下所示:
int main()
{//const对象const string cs("const hello world");//const修饰的(正向)迭代器string::const_iterator cit = cs.begin(); //这里也可以用cbegin接口,不过begin接口有提供的const修饰的版本,这就已经够用了while (cit != cs.end()) //cend同上也可以用{//错误 C3892 “cit” : 不能给常量赋值//*cit += 'x';cout << *cit << " ";++cit;}cout << endl;//const修饰的反向迭代器string::const_reverse_iterator crit = cs.rbegin(); //这里也可以用crbegin接口,不过rbegin接口有提供的const修饰的版本,这就已经够用了while (crit != cs.rend()) //crend同上也可以用{//错误 C3892 “crit” : 不能给常量赋值//*crit += 'x';cout << *crit << " ";++crit;}cout << endl;return 0;
}
运行结果:
const修饰的迭代器,普通对象也是可以使用的(也就是权限可以缩小,但不能放大),不过只能读,不能写。
int main()
{//普通对象string s("hello world");//const修饰的迭代器string::const_iterator it = s.begin();while (it != s.end()){//错误 C3892 “it” : 不能给常量赋值//*it += 'x';cout << *it << " ";++it;}cout << endl;//const修饰的反向迭代器string::const_reverse_iterator rit = s.rbegin();while (rit != s.rend()){//错误 C3892 “rit” : 不能给常量赋值//*rit += 'x';cout << *rit << " ";++rit;}cout << endl;return 0;
}
运行结果:
(这里也可以用auto自动推导它的类型,方便代码的编写)
范围for
- 对于一个有范围的集合而言,C++11中引入了基于范围的for循环。for循环后的括号由冒号“ :”分为两部分:第一部分是范围内用于迭代的变量,第二部分则表示被迭代的范围,自动迭代,自动取数据,自动判断结束。
- 范围for可以作用到数组和容器对象上进行遍历。
auto
int main()
{string s6("hello world");//字符赋值,自动迭代,自动判断结束for (auto e : s6) //auto这里自动推导类型为char{cout << e << " ";}cout << endl;return 0;
}
运行结果:
所以这里范围for想表达的是:
- 注意:范围for的底层角度是跟迭代器一样的,也就是说范围for这段代码被编译了之后会被替换成迭代器。(所以要支持范围for前提是要支持迭代器遍历)
从汇编层可以看到,这里就是被替换成了迭代器:
范围for跟迭代器就相当于没有区别,范围for只是方便编写代码。这里对比迭代器,也展示出auto的价值就是缩短代码(简化代码),不过这样会使代码可读性降低。
//这两个it的类型是一致的
string::iterator it = s6.begin();//auto会自动推导成上面的string::iterator
auto it = s6.begin();
- 迭代器是可以修改的。
int main()
{string::iterator it = s6.begin();cout << s6 << endl;while (it != s6.end()){*it += 2; //让里面的每一个值都加等2cout << *it << " ";++it;}cout << endl;for (auto e : s6){cout << e << " ";}cout << endl;return 0;
}
运行结果对比一下:
可以看到每一个值都被改变了,范围for打印数据也受到影响。范围for里也是可以修改数据的,下面在范围for里面打印原来的值:
int main()
{string::iterator it = s6.begin();cout << s6 << endl;while (it != s6.end()){*it += 2; //让里面的每一个值都加等2cout << *it << " ";++it;}cout << endl;for (auto e : s6){e -= 2; //只需要让e减等2即可cout << e << " ";}cout << endl;return 0;
}
运行结果:
- 注意:这里有坑的是,范围for打印出来的结果看似把s6恢复原状了,这时cout一下s6可以看到s6还是没有变回去的。这个原因是:
这里若想在范围for里修改,只需要加& 符号,也就是引用
for (auto& e : s6) //这里auto自动推导为char类型,//若想是char的引用,就需要主动添加一个&
//这时e就是s6里面(*it)的别名,也就是取它每个字符的别名
{e -= 2; //这时修改e,就修改了string里的值cout << e << " ";
}
cout << endl;
注意:用auto声明指针类型时,用auto和auto*没有任何区别(也就是当是一个指针类型时,可以直接写auto即可),但用auto声明引用类型时则必须加上&(auto &)。
typeid().name()
typeid()可以帮助我们观察类型:
typeid(变量名).name() //可以看到该变量的类型
int func1()
{return 10;
}int main()
{int a = 10;auto b = a;auto c = 'a';auto d = func1();cout << typeid(b).name() << endl;cout << typeid(c).name() << endl;cout << typeid(d).name() << endl;int x = 10;auto y = &x;auto* z = &x;auto& m = x;cout << typeid(x).name() << endl;cout << typeid(y).name() << endl;cout << typeid(z).name() << endl;return 0;
}
运行结果:
这里auto使用时还需要注意一些事项:
// 编译报错:rror C3531: “e”: 类型包含“auto”的符号必须具有初始值设定项
auto e;
不能这样定义,它不知道e到底是多大,auto定义的变量类型一定是由右边的变量或者函数调用表达式的返回值推导的。
// 不能做参数
void func2(auto a) //这里就算给了缺省值也不支持的
{}
auto不能做参数类型,但auto可以做返回值。
// 可以做返回值,但是建议谨慎使用
auto func3()
{return 3;
}
// 编译报错:error C3538: 在声明符列表中,“auto”必须始终推导为同一类型
auto cc = 3, dd = 4.0;
注意在一行里面定义,定义时要用同一类型
// 编译报错:error C3318: “auto []”: 数组不能具有其中包含“auto”的元素类型
auto array[] = { 4, 5, 6 };
auto不能定义一个数组(C++规定)
在这篇先总结一部分string的接口使用,剩下的部分接口总结使用在后续文章介绍。
制作不易,若有不足之处或出问题的地方,请各位大佬多多指教 ,感谢大家的阅读支持!!!
相关文章:
C++ —— string类(上)
目录 string的介绍 string类功能的使用介绍 constructor —— 构造 介绍使用(1)(2)(4) :构造、拷贝构造、带参构造 介绍(3):拷贝string类对象的一部分字符…...
React Native Mac 环境搭建
下载 Mac 版Android Studio 下载 安装 JDK 环境 Flutter 项目实战-环境变量配置一 安装 Node.js 方式一 通过Node.js 官网下载 下载完成后点击安装包进行安装 安装完成...
Python Web 开发的路径管理艺术:FastAPI 项目中的最佳实践与问题解析20241119
Python Web 开发的路径管理艺术:FastAPI 项目中的最佳实践与问题解析 引言:从路径错误到模块化管理的技术旅程 在现代 Python Web 开发中,路径管理是一个常常被忽视却非常重要的问题。尤其是在使用像 FastAPI 和 Tortoise ORM 这样的框架时…...
Rust derive macro(Rust #[derive])Rust派生宏
参考文章:附录 D:派生特征 trait 文章目录 Rust 中的派生宏 #[derive]基础使用示例:派生 Debug 派生其他常用特征示例:派生 Clone 和 Copy 派生宏的限制和自定义派生自定义派生宏上面代码运行时报错了,以下是解释 结论…...
springboot嗨玩旅游网站
摘 要 嗨玩旅游网站是一个专为旅行爱好者打造的在线平台。我们提供丰富多样的旅游目的地信息,包括景点信息、旅游线路、商品信息、社区信息、活动推广等,帮助用户轻松规划行程。嗨玩旅游网站致力于为用户提供便捷、实用的旅行服务,让每一次旅…...
杰发科技AC7840——EEP中RAM的配置
sample和手册中示例代码的sram区地址定义不一样 这个在RAM中使用没有限制,根据这个表格留下足够空间即可 比如需要4096字节的eep空间,可以把RAM的地址改成E000,即E000-EFFF,共4096bytes即可。...
从零开始的c++之旅——map_set的使用
1.序列式容器和关联式容器 序列式容器:逻辑结构为线性序列的数据结构,两个位置之间没有紧密的关系,比如两者交换一下还是序列式的容器,例如string,vector,deque,array等。 关联式容器࿱…...
Docker中的一些常用命令
find / -type f -name “文件名” 2>/dev/null 寻找所有目录中的这个文件 pwd 查看当前目录的地址 docker pull 镜像名 强制拉镜像 docker run 运行docker systemctl daemon-reload 关闭docker systemctl start docker 启动docker systemctl restart docker 重启docker /…...
自存 sql常见语句和实际应用
关于连表 查询两个表 SELECT * FROM study_article JOIN study_article_review 查询的就是两个表相乘,结果为两个表的笛卡尔积 相这样 这种并不是我们想要的结果 通常会添加一些查询条件 SELECT * FROM study_articleJOIN study_article_review ON study_art…...
python | argparse模块在命令行的使用中的重要作用
import argparseclass TestCases:def __init__(self, nameNone, expect_resultNone):self.name nameself.expect expect_resultself.parser argparse.ArgumentParser() # 创建命令解析器self.add_arguments() # 方法 : 添加命令self.args, _ self.parser.par…...
【HCIP]——OSPF综合实验
题目 实验需求 根据上图可得,实验需求为: 1.R5作为ISP:其上只能配置IP地址;R4作为企业边界路由器,出口公网地址需要通过PPP协议获取,并进行CHAP认证。(PS:因PPP协议尚未学习&#…...
PW系列工控电脑复制机:效率与精度双重提升
工控电脑复制应用:效率与精度的双重提升 随着现代企业对大数据、数据备份、和跨平台兼容性需求的快速增长,工控电脑已成为数据密集型产业的核心设备。针对工控环境中大量数据复制的特殊需求,PW系列NVMe/SATA PCIe SSD复制机(如PW…...
学习QT第二天
QT6示例运行 运行一个Widgets程序运行一个QT Quick示例 工作太忙了,难得抽空学点东西。-_-||| 博客中有错误的地方,请各位道友及时指正,感谢! 运行一个Widgets程序 在QT Creator的欢迎界面中,点击左侧的示例…...
11.20作业
题目一: 题目: // 数组的行列转置 代码: // 数组的行列转置 #include <stdio.h> int main() {int a[2][3], i, j, b[3][2];printf("输入一个两行三列的数组a:\n");for (i 0; i < 2; i)for (j 0; j < 3; j){scanf…...
Ubuntu Linux使用前准备动作_使用root登录图形化界面
Ubuntu默认是不允许使用 root 登录图形化界面的。这是出于安全考虑的设置。但如果有需要,可以通过以下步骤来实现使用 root 登录: 1、设置 root 密码 打开终端,使用当前的管理员账户登录系统。在终端中输入命令sudo passwd root,…...
DICOM核心概念:显式 VR(Explicit VR)与隐式 VR(Implicit VR)在DICOM中的定义与区别
在DICOM(Digital Imaging and Communications in Medicine)标准中,VR(Value Representation) 表示数据元素的值的类型和格式。理解显式 VR(Explicit VR)与隐式 VR(Implicit VR&#…...
源码分析Spring Boot (v3.3.0)
. ____ _ __ _ _/\\ / ____ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | _ | _| | _ \/ _ | \ \ \ \\\/ ___)| |_)| | | | | || (_| | ) ) ) ) |____| .__|_| |_|_| |_\__, | / / / /|_||___//_/_/_/:: Spring Boot :: (v3.3.0)//笔记背…...
IPv6 NDP 记录
NDP(Neighbor Discovery Protocol,邻居发现协议) 是 IPv6 的一个关键协议,它组合了 IPv4 中的 ARP、ICMP 路由器发现和 ICMP 重定向等协议,并对它们作出了改进。该协议使用 ICMPv6 协议实现,作为 IPv6 的基…...
linux常用命令(文件操作)
目录 1. ls - 列出目录内容 2. cd - 更改目录 3. pwd - 打印当前工作目录 4. mkdir - 创建目录 5. rm - 删除文件或目录 6. cp - 复制文件或目录 7. mv - 移动或重命名文件 8. touch - 更新文件访问和修改时间 9. cat - 显示文件内容 10. grep - 搜索文本 11. chmod…...
内存管理 I(内存管理的基本原理和要求、连续分配管理方式)
一、内存管理的基本原理和要求 内存管理(Memory Management)是操作系统设计中最重要和最复杂的内容之一。虽然计算机硬件技术一直在飞速发展,内存容量也在不断增大,但仍然不可能将所有用户进程和系统所需要的全部程序与数据放入主…...
【Redis】基于Redis实现秒杀功能
业务的流程大概就是,先判断优惠卷是否过期,然后判断是否有库存,最好进行扣减库存,加入全局唯一id,然后生成订单。 一、超卖问题 真是的场景下可能会有超卖问题,比如开200个线程进行抢购,抢100个…...
Hadoop 使用过程中 15 个常见问题的详细描述、解决方案
目录 问题 1:配置文件路径错误问题描述解决方案Python 实现 问题 2:YARN 资源配置不足问题描述解决方案Python 实现 问题 3:DataNode 无法启动问题描述解决方案Python 实现 问题 4:NameNode 格式化失败问题描述解决方案Python 实现…...
【Flutter 问题系列第 84 篇】如何清除指定网络图片的缓存
这是【Flutter 问题系列第 84 篇】,如果觉得有用的话,欢迎关注专栏。 博文当前所用 Flutter SDK:3.24.3、Dart SDK:3.5.3,网络图片缓存用的插件 cached_network_image: 3.4.1,缓存的网络图像的存储和检索用…...
【UE5】使用基元数据对材质传参,从而避免新建材质实例
在项目中,经常会遇到这样的需求:多个模型(例如 100 个)使用相同的材质,但每个模型需要不同的参数设置,比如不同的颜色或随机种子等。 在这种情况下,创建 100 个实例材质不是最佳选择。正确的做…...
鸿蒙动画开发07——粒子动画
1、概 述 粒子动画是在一定范围内随机生成的大量粒子产生运动而组成的动画。 动画元素是一个个粒子,这些粒子可以是圆点、图片。我们可以通过对粒子在颜色、透明度、大小、速度、加速度、自旋角度等维度变化做动画,来营造一种氛围感,比如下…...
IDEA2023 创建SpringBoot项目(一)
一、Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置。 二、快速开发 1.打开IDEA选择 File->New->Project 2、…...
VSCode:终端打开一片空白,无cmd
第一步:找到右下角设置图标 第二步:找到 Terminal - Integrated - Default Profile: Windows: 选择一个本地存在的命令方式,重启即可 也可以直接在右下角直接选择...
Zea maize GO
1.涉及到新旧基因组的转化 B73v4_to_B73v5 (davidbioinformatics只支持新版基因组) MaizeGDB Map文件下载https://download.maizegdb.org/Pan-genes/B73_gene_xref/小处理脚本(制作map文件) import pandas as pd# 读取CSV文件 …...
Android开发实战班 - 数据持久化 - 数据加密与安全
在 Android 应用开发中,数据安全至关重要,尤其是在处理敏感信息(如用户密码、支付信息、个人隐私数据等)时。数据加密是保护数据安全的重要手段,可以有效防止数据泄露、篡改和未经授权的访问。本章节将介绍 Android 开…...
EDA实验设计-led灯管动态显示;VHDL;Quartus编程
EDA实验设计-led灯管动态显示;VHDL;Quartus编程 引脚配置实现代码RTL引脚展示现象记录效果展示 引脚配置 #------------------GLOBAL--------------------# set_global_assignment -name RESERVE_ALL_UNUSED_PINS "AS INPUT TRI-STATED" set_…...
新网站怎么做才会被收录/痘痘该如何去除效果好
原文地址为: 本人常用资源整理(ing...)Deep Learning(深度学习): ufldl的2个教程(这个没得说,入门绝对的好教程,Ng的,逻辑清晰有练习):一 ufldl的2个教程(这个没得说,入…...
东莞响应式网站价格/推广方案100个
《数据结构与算法设计》实验报告书之二叉树的基本操作实现及其应用 实验项目 二叉树的基本操作实现及其应用 实验目的 1.熟悉二叉树结点的结构和对二叉树的基本操作。 2.掌握对二叉树每一种操作的具体实现。 3.学会利用递归方法编写对二叉树…...
旅游景区宣传软文/中山seo关键词
错误: 找不到或无法加载主类 scala.tools.nsc.MainGenericRunner 原因: Scala安装路径中包含空格。 解决办法:scala 不要安装在E:\Program Files 这种有空格的目录下,简直坑...
西安网站建设app建设/黄冈网站推广软件
element ui 中的步骤条组件——steps 最近在写几个小组件,嗯,组件的编写比搭建页面和渲染数据要难一些,难就难在思想,这个东西看不见摸不着,得练习,得思考。 时间列表组件,其实不用steps组件也…...
绵阳房产网站建设/百度推广的广告靠谱吗
Youtube.com,Youku.com,Tudou.com转载于:https://blog.51cto.com/fccwcom/1123901...
网站建设服务定制/免费私人网站建设平台
尝试用Python实现一些简单的算法和数据结构 之前的算法和数据结构基本都是用Swift写的,现在尝试用Python实现一些简单的算法和数据结构。 update 20160704 准备加入《剑指offer》的习题python实现,以及机器学习过程中的一些算法 update 20160717 加入leetcode部分 #…...