string的使用

前言

我们前面已经介绍了C++的基本知识,本期开始我们将进入C++的第二部分,也是非常重要的一个部分!他就是STL!本期我们来先介绍string及其使用!

本期内容介绍

STL介绍

为什么要学习string?

string的常用接口介绍

一、STL介绍

什么是STL?

STL(standarrd template libaray --- 标准模板库)是C++标准库中的重要组成部分,不仅仅是一个可复用的组件库,而且是一个包含数据结构和算法的软件框架!

STL的六大组件

如何学习STL?

我们会分为两个层次来学习STL,一是介绍它的使用,二是模拟实现!这里的模拟实现不是说实现的和库里面一模一样的!不是,我们只是模拟实现我们常用的!

OK让我们进入string的快乐学习吧!

二、为什么要学习string?

在正是的学习string前我们来想一个问题:我们为什么学习string?C语言不是字符数组替代字符串吗?为什么这里又搞出来一个string?

在C语言中,字符串是以'\0'结尾的一些字符的集合,为了方便操作,C语言标准提供了很多str系列的函数例如strcpy,strlen,strstr等,但这些函数是与字符串分离的,需要用户自己控制底层管理,不符合OOP的思想,而且稍不注意会有越界的风险!所以C++提供了string类,来更好的管理字符串!用户此时调用string相关的函数即可,不在关心底层管理,符合了OOP的思想!也更加安全了!

我们先来看看什么是string?

官网上介绍的很清楚,string是一个字符串顺序表的对象,是被typedef过成string的,为什么底层是basic_string<char>这里先不做介绍,先说结论:和编码有关!编码后面专门介绍!

三、string的常用接口介绍

构造和析构

string s;//空构造
cout << s << endl;

string tmp("123456789");
string s1(tmp);//字符串构造
cout << s1 << endl;

string s2(tmp, 3, 5);//用字符串的pos位开始的len个长度的子串构造
cout << s2 << endl;

string s3("hello string");//字符串常量构造
cout << s3 << endl;

string s4("abcdef", 3);//字符串常量的前n进行构造
cout << s4 << endl;

string s5(10, '@');//用n个c进行构造
cout << s5 << endl;

string s6(tmp.begin(), tmp.end());//迭代器区间构造
cout << s6 << endl;

这么多的构造函数,其实在日常的使用中,我们一般常用的是如下:

析构就没啥说的了!清理资源还空间嘛~!

迭代器

迭代器是和指针用法类似,但不一定是指针!!!

迭代器分为:正向、const正向、反向、const反向!后面C++11新增的那4个是为了区别!这里你可能有个一问题就是为什么要搞一个const迭代器?

这里还是权限问题:权限可以平移、可以缩小、但不能放大!假设不提供const版本,const的字符串在用迭代器访问时就权限放大了,我本来是只读的,已访问变成了可读可写的了,这显然不符合常理!这时你可能想那直接提供一个const版本即可,const和非const都可以访问了!但是如果我非const要写呢?是不是解决不了了!所以得提供两个!!!

正向、const正向

也就是说迭代器是左闭右开的!

OK,用一下:

void test_string2()
{
	string s("hello iterator");
	string::iterator it = s.begin();//正向迭代器
	while (it != s.end())
	{
		cout << *it ;
		++it;
	}
	cout << endl;

	const string s1("hello 6666");
	string::const_iterator it1 = s1.begin();//const正向迭代器
	while (it1 != s1.end())
	{
		cout << *it1;
		++it1;
	}
	cout << endl;
}

这里指定类域是因为STL容器都有迭代器,

反向、const反向

反向迭代器顾名思义就是说倒着遍历访问的!

OK,还是用一下:

void test_string3()
{
	string s("hello world");
	string::reverse_iterator rit = s.rbegin();//反向迭代器
	while (rit != s.rend())
	{
		cout << *rit;
		++rit;
	}
	cout << endl;

	const string s1("asrdafa");
	string::const_reverse_iterator rit1 = s1.rbegin();//const反向迭代器
	while (rit1 != s1.rend())
	{
		cout << *rit1;
		++rit1;
	}
	cout << endl;
}

还有最后的两组的效果和上面的const和反向是一样的,是C++11新增的目的是减少误使用的风险!原因是,上是代码的迭代器变量前的那一堆都可以用auto替代,但代码的可读性就降低了,当出现误操作时,不容易发现!!但是一般开发中很少有人这样搞!!

