C++STL详解 string【C++】

news2024/10/6 8:40:45

文章目录

  • 函数模板
    • 函数模板的原理
    • 函数模板的实例化
    • 模板参数的匹配原则
  • 类模板
    • 类模板的定义格式
    • 类模板的实例化
  • string

函数模板

函数模板的原理

template <typename T> //模板参数 ——类型 
void Swap(T& x1, T& x2)
{
	T tmp = x1;
	x1 = x2;
	x2 = tmp;
}
int main()
{
	int a = 0, b = 1;
	double c = 1.1, d = 2.2;

	swap(a, b);
	swap(c, d);
	int* p1 = &a;
	int* p2 = &b;
	swap(p1, p2);
	return 0;
}

函数模板是一个蓝图,它本身并不是函数,是编译器用使用方式产生特定具体类型函数的模具。所以其实模板就是将本来应该我们做的重复的事情交给了编译器
在这里插入图片描述

在编译器编译阶段,对于模板函数的使用,编译器需要根据传入的实参类型来推演生成对应类型的函数以供调用。比如:当用double类型使用函数模板时,编译器通过对实参类型的推演,将T确定为double类型,然后产生一份专门处理double类型的代码,对于字符类型也是如此

在这里插入图片描述

函数模板的实例化

用不同类型的参数使用函数模板时,称为函数模板的实例化。模板参数实例化分为:隐式实例化和显式实例化

1、隐式实例化:让编译器根据实参推演模板参数的实际类型

template<class T>
T Add(const T& left , const T& right)
{
	return left + right;
}
int main()
{

	int a1 = 10, a2 = 20;
	double d1 = 10.1, d2 = 20.2;
	//函数模板根据调用,自动推导模板参数的类型 ,实例化对应的参数 
		cout << Add(a1, a2) << endl;
		cout << Add(d1, d2) << endl;
	//实参传递的类型, 推演T的类型  
		cout << Add( a1, (int)d1  ) << endl;
		cout << Add( (double)a1, d1) << endl;
	//显示实例化 ,用指定的类型实例化 ,相当于隐式类型转换 
		cout << Add<int> (a1, d1) << endl;
		cout << Add<double>(a1, d1) << endl;

	return 0;
}

2、显式实例化:在函数名后的<>中指定模板参数的实际类型

template<class T>
T Add(const T& left , const T& right)
{
	return left + right;
}
int main()
{

	int a1 = 10, a2 = 20;
	double d1 = 10.1, d2 = 20.2;
	//函数模板根据调用,自动推导模板参数的类型 ,实例化对应的参数 
		cout << Add(a1, a2) << endl;
		cout << Add(d1, d2) << endl;
	//实参传递的类型, 推演T的类型  
		cout << Add( a1, (int)d1  ) << endl;
		cout << Add( (double)a1, d1) << endl;
	//显示实例化 ,用指定的类型实例化 ,相当于隐式类型转换 
		cout << Add<int> (a1, d1) << endl;
		cout << Add<double>(a1, d1) << endl;

	return 0;
}
template<class T >
 T * Alloc(int n )
{
	 return new T[n];
}

 int main()
 {
	 //有些函数无法自动推导函数模板的类型,实例化对应的参数,只能显式实例化
	 double *p1 = Alloc <double>(10);
	 return 0;
 }

模板参数的匹配原则

类模板

//类模板 ,无法推演实例化,所以类模板都是显式实例化

class Stack
{
public :
	Stack(int capacity = 3)
	{
		_array= new  T[capacity];
			_size = 0;
		_capacity = 0; 
	}
	void Push(const T &  data)
	{
		_array[_size++] = data;
	}
	~Stack()
	{
		free(_array);
		_size = _capacity = 0;
	}
private :
	T * _array;
	int _size;
	int _capacity;
};
int main()
{
	Stack <int> s1(); // int 
	Stack <double> s2();//double 
	Stack <char> s3();//char
	//Stack <int ,doule> s2();


	return 0; 
}

