【C++游记】string的使用和模拟实现

news2024/12/14 5:33:52

 

枫の个人主页

你不能改变过去,但你可以改变未来

算法/C++/数据结构/C

Hello,这里是小枫。C语言与数据结构和算法初阶两个板块都更新完毕,我们继续来学习C++的内容呀。C++是接近底层有比较经典的语言,因此学习起来注定枯燥无味,西游记大家都看过吧~,我希望能带着大家一起跨过九九八十一难,降伏各类难题,学会C++,我会尽我所能,以通俗易懂、幽默风趣的方式带给大家形象生动的知识,也希望大家遇到困难不退缩,遇到难题不放弃,学习师徒四人的精神!!!故此得名【C++游记】

 话不多说,让我们一起进入今天的学习吧~~~ 

目录

1>>标准库的String

1.1>>auto和范围for小知识

1.2>>string常用接口(组件)这里都可以查找到

容量接口

访问和遍历

 string类对象的修改操作

非成员函数但会用到 

2>>string的模拟实现

 3>>Boos战——string重要接口的模拟实现

1.String.h

2.String.cpp 

3.wctest.cpp

4>>结语


1>>标准库的String

1.1>>auto和范围for小知识

师傅别怕,赠与“武器”一把 i

auto基本知识:

它声明引用类型时,必须在auto后加上&。

声明多个变量时,这些变量必须是相同的类型。

auto不能作为函数参数,可以作为返回值。

不能用于声明数组。

#include<iostream>
using namespace std;
int main() {
	auto a = 10;
	auto b = 'b';
	auto c = "asdofih";
	auto d = 11.11;
	auto& e = a;
	cout << a << endl;
	cout << b << endl;
	cout << c << endl;
	cout << d << endl;
	cout << e << endl;
	printf("%p %p", &a, &e);
	return 0;
}

范围for:

        对比C语言的for循环,C++使用更好用的范围for代替, 格式为:“for(auto  范围内用于迭代的变量 : 被迭代的范围)”,自动迭代、取数据、结束,这就是自动范围for。

#include<iostream>
using namespace std;
int main() {
	int arr[] = { 1,2,3,4,5 };
	for (auto& e : arr) {//若要更改里面的数值,那么就要用引用才能修改到数组本身
		e += 2;
	}
	for (auto e : arr) {
		cout << e << " ";
	}
	cout << endl;
	string str("hello world");
	for (auto ch : str) {
		cout << ch << " ";
	}
	cout << endl;
	return 0;
}

1.2>>string常用接口(组件)这里都可以查找到

师傅后面都会介绍,不必担心

String函数名称功能说明
string()构造空的string类对象,即空字符串
string(const char* s)用C-string(常量字符串)来构造string类对象
string(size_t n,char c)

string类对象中包含n个字符c

string(const string&s)

拷贝构造函数
void Test1() {
	string s1;//构造空的string类对象
	string s2("hello feng");//用常量字符串构造string类对象
	string s3(s2);//用s2拷贝构造s3
}

容量接口

若定义为string s,以下表size为例,就是s.size();

size返回字符串有效字符长度,使用范围比length广
length返回字符串有效字符长度
capacity返回总空间大小
empty检测字符串释放为空串,空返回true,非空返回false
clear清空有效字符
reserve为字符串预留空间
resize将有效字符个数设置为n个,多余用c填充

补充说明:size和length的区别只有在引入迭代器才能体现出来,一般都用size,length有使用限制。

clear只清空,不改大小

resize(size_t n,char c)用变量c的字符填充多余空间,resize(size_t)则是用0来填充。

reserve预留空间,小于string的空间大小时不作改动。

访问和遍历

函数名称功能说明
operator[]返回pos位置的字符,const string类对象调用
begin+endbegin获取一个字符的迭代器+end获取最后一个字符下一个位置的迭代器
rbegin+rendrbegin获取最后一个字符的迭代器+rend获取一个字符的迭代器
范围forC++11的遍历方式

 string类对象的修改操作

函数名称

功能说明