我就那一个来用一下,其他同理!!

const string s("hello world");
//string::const_reverse_iterator rit = s.rbegin();//正常
//auto rit = s.rbegin();//auto--->这样写你不知道他是不是const
auto rit = s.crbegin();//这样就看起来是哪个了
while (rit != s.crend())
{
	//...
}

容量相关的接口

size 和 length

size和length没有区别,都是返回字符串的元素个数!以前是只有length但STL的有些容器的底层不是线性的,length不再合理了!于是就有了size,string为了和其他容器的一致性也就设计了size!!

max_size()这个接口没什么用这里直接略~!

resize

resize的英文含义是:改变大小。它的功能比较多,可以分为三中情况!

1、如果n小于当前字符串的长度(size),保留前n个字符,size 等于 n,后面的字符相当于被删除了!

2、如果n大于当前字符串的容量(capacity)的话,扩容,然后尾插字符c。如果字符c没有指定,就插入'\0',否则插入指定的字符!

3、如果n大于size,但小于capacity的话,直接尾插!

void test_string1()
{
	string s("hello world");
	cout << s << endl;
	cout << s.size() << endl;//11
	cout << s.capacity() << endl << endl;//vs上一开始默认是15个容量

	//n < _size, 删除字符 
	s.resize(5);
	cout << s << endl;
	cout << s.size() << endl;//5
	cout << s.capacity() << endl << endl;//15个容量

	// _size < n <_capacity, 尾插
	s.resize(10, '#');
	cout << s << endl;
	cout << s.size() << endl;//10
	cout << s.capacity() << endl << endl;//15个容量


	//n > _capacity,扩容 + 尾插
	s.resize(20);//默认不给第二个参数时,默认是'\0'
	cout << s << endl;
	cout << s.size() << endl;//20
	cout << s.capacity() << endl << endl;//31个容量


	s.resize(30,'@');//给第二个参数时,后面尾插的是给的字符
	cout << s << endl;
	cout << s.size() << endl;//30
	cout << s.capacity() << endl << endl;//31个容量
}

OK,再来通过调试看看,上面的没指定参数的扩容+尾插的是不是'\0'

而'\0'是字符串结束的标志,当下次插入是,还是在'\0'开始插入,以前是hello#####\0,现在需要将size改到30,需要插入@,以前的size == 20,所以在以前的基础上插入10个@即可,覆盖在\0开始的10个,这就是20个字符,但size是30的原因!!!

reserve

reserve的英文是保留、预留的意思。这里的作用是为字符串预留空间的。分为两种情况:

1、当n > _capacity时, 就会扩容到n个字符的容量或更大(有的编译器可能存在对齐)!

2、当n <= _capacity时,所不缩容是不确定的,但一定不影响size和已经有的内容!

void test_string2()
{
	string s("hello world");
	cout << s << endl;
	cout << s.size() << endl;
	cout << s.capacity() << endl << endl;

	//n > _capacity --->  扩容
	s.reserve(200);
	cout << s.size() << endl;
	cout << s.capacity() << endl << endl;
	
	// n <= _capacity, 不影响容量和size,也就是即使你的, n < _size也不会删除
	s.reserve(2);
	cout << s.size() << endl;
	cout << s.capacity() << endl << endl;
}

这里很清楚的看到,我开了200个空间,但这里是207个,原因是人家也说了开到n或更大!VS上是考虑了对齐的!而当小于_capacity时我们发现VS上没有缩容!我们再把这段代码拿到Linux上看看:

这是Linux的代码,我们可以看到Linux下是没有对齐的,开多少就是多少!而且当n <_capacity时,会缩容但缩到当前字符串的size大小,其内容不改变!!!

OK,介绍这里我们就可以看看string的扩容机制了!

先说结论:

VS上是1.5倍扩,一开始默认是15(底层有个buff数组,大小16,除去'\0',就是15)

Linux上是2倍扩!!!

void test_string3()
{
	string s;

	size_t num = s.capacity();
	cout << s.capacity() << endl;

	int i = 0;
	while (i < 200)
	{
		s.push_back('a');
		size_t count = s.capacity();
		if (count != num)
		{
			cout << count << endl;
			num = count;
		}
	
		i++;
	}
}

在VS下的结果:

Linux下结果:

OK,我们通过VS调试看看VS下的string的那个buff数组:

他这样设计是因为多数情况下的字符串是小于16的,一开始直接整一个数组就不需要去堆上开辟了,效率高了!这里就先介绍到这里,等吧所有接口介绍完了还会在谈VS下和Linux的底层结构区别的!!!

OK,既然这个reserve可以提前预留空间的话我们是不是在有些情况下,大概提前估算好所需的空间,然后一次性开好,减小了扩容次数,效率是不是会高了?是的,这也是reserve 的一个用很重要的法!!!

例如上述的代码,我们如果这道自己要200个空间的话,提前开好就不需要在扩容了:

Linux同理:

capacity

返回字符串的容量!

clear

清空字符串内容!

void test_string4()
{
	string s("hello world");
	cout << s << endl;
	cout << s.size() << endl;
	cout << s.capacity() << endl;

	s.clear();
	cout << s << endl;
	cout << s.size() << endl;
	cout << s.capacity() << endl;//不会删掉容量
}

empty

判断字符串是否为空!  如果为空,返回true; 否则,返回false;

shrink_to_fit

这是C++11提供的一个缩容接口!目的是避免多与空间的浪费,例如一个字符串实际占用的空间是5个,但容量是200!是不是有点浪费!我们可以通过这个函数来缩到当前字符串的合适的容量大小!但不影响原来字符串的长度和内容!!!

访问相关的接口和操作

除了这几个外我们上面介绍的迭代器也是元素访问,支持元素的遍历;还有一个是C++11新增的范围for,也是支持的!

[ ]  和 at 、迭代器 、范围for

一看到[],我在你在想这东西不是以前C语言有吗?是的!但成员的那个不是很安全,有时候越界检查不出来!C++又重载了[]操作符!

[]和at的作用一样呢!都是获取字符串中某个字符。会返回那个字符的引用!这里他也有const和非const版本!这里原因不在多介绍了!和上面的一,还是权限问题!

at 和 []的区别是:[]越界的检查是暴力检查(assert), 而at是温柔的检查(报异常)!