类模板的定义格式

函数类模板的声明和定义分离

template<class T>


class Stack
{
public:
	//声明 
	Stack(int capacity );
	void Push(const T& data)
	{
		_array[_size++] = data;
	}
	~Stack()
	{
		free(_array);
		_size = _capacity = 0;
	}
private:
	T* _array;
	int _size;
	int _capacity;
};
//定义 
template<class T>
 Stack<T>::Stack(int capacity )
{
	_array = new  T[capacity];
	_size = 0;
	_capacity = 0;
}
int main()
{
	Stack <int> s1(); // int 
	Stack <double> s2();//double 
	Stack <char> s3();//char
	//Stack <int ,doule> s2();


	return 0;
}

对于普通类,类名和类型是一样的,但是对于类模板 ,类名和类型是不一样的 上面的代码中Stack是类名 ,但是Stack < T >是类型

类模板的实例化

string

在这里插入图片描述

一、string的定义方式

string();  //构造一个空字符串

string(const char* s);  //复制s所指的字符序列

string(const char* s, size_t n);  //复制s所指字符序列的前n个字符

string(size_t n, char c);  //生成n个c字符的字符串

string(const string& str);  //生成str的复制品

string(const string& str, size_t pos, size_t len = npos);  //复制str中从字符位置pos开始并跨越len个字符的部分

使用示例:

string s1;                     //构造空字符串
string s2("hello string");     //复制"hello string"
string s3("hello string", 3);  //复制"hello string"的前3个字符
string s4(10, 's');            //生成10个's'字符的字符串
string s5(s2);                 //生成s2的复制品
string s6(s2, 0, 4);           //复制s2中从字符位置0开始并跨越4个字符的部分

二、string的插入

在这里插入图片描述

使用push_back进行尾插

#include <iostream>
#include <string>
using namespace std;
int main()
{
	string s;
	s.push_back('C');
	s.push_back('X');
	s.push_back('Q');
	cout << s << endl; //CXQ
	return 0;
}

使用Insert插入
在这里插入图片描述

int main()
{
	string s("C");
	//insert(pos,str)在pos位置插入字符串str
	s.insert(1, "X");
	cout << s << endl;
	//insert(pos, string) ,在pos位置插入string对象 
	string t("Q");
	s.insert(2, t);
	cout << s << endl;
	//insert(pos, char)在pos位置插入char 
	s.insert(s.end(), 'A');
	cout << s << endl;
	return 0;
}

三、string的拼接
使用append函数完成string的拼接:

在这里插入图片描述

int main()
{
	string s1("A");
	string s2("B");
	//append(string)完成两个sting对象的拼接 
	s1.append(s2);
	
	cout << s1 << endl;
	

	//append(str)完成string对象和str字符串的拼接 
	s1.append("C");
	cout << s1 << endl;
	//append(n, char)将n个字符串拼接到string对象后面 
	s1.append(1, 'D');
	cout << s1 << endl;

	return 0;
}

四、string的删除

在这里插入图片描述

int main()
{
	string s("CXQ");
	s.pop_back();
	s.pop_back();
	cout << s << endl;

	return 0;
}

使用erase删除

在这里插入图片描述

int main()
{
	string s("ABCDEFG");
	//erase (pos , n )删除pos位置开始的n个字符
	s.erase(2, 1);
	cout << s << endl;//ABDEFG
	//erase(pos)删除pos位置的字符
	s.erase(s.end() - 1);
	cout << s << endl;
	 
	//erase(pos1, pos2)删除[pos1pos2)上所有字符
	s.erase(s.begin() + 1, s.end());
	cout << s << endl;

	return 0;
}

五、string的查找
1、使用find函数正向搜索第一个匹配项

在这里插入图片描述