push_back在字符串后尾插字符c(单个)
append在字符串后追加一个字符串(多个)
operator+=在字符串后追加一个字符串(多个)
c_str返回C格式字符串
find+npos从字符串pos位置往后查找字符c,返回它的位置
rfind从字符串pos位置往前查找字符c,返回它的位置
substr在str中从pos位置开始,截取n个字符,将其返回

非成员函数但会用到 

函数       功能说明       
operator+深拷贝,效率低
operator>>输入运算符重载
operator<<输出运算符重载
getline获取一行字符串
relational operators大小比较

2>>string的模拟实现

错误示范:

#include<iostream>
#include<assert.h>
using namespace std;
class MyString {
public:
	MyString(const char* str = "") {
		if (str == nullptr) {
			perror("flase");
			return;
		}
		_str = new char[strlen(str) + 1];//加1放\0
		strcpy(_str, str);
	}
	~MyString() {
		if (_str) {
			delete[] _str;
			_str = nullptr;
		}
	}
private:
	char* _str;
};
void Test2() {
	string s1("hello feng");
	string s2(s1);
}

int main() {
	/*Test1();*/
	Test2();
	return 0;
}

上述过程会报错,因为没有写拷贝构造,s2会调用s1的默认构造,而在类和对象章节中我们知道默认构造都是浅拷贝,这里是一个字符数组,因此要调用深拷贝。

#include<iostream>
#include<assert.h>
using namespace std;
class MyString {
public:
	MyString(const char* str = "") {//构造
		if (str == nullptr) {
			perror("flase");
			return;
		}
		_str = new char[strlen(str) + 1];//加1放\0
		strcpy(_str, str);
	}
	MyString(const MyString& s)//拷贝构造
		:_str(nullptr)
	{
		MyString tmp(s._str);
		swap(tmp._str, _str);
	}
	~MyString() {//析构
		if (_str) {
			delete[] _str;
			_str = nullptr;
		}
	}
private:
	char* _str;
};
void Test2() {
	string s1("hello feng");
	string s2(s1);
}

int main() {
	/*Test1();*/
	Test2();
	return 0;
}

 3>>Boos战——string重要接口的模拟实现

这里直接附上上个文件源码,大部分已经注释完毕,请大家伙享用,感兴趣可以复制过去测试,不过还是自己敲一遍比较好。

1.String.h

#pragma once

#include<iostream>
#include<assert.h>
#include<string.h>
using namespace std;

namespace wc
{
	class string
	{
	public:
		typedef char* iterator;//手动自造迭代器,名字与库中相同,但在wc的命名空间里
		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;
		}

		void swap(string& s);//交换,直接套用标准库里的swap

		string(size_t n, char ch);//设置相同字符多少个为一个字符串
		
		string(const char* str = "");//构造函数

		string(const string& s);//拷贝构造函数
		
		~string();//析构函数
		void clear()//清除
		{
			_str[0] = '\0';
			_size = 0;
		}

		string& operator=(string s);//string& operator=(const string& s);

		const char* c_str() const//常数直接返回自己地址,比较快因此调用内联
		{
			return _str;
		}

		void reserve(size_t n);//保存,为字符串预留空间
		void push_back(char ch);//类似于尾插
		void append(const char* str);//尾插一个字符串
		string& operator+=(char ch);//类似于尾插
		string& operator+=(const char* str);//尾插一个字符串

		void insert(size_t pos, size_t n, char ch);//在pos位置插入n个ch字符
		void insert(size_t pos, const char* str);//在pos位置插入一个字符串
		void erase(size_t pos = 0, size_t len = npos);//在pos位置删除len个字符

		size_t find(char ch, size_t pos = 0);
		size_t find(const char* str, size_t pos = 0);

		size_t size() const
		{
			return _size;
		}

		size_t capacity() const
		{
			return _size;
		}

		char& operator[](size_t pos)
		{
			assert(pos < _size);
			return _str[pos];
		}

		const char& operator[](size_t pos) const
		{
			assert(pos < _size);
			return _str[pos];
		}

		string substr(size_t pos, size_t len = npos);//从pos位置开始取len个作为子串返回