void test_string5()
{
	string s("hello world");

	//[]遍历
	for (int i = 0; i < 11; i++)
	{
		cout << s[i] << " ";
	}
	cout << endl;

	//at遍历
	for (int i = 0; i < 11; i++)
	{
		cout << s.at(i) << " ";
	}
	cout << endl;

	//迭代器
	string::iterator it = s.begin();
	while (it != s.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;

	//范围for
	for (auto c : s)
	{
		cout << c << " ";
	}
	cout << endl;

}

这是非const的[]、at、和迭代器。他们,他们是可读可写的!这里的范围for没加引用,只读没即使是修改也不会修改s原本内容!!!const和这个相反!只读不写!

总结:如果访问时不修改,建议是使用cosnt的,这样const的可用,非const的也可以使用!

关于范围for,其实它的底层就是迭代器!!!后面模拟实现再看底层!!!

OK,我们再来看看,[]和at的越界不同点!在看这个之前,我先想介绍的是,[]和C语言[]的访问越界的区别:C语言[]的检查是在一定的位置抽查,有可能越界的远了查不到,但是[]是一定可以检查到的!!!因为底层是断言检查!!!

再来看看C++的[]:

再来看看at:

front 和 back

这两个接口一个是取第一个元素,一个是取最后一个元素!其实有了[]我们可以直接[0]和[size-1]!!!

修改的相关接口

OK,我们按顺序来:

operator+=

它的作用是:可以在字符串结尾;尾插一个字符、追加一个字符串、追加一个常量字符串

string s("hello world");
s += "666";
cout << s << endl;

s += string("heheh");
cout << s << endl;

s += '@';
cout << s << endl;

这个函数其实把我们将要介绍的push_back和append的功能集于一体了!!!非常好用!!!

append

这个和构造函数一样,我就不再一一的演示了!我找两个最常用的举个栗子:
 

string s("hello world");
s.append("*********");
cout << s << endl;

s.append(string("hehehe"));
cout << s << endl;

push_back

尾插一个字符

string s("hello world");

s.push_back('#');
cout << s << endl;

这个在上面的测试扩容机制时用过了,这里不在多介绍了!!!!

insert

几乎不用的我划掉了,留下的这几个也是很复杂!我们最常用的是1\3\5来演示一下!

string s("hello world");
s.insert(0, string("999999"));//0位置前插入一个字符串
cout << s << endl;

s.insert(2, "###");//2位置前插入一个字符串常量
cout << s << endl;

s.insert(5, 1,'*');//5位置前插入一个*
cout << s << endl;

erase

最常用的是第一个!

string s("hello world");
s.erase(2, 3);//2号位置开始,删除3个
cout << s << endl;

s.erase(0);//全删
cout << s << endl;

s.erase();//不给位置和长度默认全删
cout << s << endl

replace

这个设计的也是很复杂的,我还是介绍最常用的!这个和构造那块的函数很相似!若有其他需求请参照上面的构造!

void test_string1()
{
	string s("hello world");
	s.replace(0, 5, string("12345678"));//从0位置开始的5个字符,用string("12345678")替代
	cout << s << endl;

	string s1("xxxxyyyy");
	s1.replace(0, 4, "abcd");//从0位置开始的4个字符,用"abcd"替代
	cout << s1 << endl;

	string s2("aaaaaaaaaa");
	s2.replace(2, 5, 10, '@');//从2位置开始的5个字符,用10个'@'替代
	cout << s2 << endl;
}

swap

这个函数是成员函数,和算法库里面的那个不一样!!!(后期会介绍比算法库中的高效)!

它的作用就是交换两个字符串!注意这个swap交换的是string的底层的指针!空间复杂度较低!

void test_string2()
{
	string s1("hello world");
	string s2("123456");

	cout << "s1 = " << s1 << endl;//hello world
	cout << "s2 = " << s2 << endl << endl;//123456

	s1.swap(s2);

	cout << "s1 = " << s1 << endl;//123456
	cout << "s2 = " << s2 << endl;//hello world
}

我们上面感刚也说了,他是直接交换底层的指针的!我们可以看看他们的size和capacity是否已经交换!

pop_back

作用:尾删

这个函数很简单!不在举栗子了,就是删除最后一个字符!

转换和查找的相关操作

c_str和data:

由于c++是支持C语言的,有时候会混着写!例如在C++中使用fopen等!此时要的是c语言形式的字符串,给C++的string就不行了!

此时我们需要c形式的字符串,我们可以用c_str或data进行转换!

此时s1和s1.c_str()的区别是有无'\0'

find

void test_string4()
{
	string s1("hello world world");
	string s2("wor");

	size_t i = s1.find(s2, 5);//5位置开始找s1
	cout << i << endl;

	size_t j = s1.find("hello", 0);//0位置开始查找"hello"
	cout << j << endl;

	size_t x = s1.find("world", 7, 5);//7位置开始查找"world", 的5个字符
	cout << x << endl;

	size_t s = s2.find('w', 3);//3位置开始查找字符'w'
	cout << s << endl;

}

这里我有想到了一个C语言时候的一个题!就是给你一个字符串要求把空格换成20%!ok 这里就可以用find的和replace做!

void test_string5()
{
	string s1("hello world world");
	cout << s1 << endl << endl;
	size_t pos = s1.find(' ', 0);//从第一个位置开始找空格
	while (pos != string::npos)
	{
		s1.replace(pos, 1,"20%");
		pos = s1.find(' ', pos + 1);//从当前空个的下一个位置开始找下一空格
	}

	cout << s1 << endl;
}

这样写这个题就完成了!但时间效率一点也不高!!!一位insert、earse、replace等都是要挪动数据的!有的还有扩容问题!所以一般能不用就不用!!!!

这道题其实还有一个解法就是!再开一个字符串把不是空格的字符尾插到后面,遇到空格了尾插20%即可!!!这样就可以用空间换时间了!!!

	string tmp;
	for (auto c : s1)
	{
		if (c == ' ')
		{
			tmp += "20%";
		}
		else
		{
			tmp += c;
		}
	}

	cout << tmp << endl;

rfind

void test_string6()
{
	string s1("hello world world");
	size_t pos = s1.rfind("world");//最后一个位置向前找"world"在s1中最后出现的首字符的下标
	cout << pos << endl;


	size_t pos1 = s1.rfind(string("ld"), 13);//从13位置开始向前找这个字符串的最后一次出现的位置的首字符的下标
	cout << pos1 << endl;

	size_t pos2 = s1.rfind("hello", 6, 3);//从6位置开始向前找"hello"的前三个的最后一次出现的位置的首字符的下标
	cout << pos2 << endl;

	size_t pos3 = s1.rfind('w');//最后一个位置向前找'w'在s1中最后出现的下标
	cout << pos3 << endl;
}

find_first_of

这个函数的名字很神奇,一看是找第一个出现的字符的位置!但其实是从前往后找在一个字符串中第一次出现的某个字符,然后返回其位置, 如果没找到则返回npos这个前面介绍过就是整型的最大值!!!

void test_string7()
{
	string s("hello world world");
	size_t pos1 = s.find_first_of("aeiou", 1);//找到e

	size_t pos2 = s.find_first_of(string("abcd"), 0);//0位置开始找到d
}

这个东西可以干啥呢?其实在我们的日常生活中你见过!比如你的身份证的后六位隐藏,出现一些敏感词的屏蔽等!OK举个栗子:

	string s1("我草尼玛");
	cout << s1 << endl;

	size_t pos = s1.find_first_of("草尼玛");
	while (pos != string::npos)
	{
		s1[pos] = '*';
		pos = s1.find_first_of("草尼玛",pos + 1);
	}
	cout << s1 << endl;

这是一段你在游戏中问候队友的问候语,但系统检测到会给你屏蔽!

find_last_of

这个和上面的一样只不过这个是从后向前找的!举个常见的小栗子:我们得到一个文件的路径后,我们要把它的各个部分取出来此时就可以用这个了!

void test_string8()
{
	string str("c:\\win\\test.cpp");
	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';
}

find_first_not_of

这个和find_first_of的功能相反,前者是把存在的从前面找到并返回第一个字符出现的下标,这个是把不存在的第一个的下标返回!

OK,我们还是用上面屏蔽的例子来举栗(这里就是把存在不屏蔽,不存的屏蔽):

void test_string9()
{
	string s("jhsdgfuianbxcsjakghwdfuqab kbj");
	cout << s << endl;

	size_t pos = s.find_first_not_of("aeiou");
	while (pos != string::npos)
	{
		s[pos] = '*';
		pos = s.find_first_not_of("aeiou", pos + 1);
	}

	cout << s << endl;
}

find_last_not_of

这个和find_last_of的相反,前者是找在集合的字符的最后一个的位置,这个是找字符串中最后一个不匹配指定字符集合中任何字符的位置

void test_string10()
{
	string str = "Hello, World!";
	string chars = " ,!";  // 要查找的字符集合

	size_t found = str.find_last_not_of(chars);
	if (found != string::npos) 
	{
		cout << "最后一个不在指定字符集合中的字符位置是: " << found << "是" << str[found] << endl;
	}
	else 
	{
		cout << "字符串中的所有字符均在指定字符集合中" << endl;
	}
}

substr

这个是返回字符串中的一个子串!从pos位置开始,len长度的子串!!!

void test_string11()
{
	string str = "Hello, World!";
	string sub = str.substr(0, 5);
	cout << sub << endl;
}

非成员函数介绍

operator+

返回两个字符串拼接的一个字符串!他这里写成非成员函数的原因是成员函数默认第一个参数是this,如果char* + str的话就会有问题!

逻辑比较

这个就不举例子了!很简单,就是比较两个字符串的!

swap

这个函数是交换两个字符串的内容的!底层直接交换的是指针!我们前面也说过有一个成员函数swap和这个个一样,那为什么还有这个呢???有一种情况就是被误操作了,没有str1.swap(str2);而是直接swap(str1,str2),这不就是调算法库里面的那个呢吗?有拷贝不好!这里就是为了防止这种情况的!你可能会说这个在全局,算法库的那个也在全局到底调用哪个?我们在模板那里介绍过!编译器和人一样有现成的迟现成的,没有现成的再去做!!!这里也是一样,swap已经是string的参数了,就不用去实例化了!而这个swap底层实际上是调用的str1.swap()!

流插入和流提取略!

getline

这个函数的意思是从流里面提取字符到字符串,遇到终止符结束,如果终止符没指定就遇到\n结束!也就是终止符默认是\n

	string s;
	getline(cin, s, '@');//有指定符到指定福结束
	cout << s << endl;

	string s;
	getline(cin, s);//没有指定符到\n结束
	cout << s << endl;

to_string

将非字符串转化为字符串!然后返回这个字符串

	int a = 10;
	string s = to_string(a);
	cout << s << endl;

OK,这就是string的基本使用,本期就介绍到这里!好兄弟,我们下期再见!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/452372.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Twinmotion】Twinmotion导入UE5

步骤 1. 在虚幻商城中安装“Datasmith Twinmotion导入器插件” 安装“面向虚幻引擎的Twinmotion内容” 2. 打开虚幻引擎&#xff0c;在插件中搜索“twinmotion”&#xff0c;勾选如下两个插件&#xff0c;然后重启虚幻引擎 3. 打开Twinmotion&#xff0c;随便添加一个物体 导出…

NAND和NOR Flash 完全学习笔记

本文要点&#xff1a; NAND FLASH与NOR FLASH 的技术对比&#xff1b;最详细的存储单元对比详解&#xff1b;NAND FLASH与NOR FLASH 的最新市场份额及应用&#xff1b;NAND FLASH与NOR FLASH 的基础原理分析。 目前&#xff0c;NOR FLASH和NAND FLASH是市场上主要的非易失性闪…

李彦宏:在中文上文心大模型4.0已经超过了GPT-4!如何优雅地反驳

大家好&#xff0c;我是木易&#xff0c;一个持续关注AI领域的互联网技术产品经理&#xff0c;国内Top2本科&#xff0c;美国Top10 CS研究生&#xff0c;MBA。我坚信AI是普通人变强的“外挂”&#xff0c;所以创建了“AI信息Gap”这个公众号&#xff0c;专注于分享AI全维度知识…

<逻辑回归算法(Logistic regression)>——《机器学习算法初识》

目录 一、 逻辑回归介绍 1 逻辑回归的应用场景 2 逻辑回归的原理 2.1 输入 2.2 激活函数 3 损失以及优化 3.1 损失 3.2 优化 4 小结 二、逻辑回归api介绍 实现过程&#xff1a; 三、分类评估方法 1.分类评估方法 1.1 精确率与召回率 1.1.1 混淆矩阵 1.1.2 精确…

【五、接口自动化测试】5分钟掌握python + requests接口测试

你好啊&#xff01;我是山茶&#xff0c;一个持续探索AI 测试的程序员&#xff01; 在做接口测试时&#xff0c;在python中内置了HTTP库 urllib&#xff0c;可以用于发送http请求。基于urllib二次封装的三方库Requests&#xff0c;相较于urllib更佳简介易用。所以&#xff0c;…

LED基础知识分享(一)

大家好&#xff0c;我是砖一。 今天给大家分享一下&#xff0c;LED的基础知识&#xff0c;有照明行业&#xff0c;或者对LED感兴趣的朋友&#xff0c;可以学习一下&#xff0c;希望对你有用~ 一&#xff0c;什么是LED (Light Emitting Diode)? 1&#xff0c;LED是一种发出某…

MathType7最新软件产品秘钥2024中文版

MathType 7是一款功能强大的数学公式编辑器&#xff0c;专为教育工作者、学生、科研人员以及任何需要处理数学公式的人群设计。以下是对MathType 7的详细介绍&#xff1a; 一、功能特点&#xff1a; 广泛的符号和模板支持&#xff1a;MathType 7支持各种数学符号、公式、方程…

Centos7 安装postgresql14后无法连接数据库

1、数据库服务器允许外部访问5432端口。 2、postgresql.conf 3、pg_hba.conf a、制定某个IP&#xff08;192.168.0.107&#xff09;访问 b、指定ip段访问 允许10.1.1.0~10.1.1.255网段登录数据库 host all all 10.1.1.0/24 trust c、指定全网访问 host a…

mysql5.6---windows和linux安装教程和忘记密码怎么办

一、windows安装 1.完成解压 解压完成之后将其放到你喜欢的地址当中去&#xff0c;这里我默认放在了D盘&#xff0c;这是我的根目录 2.配置环境变量 我的电脑->属性->高级->环境变量->系统变量 选择PATH,在其后面添加: (注意自己的安装地址) D:\mysql-5.6.49…

【C++庖丁解牛】vector容器的简易模拟实现(C++实现)(最后附源码)

&#x1f341;你好&#xff0c;我是 RO-BERRY &#x1f4d7; 致力于C、C、数据结构、TCP/IP、数据库等等一系列知识 &#x1f384;感谢你的陪伴与支持 &#xff0c;故事既有了开头&#xff0c;就要画上一个完美的句号&#xff0c;让我们一起加油 目录 前言vector容器代码实现内…

【测试开发学习历程】Linux用户管理+文件权限管理

目录 一、用户管理 &#xff08;一&#xff09;用户和用户组的基本概念 1.概念 2.设置原因 3.用户与用户组的关系 4.用户类型 &#xff08;二&#xff09;用户的创建、修改属性和删除用户 1.用户信息文件 2.创建用户 3.修改用户密码 4.修改用户信息 5.用户查询 6.…

5.shell if判断语句

shell-if判断语句 1.什么是if2.为什么要用if3.if基础语法4.基于文件进行判断5.基于整数比对6.基于字符比对7.基于正则比对 1.什么是if if其实就是模仿人类的判断来进行的&#xff0c;要么真、要么假、就这两种结果。 2.为什么要用if 判断 3.if基础语法 单条件 if [ 如果你…

RocketMQ快速入门

RocketMQ快速入门 准备工作下载RocketMQ环境要求 JDK下载安装JDK下载JDK安装 安装RocketMQ安装步骤目录介绍 启动RocketMQ测试RocketMQ发送消息接收消息 关闭RocketMQ RocketMQ是阿里巴巴2016年开源的MQ中间件&#xff0c;使用Java语言开发&#xff0c;在阿里内部&#xff0c;R…

String、StringBuilder、StringBuffer 有什么区别?

1、典型回答 String、StringBuilder 和 StringBuffer 都是 Java 语言中&#xff0c;用于操作字符串的类&#xff0c;但它们在性能、可变性和线程安全性方面有一些区别 1、String&#xff1a;不可变字符串类&#xff0c;也就是说一旦创建&#xff0c;它的值就不可变。每次对 S…

数据库基础理论知识

1.基本概念 数据(Data)&#xff1a;数据库存储的基本对象。数字、字符串、图形、图像、音频、视频等数据库(DB)&#xff1a;在计算机内&#xff0c;永久存储、有组织、可共享的数据集合数据库管理系统(DBMS)&#xff1a;管理数据库的系统软件数据库系统(DBS):DBDBMSDBADBAP 数…

【spring】-多模块构建二-问题整理

1、bean注入问题 The injection point has the following annotations: - org.springframework.beans.factory.annotation.Autowired(requiredtrue) 解决1&#xff1a; 由于引入的bean类 不属于启动类的子模块下&#xff0c;需要在启动类手动声明扫描的类 也适用于公共子模…

Ribbon-负载均衡

目录 一、负载均衡的作用位置 二、Ribbon负载均衡的工作流程 三、IRule接口 负载均衡的策略&#xff1a; 修改负载均衡策略&#xff08;即修改使用的IRule接口的实现类&#xff09;&#xff1a; 四、饥饿加载 五、总结 前置知识&#xff1a;Eureka注册中心 不熟悉Eureka的…

【Emgu CV教程】9.3、形态学常用操作之开运算

文章目录 一、相关概念1.什么叫开运算3.开运算的函数 二、演示1.原始素材2.代码3.运行结果 一、相关概念 1.什么叫开运算 腐蚀、膨胀已经讲完&#xff0c;这两个是最基础的形态学操作。这次讲的是开运算&#xff0c;它是一个先腐蚀、后膨胀的过程。原始图像先被腐蚀&#xff…

使用Anaconda创建Python指定版本的虚拟环境

由于工作的需要和学习的需要&#xff0c;需要创建不同Python版本的虚拟环境。 比如zdppy的框架&#xff0c;主要支持的是Python3.8的版本&#xff0c;但是工作中FastAPI主要使用的是3.11的版本&#xff0c;所以本地需要两套Python环境。 决定使用Anaconda虚拟环境管理的能力&…

发那科数控机床FanucCNC(NCGuide)仿真模拟器配置和数据采集测试

开发日记3.12 此篇用于记录发那科数控机床(Fanuc CNC)采集程序开发中&#xff0c;用虚拟机做测试时&#xff0c;虚拟机的配置和使用以支持采集软件开发和测试。 配置虚拟机使用仿真软件 下载VMware15 「链接&#xff1a;https://pan.xunlei.com/s/VNsl9Gmb14ANBiiNlsT7vA2LA…