int main()
{
	string s1("http://www.cplusplus.com/reference/string/string/find/");
	//find(string)正向搜索与string对象所匹配的第一个位置 
	string s2("www");
	size_t pos1 = s1.find(s2);
	cout << pos1 << endl;
	//find(str)正向搜索与str字符串所匹配的第一个位置 
	char str[] = "cplusplus.com";
	size_t pos2 = s1.find(str);
	cout << pos2 << endl;
	//find(char)正向搜索与char字符所匹配的第一个位置 
	size_t pos3 = s1.find('r');
	cout << pos3 << endl;
	return 0;

}

2、使用rfind函数反向搜索第一个匹配项

在这里插入图片描述

int main()
{
	string s1("http://www.cplusplus.com/reference/string/string/find/");
	//rfind反向搜索与string对象所匹配的第一个位置 
	string s2("string");
	size_t pos1 = s1.rfind(s2);
	cout << pos1 << endl;
	//rfind(str)反向搜索与字符串str所匹配的第一个位置
	char str[] = "reference";
	size_t pos2 = s1.rfind(str);
	cout << pos2 << endl;
	//rfind(char)反向搜索与字符char所匹配的第一个位置 
	size_t pos3 = s1.rfind('/');
	cout << pos3 << endl;
	return 0;
}

六、string的比较
使用compare函数完成比较:

比较规则:

1、比较字符串中第一个不匹配的字符值较小,或者所有比较字符都匹配,但比较字符串较短,则返回小于0的值。

 2、比较字符串中第一个不匹配的字符值较大,或者所有比较字符都匹配,但比较字符串较长,则返回大于0的值。

 3、比较的两个字符串相等,则返回0。
在这里插入图片描述

int main()
{
	string s1("hello world");
	string s2("hello Linux"); 
	cout << s1.compare(s2) << endl;//1
	//ell 与hello Linux 比较 
	cout << s1.compare(1, 3, s2) << endl;//-1
	//hello与hello比较
	cout << s1.compare(0, 4, s2, 0, 4) << endl;//0

	return 0;
}

注意:除了支持string类之间进行比较,compare函数还支持string类和字符串进行比较

七、string的替换
使用replace函数完成string的替换:

在这里插入图片描述

int main()
{
	string s("hello world");
	//replace(pos, len, str)将pos开始的len个字符替换成str 
    s.replace(6, 5, "Linux");//hello Linux 
	cout << s << endl;
	//replace(pos, len, n, char)将pos位置开始的len个字符替换成n个字符char 
	s.replace(10, 1, 3, '!');
	cout << s << endl;//hello Linu!!!
	return 0;

}

八、string的交换
使用swap函数完成两个string类的交换:

在这里插入图片描述

int main()
{
	string s1("hello");
	string s2("Linux");
	//使用string类的成员函数swap交换s1和s2
	s1.swap(s2);
	cout << s1 << endl;
	cout << s2 << endl;
	//使用非成员函数swap交换s1和s2
	swap(s1, s2);
	cout << s1 << endl;
	cout << s2 << endl;
	return 0;
}

九、string的大小和容量
1、使用size函数或length函数获取当前有效字符的个数

在这里插入图片描述

int main()
{
	string s("hello");
	cout << s.size() << endl;
	cout << s.length() << endl;
	return 0;
}

2、使用max_size函数获取string对象最多可包含的字符数

int main()
{
	string s("hello");
	cout << s.size() << endl;
	cout << s.length() << endl;
	cout << s.max_size() << endl;
	return 0;
}

3、使用capacity函数获取当前对象所分配的存储空间的大小
在这里插入图片描述

int main()
{
	string s("hello");
	cout << s.size() << endl;
	cout << s.length() << endl;
	cout << s.max_size() << endl;
	cout << s.capacity() << endl;
	return 0;
}

4、使用resize改变当前对象的有效字符的个数
在这里插入图片描述

resize规则:
 1、当n大于对象当前的size时,将size扩大到n,扩大的字符为c,若c未给出,则默认为’\0’。
 2、当n小于对象当前的size时,将size缩小到n。