		bool operator==(const string& s) const;
		bool operator!=(const string& s) const;
		bool operator<(const string& s) const;
		bool operator<=(const string& s) const;
		bool operator>(const string& s) const;
		bool operator>=(const string& s) const;
	private:
		char* _str = nullptr;//定义字符串数组_str
		size_t _size = 0;//有效个数
		size_t _capacity = 0;//总容量
		const static size_t npos;//设置默认结束值
	};

	// cout<<s1
	ostream& operator<<(ostream& out, const string& s);
	// cin>>s1
	istream& operator>>(istream& in, string& s);

	istream& getline(istream& is, string& s, char delim = '\n');

	void test_string1();
	void test_string2();
	void test_string3();
	void test_string4();
	void test_string5();
	void test_string6();
	void test_string7();
}

2.String.cpp 

//#include<iostream>
//using namespace std;
//int main() {
//	auto a = 10;
//	auto b = 'b';
//	auto c = "asdofih";
//	auto d = 11.11;
//	auto& e = a;
//	cout << a << endl;
//	cout << b << endl;
//	cout << c << endl;
//	cout << d << endl;
//	cout << e << endl;
//	printf("%p %p", &a, &e);
//	return 0;
//}
//#include<iostream>
//using namespace std;
//int main() {
//	int arr[] = { 1,2,3,4,5 };
//	for (auto& e : arr) {//若要更改里面的数值,那么就要用引用才能修改到数组本身
//		e += 2;
//	}
//	for (auto e : arr) {
//		cout << e << " ";
//	}
//	cout << endl;
//	string str("hello world");
//	for (auto ch : str) {
//		cout << ch << " ";
//	}
//	cout << endl;
//	return 0;
//}

//void Test1() {
//	string s1;//构造空的string类对象
//	string s2("hello feng");//用常量字符串构造string类对象
//	string s3(s2);//用s2拷贝构造s3
//}
//#include<iostream>
//#include<assert.h>
//using namespace std;
//class MyString {
//public:
//	MyString(const char* str = "") {//构造
//		if (str == nullptr) {
//			perror("flase");
//			return;
//		}
//		_str = new char[strlen(str) + 1];//加1放\0
//		strcpy(_str, str);
//	}
//	MyString(const MyString& s)//拷贝构造
//		:_str(nullptr)
//	{
//		MyString tmp(s._str);
//		swap(tmp._str, _str);
//	}
//	~MyString() {//析构
//		if (_str) {
//			delete[] _str;
//			_str = nullptr;
//		}
//	}
//private:
//	char* _str;
//};
//void Test2() {
//	string s1("hello feng");
//	string s2(s1);
//}
//
//int main() {
//	/*Test1();*/
//	Test2();
//	return 0;
//}

#define _CRT_SECURE_NO_WARNINGS 1
#include"string.h"

namespace wc
{
	const size_t string::npos = -1;

	void string::swap(string& s)
	{
		std::swap(_str, s._str);
		std::swap(_size, s._size);
		std::swap(_capacity, s._capacity);
	}

	string::string(size_t n, char ch)
		:_str(new char[n + 1])
		, _size(n)
		,_capacity(n)
	{
		for (size_t i = 0; i < n; i++) {
			_str[i] = ch;
		}
		_str[_size] = '\0';
	}

	string::string(const char* str)//声明中写过默认值,这里就不能再写了 
		:_size(strlen(str))
	{
		_capacity = _size;
		_str = new char[_size + 1];
		strcpy(_str, str);//复制还没复制\0
		_str[_size] = '\0';
	}

	string::string(const string& s)
	{
		string tmp(s._str);
		swap(tmp);
	}

	string::~string()
	{
		delete[] _str;
		_str = nullptr;
		_size = 0;
		_capacity = 0;
	}
	string& string::operator=(string s) 
	{
		swap(s);
		return *this;
	}

	void string::reserve(size_t n) {//预留空间
		if (n > _capacity) {//大于就扩容
			char* tmp = new char[n + 1];
			strcpy(tmp, _str);
			delete[] _str;
			_str = tmp;
			_capacity = n;
		}
	}