int main()
{
	string s1("hello");
	s1.resize(30);
	cout << s1 << endl;
	//resize(n)n大于对象当前的size时,将size扩大到n,扩大的字符默认为'\0'
	cout << s1.capacity() << endl;
	cout << s1.size() << endl;
	

	string s2("ABCD");
	// resize(n, char)n大于对象当前的size时,将size扩大到n,扩大的字符为char
	s2.resize(20, 'x');
	cout <<s2<< endl; //ABCDxxxxxxxxxxxxxxxx
	cout << s2.size() << endl; //20
	cout << s2.capacity() << endl; //当前容量 


	string s3("ABCD");
	//resize(n)n小于对象当前的size时,将size缩小到n
	s3.resize(2);
	cout << s3 << endl;
	cout << s3.capacity() << endl;//当前容量
	cout << s3.size() << endl;//当前有效字符个数 


	return 0;
}

注意:若给出的n大于对象当前的capacity,则capacity也会根据自己的增长规则进行扩大。

5、使用reserve改变当前对象的容量大小

reserve规则:
 1、当n大于对象当前的capacity时,将capacity扩大到n或大于n。
 2、当n小于对象当前的capacity时,什么也不做。

int main()
{
	string s("ABCD");
	cout << s << endl;
	cout << s.size() << endl;//当前有效字符的个数 
	cout << s.capacity() << endl; //当前容量 

		//reverse(n)当n大于对象当前的capacity时,将当前对象的capacity扩大为n或大于n
	s.reserve(20);
	cout << s << endl;
	cout << s.size() << endl;//当前有效字符的个数 
	cout << s.capacity() << endl; //当前容量 

	// reverse(n)当n小于对象当前的capacity时,什么也不做
	s.reserve(2);
	cout << s << endl;
	cout << s.size() << endl;//当前有效字符的个数 
	cout << s.capacity() << endl; //当前容量 

	return 0;
}

注意:此函数对字符串的size没有影响,并且无法更改其内容

6、使用clear删除对象的内容,删除后对象变为空字符串
在这里插入图片描述

int main()
{
	string s("hello");
	cout << s << endl;
	s.clear();
	cout << s << endl;
	return 0;
}

7、使用empty判断对象是否为空
在这里插入图片描述

int main()
{
	string s("hello");
	cout << s << endl;
	cout << s.empty() << endl;//判断对象是否为空 
	s.clear();//删除对象里的内容,对象将变为空字符串 
	cout << s.empty() << endl;//判断对象是否为空 
	return 0;
}

十、string中元素的访问

在这里插入图片描述

1、[ ]+下标
 因为string类对[ ]运算符进行了重载,所以我们可以直接使用[ ]+下标访问对象中的元素。并且该重载使用的是引用返回,所以我们可以通过[ ]+下标修改对应位置的元素。

int main()
{
	string s("ABCD");
	//[]+下标访问对象元素
	for (size_t i =0; i < s.size(); i++)
	{
		cout << s[i] << endl;;
	}
	//[]+下标修改对象元素内容
	for (size_t i= 0; i < s.size(); i++)
	{
		s[i] = 'x';
	}
	cout << s << endl;
//	string s1("hello world");
//	char s3[] = "hello world";
//	s3[1]++; //  等价于*(s3+1)
//	s1[1]++; // 等价于s1.operator[](1);
	return 0;
}

2、使用at访问对象中的元素
 因为at函数也是使用的引用返回,所以我们也可以通过at函数修改对应位置的元素。

在这里插入图片描述

int main()
{
	string s("ABCD");
	for (size_t i = 0; i < s.size(); i++)
	{
		cout << s.at(i);
	}
	cout<< endl;
	for (size_t i = 0; i < s.size(); i++)
	{
		s.at(i) = 'x';
	}
	cout << s << endl;
	return 0;

}

3、使用范围for访问对象中的元素
 需要特别注意的是:若是需要通过范围for修改对象的元素,则用于接收元素的变量e的类型必须是引用类型,否则e只是对象元素的拷贝,对e的修改不会影响到对象的元素。

范围for底层替换为正向迭代器,范围for有局限 :范围for不能支持反向迭代器

正向迭代器 : iterator const_iterator(只能读)

在这里插入图片描述

反向迭代器: reverse_iterator 、const_reverse_iterator(只能读)

#include <iostream>
#include <string>
using namespace std;
int main()
{
	string s("CSDN");
	//使用范围for访问对象元素
	for (auto e : s)
	{
		cout << e;
	}
	cout << endl; //CSDN

	//使用范围for访问对象元素,并对其进行修改
	for (auto& e : s) //需要修改对象的元素,e必须是引用类型
	{
		e = 'x';
	}
	cout << s << endl; //xxxx
	return 0;
}

4、使用迭代器访问对象中的元素

int main()
{
	string s1("ABCD");
	//使用迭代器访问对象元素
	string::iterator it = s1.begin();
	while (it != s1.end())
	{
		cout << *it <<" ";
		++it; 
	}
	cout << endl;

	//使用迭代器访问对象元素,并对其进行修改
	string s2("QWER");
	string::iterator it2 = s2.begin();
	while (it2 != s2.end())
	{
		*it2 += 1;
		it2++;
	}
	cout << s2;
	return 0;

}

在这里插入图片描述

iterator 提供了一种统一的方式访问和修改容器的数据,算法可以通过迭代器处理容器中的数据

十一、string中运算符的使用
1、operator=
 string类中对=运算符进行了重载,重载后的=运算符支持string类的赋值、字符串的赋值以及字符的赋值。

int main()
{
	string s1;
	string s2("ABCD");
	//支持string类的赋值
	s1 = s2;
	cout << s1 << endl;
	//支持字符串的赋值
	s1 = "hello";
	cout << s1 << endl;
	//支持字符的赋值
	s1 = 'X';
	cout << s1 << endl;

	return 0;
}

2、operator+=
 string类中对+=运算符进行了重载,重载后的+=运算符支持string类的复合赋值、字符串的复合赋值以及字符复合的赋值。

int main()
{
	string s1;
	string s2("hello");
	//支持string类的复合赋值
	s1 += s2;
	cout << s1 << endl;
	//支持字符串的复合赋值
	s1 += " world";
	cout << s1 << endl;
	//支持字符的复合赋值
	s1 += "X";
	cout << s1 << endl;
	return 0;
}

3、operator+
 string类中对+运算符进行了重载,重载后的+运算符支持以下几种类型的操作:
 string类 + string类
 string类 + 字符串
 字符串 + string类
 string类 + 字符
 字符 + string类
它们相加后均返回一个string类对象。

int main()
{
	string s;
	string s1("ABCD");
	string s2("QWER");
	char str[] = "DFGH";
	char ch = '!';
	//string类 + string类
	s = s1 + s2;
	cout << s << endl;
	//string类 + 字符串
	s = s1 + str;
	cout << s << endl;
	//字符串 + string类
	s = str + s1;
	cout << s << endl;
	//string类 + 字符
	s = s1 + ch;
	cout << s << endl;
	//字符+string类
	s = ch + s1;
	cout << s << endl;
	return 0;
}

4、operator>> 和 operator<<

在这里插入图片描述

string类中也对>>和<<运算符进行了重载,这就是为什么我们可以直接使用>>和<<对string类进行输入和输出的原因。

int main()
{
	string s;
	cin >>s ;//输入
	cout << s;//输出 
	return 0;
}

5、relational operators
 string类中还对一系列关系运算符进行了重载,它们分别是==、!=、<、<=、>、>=。重载后的关系运算符支持string类和string类之间的关系比较、string类和字符串之间的关系比较、字符串和string类之间的关系比较。

int main()
{
	string s1("abcd");
	string s2("abde");
	cout << (s1 > s2) << endl; //0
	cout << (s1 < s2) << endl; //1
	cout << (s1 == s2) << endl; //0
	return 0;
}