	void string::push_back(char ch) {
		if (_size + 1 > _capacity) {//大于就扩容
			reserve(_capacity == 0 ? 4 : _capacity * 2);//预留空间刚写就能用
		}
		_str[_size] = ch;
		_size++;
		_str[_size] = '\0';
	}
	void string::append(const char* str) {
		size_t len = strlen(str);
		if (_size + len > _capacity) {
			reserve(_size + len);
		}
		strcpy(_str + _size, str);
		_size += len;
	}

	string& string::operator+=(char ch)
	{
		push_back(ch);
		return *this;
	}

	string& string::operator+=(const char* str)
	{
		append(str);
		return *this;
	}

	void string::insert(size_t pos, size_t n, char ch)
	{
		assert(pos <= _size);
		assert(n > 0);

		if (_size + n > _capacity)
		{
			// 扩容
			size_t newCapacity = 2 * _capacity;
			if (_size + n > 2 * _capacity)
			{
				newCapacity = _size + n;
			}

			reserve(newCapacity);
		}

		size_t end = _size + n;
		while (end > pos + n - 1) {
			_str[end] = _str[end - n];
			end--;
		}
		for (size_t i = 0; i < n; i++) {
			_str[pos + i] = ch;
		}
		_size += n;
	}

	void string::insert(size_t pos, const char* str)
	{
		size_t n = strlen(str);
		insert(pos, n, 'x');//覆盖一下
		for (size_t i = 0; i < n; i++)
		{
			_str[pos + i] = str[i];
		}
	}

	void string::erase(size_t pos, size_t len) {
		if (len > _size - pos) {//多删了
			_str[pos] = '\0';
			_size = pos;
		}
		else {
			size_t end = pos + len;
			while (end <= _size) {//\0也拷贝
				_str[end - len] = _str[end];
				end++;
			}
			_size -= len;
		}
	}

	size_t string::find(char ch, size_t pos)
	{
		for (size_t i = pos; i < _size; i++)
		{
			if (_str[i] == ch)
			{
				return i;
			}
		}

		return npos;
	}

	size_t string::find(const char* str, size_t pos)
	{
		const char* p = strstr(_str + pos, str);
		if (p == nullptr)
		{
			return npos;
		}
		else
		{
			return p - _str;
		}
	}

	string string::substr(size_t pos, size_t len)
	{
		if (len > _size - pos)//若超出,就等于剩下长度
			len = _size - pos;
		
		string tmp;
		tmp.reserve(len);
		for (size_t i = 0; i < len; i++) {
			tmp += _str[pos + i];//直接加等,简单易懂
		}
		return tmp;
	}

	bool string::operator==(const string& s) const
	{
		return strcmp(_str, s._str) == 0;
	}

	bool string::operator!=(const string& s) const
	{
		return !(*this == s);
	}

	bool string::operator<(const string& s) const
	{
		return strcmp(_str, s._str) < 0;
	}

	bool string::operator<=(const string& s) const
	{
		return *this < s || *this == s;
	}

	bool string::operator>(const string& s) const
	{
		return !(*this <= s);
	}

	bool string::operator>=(const string& s) const
	{
		return !(*this < s);
	}


	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();

		// 输入短串,不会浪费空间
		// 输入长串,避免不断扩容
		const size_t N = 1024;
		char buff[N];
		int i = 0;
		char ch = in.get();
		while (ch != ' ' && ch != '\n')//遇到空格和\n停止
		{
			buff[i++] = ch;
			if (i == N - 1)
			{
				buff[i] = '\0';//最后一个复制为0然后加上
				s += buff;
				i = 0;
			}
			//也可以直接写s+=ch,不过占用内存高
			ch = in.get();
		}

		if (i > 0)
		{
			buff[i] = '\0';
			s += buff;
		}