注意:这些重载的关系比较运算符所比较的都是对应字符的ASCII码值。

十二、string中与迭代器相关的函数
1、与正向迭代器相关的函数
在这里插入图片描述

begin函数:返回一个指向字符串第一个字符的迭代器。

end函数:返回一个指向字符串结束字符的迭代器,即’\0’。
在这里插入图片描述

int main()
{
	string s("hello string");

	//正向迭代器
	string::iterator it1 = s.begin();
	while (it1 != s.end())
	{
		cout << *it1;
		it1++;
	}
	cout << endl;
	return 0;
}

2、与反向迭代器相关的函数
rbegin函数:返回指向字符串最后一个字符的反向迭代器。
在这里插入图片描述

rend函数:返回指向字符串第一个字符前面的理论元素的反向迭代器。
在这里插入图片描述

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

十三、string与字符串之间的转换
1、将字符串转换为string
 将字符串转换为string很简单,在前面讲string的定义方式时就有说到。

#include <iostream>
#include <string>
using namespace std;
int main()
{
	//方式一
	string s1("hello world");

	//方式二
	char str[] = "hello world";
	string s2(str);

	cout << s1 << endl; //hello world
	cout << s2 << endl; //hello world
	return 0;
}

2、使用c_str或data将string转换为字符串
在这里插入图片描述
区别:

在C++98中,c_str()返回 const char* 类型,返回的字符串会以空字符结尾。
在C++98中,data()返回 const char* 类型,返回的字符串不以空字符结尾。
但是在C++11版本中,c_str()与data()用法相同。

int main()
{
	//将string 转换为字符串 
	string s("hello world ");
	const char* str1 = s.data();
	const char* str2 = s.c_str();
	cout << str1 << endl;
	cout << str2 << endl;

	return 0;
}

十四、string中子字符串的提取
在这里插入图片描述

int main()
{
	string s1("abcdef");
	string s2;
	//substr(pos, n)提取pos位置开始的n个字符序列作为返回值
	s2 = s1.substr(2, 4);
	cout << s2 << endl;
	
	return 0;
}

2、使用copy函数将string的子字符串复制到字符数组中
在这里插入图片描述

int main()
{
	string s("abcdef");
	char str[20];
	//copy(str, n, pos)复制pos位置开始的n个字符到str字符串
	size_t lenth=s.copy(str, 4, 2);
	//copy函数不会在复制内容的末尾附加'\0',需要手动加
	str[lenth] = '\0';
	cout << str << endl;
	return 0;
}

十五、string中的getline函数
 我们知道,使用>>进行输入操作时,当>>读取到空格便会停止读取,基于此,我们将不能用>>将一串含有空格的字符串读入到string对象中。

这时,我们就需要用getline函数完成一串含有空格的字符串的读取操作了。
用法一:
在这里插入图片描述

getline函数将从istream中提取到的字符存储到str中,直到读取到换行符’\n’为止。

#include <iostream>
#include <string>
using namespace std;
int main()
{
	string s;
	getline(cin, s); //输入:hello CSDN
	cout << s << endl; //输出:hello CSDN
	return 0;
}

在这里插入图片描述
getline函数将从is中提取到的字符存储到str中,直到读取到分隔符delim或换行符’\n’为止。

int main()
{
	string s;
	getline(cin, s, 'D');
	cout << s << endl;
	return 0;
}

如果你觉得这篇文章对你有帮助,不妨动动手指给点赞收藏加转发,给鄃鳕一个大大的关注
你们的每一次支持都将转化为我前进的动力!!!

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

牛客网语法刷题篇(C语言) — 输出格式化

&#x1f929;本文作者&#xff1a;大家好&#xff0c;我是paperjie&#xff0c;感谢你阅读本文&#xff0c;欢迎一建三连哦。 &#x1f970;内容专栏&#xff1a;这里是《C语言—语法篇》专栏&#xff0c;笔者用重金(时间和精力)打造&#xff0c;基础知识一网打尽&#xff0c;…

解析Linux中断子系统之中断映射

中断是当前计算机系统的基础功能&#xff0c;也是系统响应外设事件的必备桥梁。不同的架构对中断控制器有不同的设计理念&#xff0c;本文针对ARM公司提供的通用中断控制器&#xff08;GIC,Generic Interrupt Controller&#xff09;介绍在linux系统中的硬件中断号与软件中断号…

SpringBootWeb登录认证

1. 登录功能 1.1 需求 在登录界面中&#xff0c;我们可以输入用户的用户名以及密码&#xff0c;然后点击 “登录” 按钮就要请求服务器&#xff0c;服务端判断用户输入的用户名或者密码是否正确。如果正确&#xff0c;则返回成功结果&#xff0c;前端跳转至系统首页面。 1.2 …

简单聊一聊数据库驱动

数据库驱动通常是数据库厂家提供的&#xff0c;他们按照jdbc协议对自家数据库封装了一套可对外调用的API。在应用程序和数据库之间起到了桥接的作用。它是一个软件组件&#xff0c;提供了与特定数据库系统进行通信的接口和功能。 1. 数据库驱动的作用&#xff1a; 连接数据库&…

AAOS 音频动态路由

文章目录 基本概念车载音频配置文件外部的配置音频区的方式车载音频服务配置路由流程框架中获取可用输出设备配置例子测试方法相关问题 基本概念 Android 管理来自 Android 应用的声音&#xff0c;同时控制这些应用&#xff0c;并根据其声音类型将声音路由到 HAL 中的输出设备…

FastAPi上传文件报错,There was an error parsing the body

问题描述 通过postman调用fastapi编写的文件接口报错&#xff0c;如下图&#xff1a; {"detail": "There was an error parsing the body" } 问题的解决过程 postman本身的问题 postman有个work directory的概念&#xff0c;所以再使用postman上传的文…

Git常用命令submodule

Git常用命令submodule 1、需求 当程序比较大参与开发人员较多时&#xff0c;代码管理就复杂起来。代码如果全员可见&#xff0c;可以创建 share 分支维护共用代 码&#xff0c;可以创建 core 分支维护核心算法代码&#xff0c;各进程分别占一个分支&#xff0c;定期同步 sha…

如何从 OpenAI 迁移到 Azure OpenAI(保姆级教程,包含如何兼容 JS 语言版 LangChain)

Azure OpenAI 和 OpenAI 一样&#xff0c;本质都是调用 api&#xff0c;Azure OpenAI 的使用会稍微复杂一点&#xff0c;但好处就是方便付费。 创建 Azure OpenAI 资源 首先&#xff0c;先登录 Azure 账号&#xff1a;https://azure.microsoft.com/zh-cn/ 接着创建 OpenAI 资…

硬件工程师-BOOST升压电源设计

一、Boost变换原理 开关闭合时&#xff0c;电感电压等于输入电压 开关断开时&#xff0c;电感电压输出电压-输入电压&#xff0c; 电感的感生电动势&#xff0c;N ΔΦ磁通的变化率&#xff0c;Δt时间 假设开关闭合与开关断开&#xff0c;开关断开时能量全部释放光 将第三个式…

MySQL(进阶篇1.0)

MySQL体系结构 1、连接层 最上层是一些客户端和连接服务&#xff0c;包含本地sock通信和大多数基于客户端/服务端工具实现的类似于TCP/IP的通信。主要完成一些类似于连接处理、授权认证、及相关安全方案。在该层上引入了线程池的概念&#xff0c;为通过认证安全接入的客户端提…

进程的通信方式有哪些?

目录 管道消息队列共享内存信号量信号套接字 管道 最初我们在学习Linux基本命令使用的时候&#xff0c;我们经常通过多个命令的组合来完成我们的需求。比如说我们想知道如何查看进程或者端口是否在使用&#xff0c;会使用下面的这条命令 netstat nlp | grep xxx 这里的"|“…