		return in;
	}

	istream& getline(istream& in, string& s, char delim)
	{
		s.clear();

		const size_t N = 1024;
		char buff[N];
		int i = 0;
		char ch = in.get();
		while (ch != delim)
		{
			buff[i++] = ch;
			if (i == N - 1)
			{
				buff[i] = '\0';
				s += buff;
				i = 0;
			}

			ch = in.get();
		}

		if (i > 0)
		{
			buff[i] = '\0';
			s += buff;
		}

		return in;
	}

	void test_string1()
	{
		string s1("hello world");
		cout << s1.c_str() << endl;

		string s2;
		cout << s2.c_str() << endl;

		s1 += ' ';
		s1 += '+';
		s1 += "hello ";
		s1 += "hello feng1111111111111111111111111";
		cout << s1.c_str() << endl;
	}

	void test_string2()
	{
		string s1("hello world");
		cout << s1.c_str() << endl;

		s1.insert(11, 3, 'x');
		cout << s1.c_str() << endl;

		s1.insert(6, 3, 'x');
		cout << s1.c_str() << endl;

		s1.insert(0, 3, 'x');
		cout << s1.c_str() << endl;

		string s2("hello world");
		cout << s2.c_str() << endl;

		s2.insert(11, "yyy");
		cout << s2.c_str() << endl;

		s2.insert(6, "yyy");
		cout << s2.c_str() << endl;

		s2.insert(0, "yyy");
		cout << s2.c_str() << endl;
	}

	void test_string3()
	{
		string s1("hello world");
		cout << s1.c_str() << endl;

		s1.erase(6, 2);
		cout << s1.c_str() << endl;

		s1.erase(6, 20);
		cout << s1.c_str() << endl;

		s1.erase(3);
		cout << s1.c_str() << endl;

		string s2("hello helleoo");
		cout << s2.find('e') << endl;
		cout << s2.find("helle") << endl;
	}

	void test_string4()
	{
		string s1("hello world");
		for (size_t i = 0; i < s1.size(); i++)
		{
			s1[i]++;
			cout << s1[i] << " ";
		}
		cout << endl;

		string::iterator it = s1.begin();
		while (it != s1.end())
		{
			cout << *it << " ";
			++it;
		}
		cout << endl;

		for (auto e : s1)
		{
			cout << e << " ";
		}
		cout << endl;

		const string s2("hello world");
		for (auto e : s2)
		{
			cout << e << " ";
		}
		cout << endl;
	}

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

		string sub1 = s1.substr(6, 3);
		cout << sub1.c_str() << endl;

		string sub2 = s1.substr(6, 300);
		cout << sub2.c_str() << endl;

		string sub3 = s1.substr(6);
		cout << sub3.c_str() << endl;

		string s2("hello fengxxxxxxxxxxxxxxxxxx");
		s1 = s2;
		cout << s1.c_str() << endl;
		cout << s2.c_str() << endl;

		s1 = s1;
		cout << s1.c_str() << endl;
	}

	void test_string6()
	{
		/*string s1("hello world");
		string s2("hello bit");

		cout << s1 << endl;
		cout << s2 << endl;

		string s3;
		cin >> s3;
		cout << s3 << endl;*/

		string s1, s2;
		cin >> s1 >> s2;
		cout << s1 << endl;
		cout << s2 << endl;

		string s3;
		//getline(cin, s3);
		getline(cin, s3, '!');
		cout << s3 << endl;
	}

	void test_string7()
	{
		string s1("1111111111111");
		string s2(s1);
		cout << s1 << endl;
		cout << s2 << endl;

		string s3("222222222222222222222222222");
		s1 = s3;
		cout << s1 << endl;
		cout << s3 << endl;

		//s1.swap(s2);
		//swap(s1, s2);
		cout << s1 << endl;
		cout << s2 << endl;
	}
}

3.wctest.cpp

#include"string.h"

int main()
{
	//wc::test_string1();
	//wc::test_string3();
	wc::test_string5();

	return 0;
}

4>>结语

        今日C++到这里就结束啦,如果觉得文章还不错的话,可以三连支持一下。感兴趣的宝子们欢迎持续订阅小枫,小枫在这里谢谢宝子们啦~小枫の主页还有更多生动有趣的文章,欢迎宝子们去点评鸭~C++的学习很陡,时而巨难时而巨简单,希望宝子们和小枫一起坚持下去~你们的三连就是小枫的动力,感谢支持~

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

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

相关文章

【深度学习量化交易7】miniQMT快速上手教程案例集——使用xtQuant进行历史数据下载篇

我是Mr.看海&#xff0c;我在尝试用信号处理的知识积累和思考方式做量化交易&#xff0c;应用深度学习和AI实现股票自动交易&#xff0c;目的是实现财务自由~ 目前我正在开发基于miniQMT的量化交易系统。 在前几篇的文章中讲到&#xff0c;我正在开发的看海量化交易系统&#x…

相差不超过k的最多数,最长公共子序列(一),排序子序列,体操队形,青蛙过河

相差不超过k的最多数 链接:相差不超过k的最多数 来源&#xff1a;牛客网 题目描述&#xff1a; 给定一个数组&#xff0c;选择一些数&#xff0c;要求选择的数中任意两数差的绝对值不超过 &#x1d458; 。问最多能选择多少个数&#xff1f; 输入描述: 第一行输入两个正整…

解决navicat 导出excel数字为科学计数法问题

一、原因分析 用程序导出的csv文件&#xff0c;当字段中有比较长的数字字段存在时&#xff0c;在用excel软件查看csv文件时就会变成科学技术法的表现形式。 其实这个问题跟用什么语言导出csv文件没有关系。Excel显示数字时&#xff0c;如果数字大于12位&#xff0c;它会自动转化…

C++3--内联函数、auto

1.内联函数 1.1概念 以inline修饰的函数叫做内联函数&#xff0c;编译时C编译器会在调用内联函数的地方展开&#xff0c;没有函数调用建立栈帧的开销&#xff0c;内联函数提升程序的效率 如果在上述函数前增加inline关键字将其改成内联函数&#xff0c;在编译期间编译器会用函…

AES 与 SM4 加密算法:深度解析与对比

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家&#xff0c;历代文学网&#xff08;PC端可以访问&#xff1a;https://literature.sinhy.com/#/literature?__c1000&#xff0c;移动端可微信小程序搜索“历代文学”&#xff09;总架构师&#xff0c;15年工作经验&#xff0c;…

视频怎么转音频mp3?5种视频转音频的方法

在视频剪辑时&#xff0c;将视频中的音频提取出来并转换为MP3格式已成为许多人的需求。无论是为了制作音乐播放列表、剪辑音频片段&#xff0c;还是为了在其他设备上更方便地播放&#xff0c;将视频转换为音频MP3都显得尤为重要。下面将介绍五种实用的方法&#xff0c;帮助你轻…

Maven学习(传统Jar包管理、Maven依赖管理(导入坐标)、快速下载指定jar包)

目录 一、传统Jar包管理。 &#xff08;1&#xff09;基本介绍。 &#xff08;2&#xff09;传统的Jar包导入方法。 1、手动寻找Jar包。并放置到指定目录下。 2、使用IDEA的库管理功能。 3、配置环境变量。 &#xff08;3&#xff09;传统的Jar包管理缺点。 二、Maven。 &#…

【机器学习】分类器