电子科技大学计算机系统结构复习笔记(四):存储系统

目录 前言 重点一览 Cache基本原理 三种映像方式 物理地址与Cache地址的映射计算 Cache块标识 Cache替换算法 Cache写策略 分离cache与一体cache Cache性能与优化 Cache性能计算 Cache性能优化 主存储器与虚拟存储器 主存储器性能优化 虚拟存储器 虚拟存储器与…

编译 ONNX 模型

本篇文章译自英文文档 Compile ONNX Models — tvm 0.13.dev0 documentation 作者是 Joshua Z. Zhang 更多 TVM 中文文档可访问 →TVM 中文站。 本文将介绍如何用 Relay 部署 ONNX 模型。 首先安装 ONNX 包&#xff0c;最便捷的方法推荐安装 protobuf 编译器&#xff1a; pi…

【资料分享】浪涌电流(Inrush Current)产生原因

1、对Inrush Current电流的直观感受 当电灯在电路中工作时&#xff0c;如果突然启动马达或者变压器时&#xff0c;会出现电灯暗一下&#xff0c;此时电灯出现暗的情况就是因为马达或者变压器启动时&#xff0c;在电路中产生较大Inrush Current&#xff0c;具体分析可以参考下图…

图解HTTP书籍学习

了解Web及网络基础 HTTP&#xff08;HyperText Transfer Protocol&#xff0c;超文本传输协议&#xff09; Web是建立在HTTP协议上通信的 把SGML&#xff08;Standard Generalized Markup Language&#xff0c;标准通用标记语言&#xff09; HTML&#xff08;HyperText Mar…

大数据:spark任务调度,DAGscheduler,Taskscheduler

大数据&#xff1a;spark任务调度 2022找工作是学历、能力和运气的超强结合体&#xff0c;遇到寒冬&#xff0c;大厂不招人&#xff0c;可能很多算法学生都得去找开发&#xff0c;测开 测开的话&#xff0c;你就得学数据库&#xff0c;sql&#xff0c;oracle&#xff0c;尤其s…

SpringBoot源码分析:SpringBoot自动装配(二)

一、概述 SpringBoot的启动流程入下图所示&#xff0c;它主要分为加载主启动类和解析启动类两个部分&#xff0c;我将从这两个部分分别开始介绍。 二、加载主启动类 首先点入SpringApplication.run方法 之后进入SpringApplication.prepareContext方法 之后进入SpringApplicat…

【JavaEE】简单前后端分离小项目-表白墙

plus版表白墙&#xff01;✿✿ヽ(▽)ノ✿ 文章目录 JavaEE & 简单前后端分离小项目 - 表白墙1. body格式约定 - 应用层协议2. 后端处理请求2.1 模板2.2 doGet方法2.3 doPost方法 3. 前端制作请求并解析响应3.1 原前端页面的代码3.2 刷新时发送GET请求3.3 点击发送时构造Pos…

40 KVM管理设备-配置磁盘IO悬挂

文章目录 40 KVM管理设备-配置磁盘IO悬挂40.1 总体介绍40.1.1 概述40.1.2 应用场景40.1.3 注意事项和约束限制 40.2 磁盘IO悬挂配置40.2.1 Qemu命令行配置40.2.2 xml配置方式 40 KVM管理设备-配置磁盘IO悬挂 40.1 总体介绍 40.1.1 概述 存储故障&#xff08;比如存储断链&am…

卡尔曼滤波与组合导航原理(三)连续随机系统的离散化与连续时间Kalman滤波

文章目录 一、连续时间系统方程离散化1、连续时间模型2、状态转移矩阵计算3、激励噪声的等效计算4、最终离散化结论5、常见简单随机过程离散化6、实际物理信号的噪声单位 二、连续时间量测方程离散化三、连续时间Kalman滤波1、连续状态空间模型2、离散时间Kalman滤波3、增益矩阵…