在机器学习(Machine Learning&#xff0c;ML)中&#xff0c;分类器泛指算法或模型&#xff0c;用于将输入数据分为不同的类别或标签。分类器是监督学习的一部分&#xff0c;它依据已知的数据集中的特征和标签进行训练&#xff0c;并根据这些学习到的知识对新的未标记数据进行分…

uni-app在image上绘制点位并回显

在 Uni-app 中绘制多边形可以通过使用 Canvas API 来实现。Uni-app 是一个使用 Vue.js 开发所有前端应用的框架&#xff0c;同时支持编译为 H5、小程序等多个平台。由于 Canvas 是 H5 和小程序中都支持的 API&#xff0c;所以通过 Canvas 绘制多边形是一个比较通用的方法。 1.…

【机器学习与数据挖掘实战】案例01:基于支持向量回归的市财政收入分析

【作者主页】Francek Chen 【专栏介绍】 ⌈ ⌈ ⌈机器学习与数据挖掘实战 ⌋ ⌋ ⌋ 机器学习是人工智能的一个分支&#xff0c;专注于让计算机系统通过数据学习和改进。它利用统计和计算方法&#xff0c;使模型能够从数据中自动提取特征并做出预测或决策。数据挖掘则是从大型数…

Spire.PDF for .NET【页面设置】演示:向 PDF 文档添加页码

在 PDF 文档中添加页码不仅实用&#xff0c;而且美观&#xff0c;因为它提供了类似于专业出版材料的精美外观。无论您处理的是小说、报告还是任何其他类型的长文档的数字副本&#xff0c;添加页码都可以显著提高其可读性和实用性。在本文中&#xff0c;您将学习如何使用Spire.P…

【iOS】OC高级编程 iOS多线程与内存管理阅读笔记——自动引用计数(三)

目录 ARC规则 概要 所有权修饰符 __strong修饰符 __weak修饰符 __unsafe_unretained修饰符 __autoreleasing修饰符 ARC规则 概要 “引用计数式内存管理”的本质部分在ARC中并没有改变&#xff0c;ARC只是自动地帮助我们处理“引用计数”的相关部分。 在编译单位上可以…

An error happened while trying to locate the file on the Hub and we cannot f

An error happened while trying to locate the file on the Hub and we cannot find the requested files in the local cache. Please check your connection and try again or make sure your Internet connection is on. 关于上述comfy ui使用control net预处理器的报错问…

angular19-官方教程学习

周日了解到angular已经更新到19了&#xff0c;想按官方教程学习一遍&#xff0c;工欲善其事必先利其器&#xff0c;先更新工具&#xff1a; 安装新版版本 卸载老的nodejs 20.10.0&#xff0c;安装最新的LTS版本 https://nodejs.org 最新LTS版本已经是22.12.0 C:\Program File…

计算机毕业设计Python+Vue.js游戏推荐系统 Steam游戏推荐系统 Django Flask 游 戏可视化 游戏数据分析 游戏大数据 爬虫 机

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…

上海亚商投顾:创业板指震荡调整 机器人概念股再度爆发

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。 一.市场情绪 沪指昨日冲高回落&#xff0c;深成指、创业板指盘中跌超1%&#xff0c;尾盘跌幅有所收窄。机器人概念股逆势爆…

粘贴可运行:Java调用大模型(LLM) 流式Flux stream 输出;基于spring ai alibaba

在Java中&#xff0c;使用Spring AI Alibaba框架调用国产大模型通义千问&#xff0c;实现流式输出&#xff0c;是一种高效的方式。通过Spring AI Alibaba&#xff0c;开发者可以轻松地集成通义千问模型&#xff0c;并利用其流式处理能力&#xff0c;实时获取模型生成的文本。这…

【CSS in Depth 2 精译_070】11.3 利用 OKLCH 颜色值来处理 CSS 中的颜色问题(下):从页面其他颜色衍生出新颜色

当前内容所在位置&#xff08;可进入专栏查看其他译好的章节内容&#xff09; 第四部分 视觉增强技术 ✔️【第 11 章 颜色与对比】 ✔️ 11.1 通过对比进行交流 11.1.1 模式的建立11.1.2 还原设计稿 11.2 颜色的定义 11.2.1 色域与色彩空间11.2.2 CSS 颜色表示法 11.2.2.1 RGB…

Ajax--实现检测用户名是否存在功能

目录 &#xff08;一&#xff09;什么是Ajax &#xff08;二&#xff09;同步交互与异步交互 &#xff08;三&#xff09;AJAX常见应用情景 &#xff08;四&#xff09;AJAX的优缺点 &#xff08;五&#xff09;使用jQuery实现AJAX 1.使用JQuery中的ajax方法实现步骤&#xf…

【PSINS】以速度和位置作为观测量(即6维观测量)的组合导航滤波,EKF实现,提供可直接运行的MATLAB代码

原有的代码是以位置作为观测量的,这里提供位置+速度,共6维的观测量,状态量还是15维不变 文章目录 源代码运行结果PS源代码 源代码如下: % 【PSINS】位置与速度为观测的153,EKF。从速度观测的EKF153改进而来 % 2024-12-11/Ver1:位置与速度为观测量% 清空工作空间,清除命…