C++string类重要函数模拟实现

news2024/11/16 10:28:24

为了和C++标准库区分,以下代码除主函数外均在namespace空间

目录

一.成员

二、带参构造函数

三、拷贝构造函数和赋值运算符重载

四、析构函数

 五、重要成员函数实现

1. c_str函数

2. operator[]重载

3. size函数和capacity函数

4.reverse函数

5. push_back和append函数

6. operator+=重载

7. insert函数

8. erase函数 

9. clear函数 

10.resize函数 

11.find函数 

12.substr函数 

六、迭代器

七、全局函数

1.operator判断符重载

2.流输入和流输出运算符重载


一.成员

首先一定要有个字符指针 _str,指向所存放的字符串。

还需要有字符串的大小_size,能够快速的知道这个字符串多大。

再需要有字符串的容量_capacity,知道字符串追加后是否需要扩容。

因此我们定义

class string
{
private:
    char* _str;
    size_t _size;
    size_t _capacity;   
}

二、带参构造函数

构造函数使用的是字符串来构造,并且给缺省值  ""  ,注意里面没有空格,为了能够进行默认构造,并且这是一个字符串,虽然没有给到什么内容,但会存放一个'\0'。

_size和_capacity的大小就是str的长度。

_str需要使用new来开辟空间,开辟空间的大小是_capacity+1,因为之前strlen(str)算出来的长度都没有算'\0',因此你需要多开辟一个空间来存放'\0';

string(const char* str = "")
	:_size(strlen(str))
	,_capacity(_size)
    {
		_str = new char[_capacity + 1];
		strcpy(_str, str);
	}

三、拷贝构造函数和赋值运算符重载

为了实现深拷贝,就需要自己写拷贝构造和赋值运算符重载。

这里的拷贝构造函数和赋值我们选用了很简单的写法,使用带参构造函数构造出一个临时的类对象tmp,这个tmp对象的值正好是当前对象需要的,因此将他们两个交换一下,当前对象就完成了深拷贝了,同时tmp也会出了作用域也会自动调用析构函数进行析构(析构函数马上就写)。

赋值运算符重载也是利用的这种思想,甚至更加简单粗暴,不用为了节约而传 const string& s了,直接传string  tmp,这样会调用一次拷贝构造,我要的就是拷贝出来的临时对象跟我互换,换了之后返回*this 即可

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

string(const string& s)
	:_str(nullptr)
	,_size(0)
	,_capacity(0)			//保证编译器一定初始化,析构才不会出错
{
	string tmp(s._str);
	swap(tmp);
}
string& operator=(string tmp)
{
	swap(tmp);
	return *this;
}

四、析构函数

析构函数非常简单,只需要将_str里面的内容delete掉即可,注意是需要delete[] ,顺便将_str置空, _size  和 _capacity赋值给0。

~string()
{
	delete[] _str;
	_str = nullptr;
	_size = _capacity = 0;
}

 五、重要成员函数实现

1. c_str函数

c_str()是将string类对象转化为字符串的格式,方便我们打印操作.

代码只需返回_str即可。

const char* c_str() const
{
	return this->_str;
}

2. operator[]重载

为了让string类对象像数组一样访问,我们需要重载 [] 

代码也很简单。这里写了两个版本,一个普通版一个const版,这为了让普通对象调用可以修改,const类对象的调用不能修改

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

 3. size函数和capacity函数

让类外访问到private成员_size和_capacity的值。

size_t size() const 
{
	return _size;
}
size_t capacity() const
{
	return _capacity;
}

 4.reverse函数

reverse是扩容,如果n比_capacity小就不管,比_capacity打就按照n的大小来扩容。

流程为开辟空间,拷贝数据,释放空间,指向新空间,_capacity变为0

void reverse(size_t n)
{
	if (n > _capacity)
	{
		char* tmp = new char[n+1];//要多开一个留给'\0'
		strcpy(tmp, _str);
		if(_str!=nullptr)
			delete[] _str;
		_str = tmp;
		_capacity = n;
	}
}

5. push_back和append函数

push_back是在尾部插入一个字符,插入之前判断空间是否足够,不足就扩容再插入,_size需要++,注意后面要置为'\0'。

append是在尾部插入一个字符串,依然要判断是否扩容,使用了库函数来进行拷贝,strcpy会拷贝'\0',因此无需关心'\0',将_size+=len即可

void push_back(char ch)
{
	if (_size == _capacity)
	{
		reverse(_capacity == 0 ? 4 : 2 * _capacity);
	}
	_str[_size] = ch;
	_size++;
	_str[_size] = '\0';
}
void append(const char* str)
{
	size_t len = strlen(str);
	if (_size + len > _capacity)
	{
		reverse(_size + len);
	}
	strcpy(_str + _size, str);
	_size += len;
}

 6. operator+=重载

使用+=比push_back和append爽的多,还不需要关心是字符还是字符串,因为我们运算符重载加函数重载了。

代码部分分别调用即可。

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

 7. insert函数

insert函数运用了重载,可以在你想要的位置插入字符和字符串。

他的主要思想是从后往前遍历,并且将数据往后面挪动,直到到了pos位置才会停止,然后将要插入的字符或者字符串放在pos位置即可。

只需要注意字符移动一格,字符串移动len格。

void insert(size_t pos,char ch)
{
	assert(pos <= _size && pos >= 0);
	if (_size == _capacity)
	{
		reverse(_capacity == 0 ? 4 : 2 * _capacity);
	}
	for(size_t i = _size + 1; i > pos; i--)
	{
		_str[i] = _str[i - 1];
	}
	_str[pos] = ch;
	_size++;
}
void insert(size_t pos, const char* str)
{
	assert(pos <= _size && pos >= 0);
	size_t len = strlen(str);
	if (len+_size > _capacity)
	{
		reverse(len + _size);
	}
	for (size_t i = _size + len; i > pos; i--)
	{
		_str[i] = _str[i  - len];
	}
	memcpy(_str + pos, str, len);
	_size += len;
}

8. erase函数 

erase函数要分两种情况

一种是len的长度要大于等于_size-pos,也就是说要将pos后面的内容全部删除,这种我们处理起来很简单,将pos位置直接置为'\0',同时_size = pos即可。

另一种是后面还有字符需要保留,需要将后面的字符挪动到pos位置这里来,再_size -= len;

这里参数缺省值npos是静态成员函数,类型为size_t,值为-1,代表int的最大值

void erase(size_t pos,size_t len = npos)
{
	assert(pos < _size && pos >= 0);
	if (len >= _size - pos)
	{
		_size = pos;
		_str[_size] = '\0';
	}
	else
	{
		for (size_t i = pos + len; i <= _size; i++)
		{
			_str[i - len] = _str[i];
		}
		_size -= len;
	}
}

 9. clear函数 

clear函数简单,不需要处理_capacity,只需要第一个字符给到'\0',将_size给0。

void clear()
{
	_str[0] = '\0';
	_size = 0;
}

10.resize函数 

resize也是两种情况

n小于等于_size时,证明_size要减小,直接在n这个位置给到'\0',_size给0就好

另一种情况就可能需要扩容了,我们直接暴力处理,不管你扩不扩容,先来个reverse(n),要扩容我就扩容,不需要我就返回继续执行后续代码,同时给后面的空间都赋值ch。不要忘记最后_size给0,还有最后给'\0'。

void resize(size_t n,char ch = '\0')
{
	if (n <= _size)
	{
		_str[n] = '\0';
		_size = n;
	}
	else
	{
		reverse(n);
		for (size_t i = _size; i < n; i++)
		{
			_str[i] = ch;
		}
		_size = n;
		_str[_size] = '\0';
	}
}

11.find函数 

find函数重载了,可以从某位位置往后找字符,或者字符串。

找字符很简单,一个循环完事。

找字符串用到了strstr()函数,不为空代表找到了,就返回找到的指针- _str指针,就能算出他们两个的差值,就是索引,指针为空就返回 npos。

size_t find(char ch,size_t pos = 0)
{
	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)
{
	const char* p = strstr(_str + pos, str);
	if (p)
	{
		return p - _str;
	}
	return npos;
}

12.substr函数 

substr是从pos位置,截取n个长度的字符串,返回类型为string

如果n == pos||n>=_size-pos即代表pos后面的长度都要截取到,算出pos后面还有多少个字符,给s开辟好空间,遍历直接直接+=即可。

另一种情况,就遍历到 pos + n,再进行+=

string substr(size_t pos, size_t n = npos)
{
	string s;
	if (n == npos || n  >= _size - pos)
	{
		n = _size - pos;
		s.reverse(n);
		for (size_t i = pos; i < _size; i++)
		{
			s += _str[i];
		}
	}
	else
	{
		s.reverse(n);
		for (size_t i = pos; i < pos + n; i++)
		{
			s += _str[i];
		}
	}
	return s;
}

六、迭代器

迭代器是STL的特性,string类虽然比STL要早一点,还后面还是支持了迭代器,只不过因为该有的功能都有了,迭代器没有那么重要,但是可以为我们后续学其他容器打好基础。

string类的迭代器非常简单,就是一个指针,只需要写好begin() 和 end()就可以进行范围for的遍历了,指针本身就支持++和解引用,因此不需要重载。

我们写了两个迭代器,普通迭代器可以修改,const 迭代器不能修改

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;
}

七、全局函数

1.operator判断符重载

调用strcmp,再加复用

下面6种判断符重载,可以写在类里面,但string类为了支持宽字符等其他字符,写出了全局函数,这里只支持char类型,但还是写出了全局函数

bool operator<(const string& s1, const string& s2)
{
	return strcmp(s1.c_str(), s2.c_str()) < 0;
}
bool operator>(const string& s1, const string& s2)
{
	return strcmp(s1.c_str(), s2.c_str()) > 0;
}
bool operator==(const string& s1, const string& s2)
{
	return strcmp(s1.c_str(), s2.c_str()) == 0;
}
bool operator<=(const string& s1, const string& s2)
{
	return !(s1>s2);
}
bool operator>=(const string& s1, const string& s2)
{
	return !(s1<s2);
}
bool operator!=(const string& s1, const string& s2)
{
	return !(s1 == s2);
}

 2.流输入和流输出运算符重载

流输出非常简单,直接遍历即可。

这里使用get()函数才可以获取到' '(空格)和'\n'(换行) 

我们使用了临时数组来存储,目的是为了减少扩容,因为扩容的消耗很大。一个一个放到数组里面,等获取到' '(空格)和'\n'(换行) ,或者数据满了之后,再从数组里面将数据提取出来。

ostream& operator<<(ostream& out, const string& s)
{
	//out << s.c_str() << endl;
	for (auto e : s)
	{
		out << e;
	}
	return out;
}
istream& operator>>(istream& in,string& s)
{
	s.clear();
	char tmp[129];
	size_t i = 0;
	char ch;
	ch = in.get();
	while (ch != ' ' && ch != '\n')
	{
		tmp[i++] = ch;
		if (i == 128)
		{
			tmp[i] = '\0';
			s += tmp;
			i = 0;
		}
		ch = in.get();
	}
	if (i != 0)
	{
		tmp[i] = '\0';
		s += tmp;
	}
	return in;
}

到此,我们程序终于完成了,最后放上总代码 

string.h

#define _CRT_SECURE_NO_WARNINGS 1
#pragma once
#include <cassert>
#include <iostream>
using namespace std;
namespace kky
{
	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 = "")
			:_size(strlen(str))
			,_capacity(_size)
		{
			_str = new char[_capacity + 1];
			strcpy(_str, str);
		}

		//传统
		//string(const string& s)
		//	:_size(s._size)
		//	,_capacity(s._capacity)
		//{
		//	_str = new char[_capacity + 1];
		//	strcpy(_str, s._str);
		//}
		
		//string& operator=(const string& s)
		//{
		//	if (this != &s)
		//	{
		//		char* tmp = new char[s._capacity + 1];
		//		strcpy(tmp, s._str);
		//		delete[] _str;
		//		_str = tmp;
		//		_size = s._size;
		//		_capacity = s._capacity;
		//	}
		//	return *this;
		//}

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

		string(const string& s)
			:_str(nullptr)
			,_size(0)
			,_capacity(0)			//保证编译器一定初始化,析构才不会出错
		{
			string tmp(s._str);
			swap(tmp);
		}
		string& operator=(string tmp)
		{
			swap(tmp);
			return *this;
		}

		const char* c_str() const
		{
			return this->_str;
		}
		~string()
		{
			delete[] _str;
			_str = nullptr;
			_size = _capacity = 0;
		}
		size_t size() const 
		{
			return _size;
		}
		size_t capacity() const
		{
			return _capacity;
		}
		char& operator[](size_t pos)
		{
			assert(pos >= 0 && pos <= _size);
			return _str[pos];
		}
		const char& operator[](size_t pos) const
		{
			assert(pos >= 0&&pos<=_size);
			return _str[pos];
		}

		size_t find(char ch,size_t pos = 0)
		{
			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)
		{
			const char* p = strstr(_str + pos, str);
			if (p)
			{
				return p - _str;
			}
			return npos;
		}

		string substr(size_t pos, size_t n = npos)
		{
			string s;
			if (n == npos || n  >= _size - pos)
			{
				n = _size - pos;
				s.reverse(n);
				for (size_t i = pos; i < _size; i++)
				{
					s += _str[i];
				}
			}
			else
			{
				s.reverse(n);
				for (size_t i = pos; i < pos + n; i++)
				{
					s += _str[i];
				}
			}
			return s;
		}
		void reverse(size_t n)
		{
			if (n > _capacity)
			{
				char* tmp = new char[n + 1];//要多开一个留给'\0'
				strcpy(tmp, _str);
				if (_str != nullptr)
					delete[] _str;
				_str = tmp;
				_capacity = n;
			}
		}
		void push_back(char ch)
		{
			if (_size == _capacity)
			{
				reverse(_capacity == 0 ? 4 : 2 * _capacity);
			}
			_str[_size] = ch;
			_size++;
			_str[_size] = '\0';
		}
		void append(const char* str)
		{
			size_t len = strlen(str);
			if (_size + len > _capacity)
			{
				reverse(_size + len);
			}
			strcpy(_str + _size, str);
			_size += len;
		}

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


		void insert(size_t pos,char ch)
		{
			assert(pos <= _size && pos >= 0);
			if (_size == _capacity)
			{
				reverse(_capacity == 0 ? 4 : 2 * _capacity);
			}
			for(size_t i = _size + 1; i > pos; i--)
			{
				_str[i] = _str[i - 1];
			}
			_str[pos] = ch;
			_size++;
		}
		void insert(size_t pos, const char* str)
		{
			assert(pos <= _size && pos >= 0);
			size_t len = strlen(str);
			if (len+_size > _capacity)
			{
				reverse(len + _size);
			}
			for (size_t i = _size + len; i > pos; i--)
			{
				_str[i] = _str[i  - len];
			}
			memcpy(_str + pos, str, len);
			_size += len;
		}
		void erase(size_t pos,size_t len = npos)
		{
			assert(pos < _size && pos >= 0);
			if (len >= _size - pos)
			{
				_size = pos;
				_str[_size] = '\0';
			}
			else
			{
				for (size_t i = pos + len; i <= _size; i++)
				{
					_str[i - len] = _str[i];
				}
				_size -= len;
			}
		}
		void clear()
		{
			_str[0] = '\0';
			_size = 0;
		}
		void resize(size_t n,char ch = '\0')
		{
			if (n <= _size)
			{
				_str[n] = '\0';
				_size = n;
			}
			else
			{
				reverse(n);
				for (size_t i = _size; i < n; i++)
				{
					_str[i] = ch;
				}
				_size = n;
				_str[_size] = '\0';
			}
		}

	private:
		char* _str;
		size_t _size;
		size_t _capacity;
		//const static size_t npos = -1; //特例
		const static size_t npos;
	};

	const size_t string::npos = -1;

	ostream& operator<<(ostream& out, const string& s)
	{
		//out << s.c_str() << endl;
		for (auto e : s)
		{
			out << e;
		}
		return out;
	}
	istream& operator>>(istream& in,string& s)
	{
		s.clear();
		char tmp[129];
		size_t i = 0;
		char ch;
		ch = in.get();
		while (ch != ' ' && ch != '\n')
		{
			tmp[i++] = ch;
			if (i == 128)
			{
				tmp[i] = '\0';
				s += tmp;
				i = 0;
			}
			ch = in.get();
		}
		if (i != 0)
		{
			tmp[i] = '\0';
			s += tmp;
		}
		return in;
	}

	bool operator<(const string& s1, const string& s2)
	{
		return strcmp(s1.c_str(), s2.c_str()) < 0;
	}
	bool operator>(const string& s1, const string& s2)
	{
		return strcmp(s1.c_str(), s2.c_str()) > 0;
	}
	bool operator==(const string& s1, const string& s2)
	{
		return strcmp(s1.c_str(), s2.c_str()) == 0;
	}
	bool operator<=(const string& s1, const string& s2)
	{
		return !(s1>s2);
	}
	bool operator>=(const string& s1, const string& s2)
	{
		return !(s1<s2);
	}
	bool operator!=(const string& s1, const string& s2)
	{
		return !(s1 == s2);
	}

	void test01()
	{
		string s("123456");
		cout << s.c_str() << endl;
		s[0] = 'c';
		cout << s.c_str() << endl;
		/*for (int i = 0; i < s.size(); i++)
		{
			cout << s[i] << " ";
		}
		cout << endl;
		string::iterator it = s.begin();
		while (it != s.end())
		{
			cout << *it << " ";
			it++;
		}
		cout << endl;
		for (auto e : s)
		{
			cout << e << " ";
		}*/
	}
	void test02()
	{
		string s1("hello world");
		cout << s1.c_str() << endl;
		s1.push_back('s');
		s1.append("tring");
		cout << s1.c_str() << endl;
		s1 += 'w';
		s1 += "odema";
		cout << s1.c_str() << endl;
	}

	void test03()
	{
		string s1("hello world");
		cout << s1.c_str() << endl;
		s1.insert(5, 'c');
		cout << s1.c_str() << endl;
		s1.insert(s1.size(), 'c');
		cout << s1.c_str() << endl;
		s1.insert(0, 'c');
		cout << s1.c_str() << endl;
		s1.insert(5, "hhh");
		cout << s1.c_str() << endl;
		s1.erase(0, 3);
		cout << s1.c_str() << endl;
		s1.erase(s1.size()-1, 3);
		cout << s1.c_str() << endl;
	}
	void test04()
	{
		string s1("hello world");
		cout << s1.c_str() << endl;
		string s2("hello worldl");
		cout << (s1 != s2) << endl;;
		cout << s2 << endl;
		cin >> s1;
		cout << s1.c_str() << endl;
	}
	void test05()
	{
		string s1("hello world");
		cout << s1.c_str() << endl;
		string s2("hello worldl");
		cout << s2 << endl;
		s1.resize(5);
		cout << s1 << endl;
		s1.resize(15,'c');
		cout << s1 << endl;
	}
	void test06()
	{
		string s1("hello world");
		string s2(s1);
		cout << s1 << endl;
		cout << s2 << endl;
		string s3 = "wasg1";
		s3 = s1;
		cout << s3 << endl;
	}
}

test.cpp  (调用测试接口即可) 

#include"string.h"
int main()
{
	kky::test06();

}

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

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

相关文章

plink分析100个性状的批量gwas分析

大家好&#xff0c;我是邓飞。 GWAS分析时&#xff0c;3~5个性状是正常操作&#xff0c;要分析100个性状呢&#xff0c;手动修改参数&#xff0c;工作量是够了&#xff0c;但是程序员的修养体现在哪里了&#xff1f;&#xff1f;&#xff1f; 如果还是按照每个性状一个文件夹…

Jetpack:012-Jetpack中的弹出菜单

文章目录 1. 概念介绍2. 使用方法2.1 DropdownMenu2.2 DropdownMenuItem 3. 示例代码3.1 代码和注释3.2 代码难点3.3 运行效果 4. 内容总结 我们在上一章回中介绍了Jetpack中标题栏相关的内容&#xff0c;本章回中主要 弹出菜单。闲话休提&#xff0c;让我们一起Talk Android …

Appium+python+unittest搭建UI自动化框架!

阅读本小节&#xff0c;需要读者具备如下前提条件&#xff1a; 1. 掌握一种编程语言基础&#xff0c;如java、python等。 2. 掌握一种单元测试框架&#xff0c;如java语言的testng框架、python的unittest框架。 3. 掌握目前主流的UI测试框架&#xff0c;移动端APP测试框架Appiu…

智能化巡检系统哪家好?巡检系统可以为企业单位带来什么便利?

设备点检是设备维修策略中预防维修的一个重要手段。在很多单位内也得到了广泛的应用&#xff0c;但是实施效果均不太理想&#xff0c;弄虚作假的情况时常存在。尽管现在是人手一机的时代&#xff0c;但仍然有不少企业以纸笔抄录作为点检模式&#xff0c;这样就容易存在一系列的…

HarmonyOS/OpenHarmony原生应用-ArkTS万能卡片组件Slider

滑动条组件&#xff0c;通常用于快速调节设置值&#xff0c;如音量调节、亮度调节等应用场景。该组件从API Version 7开始支持。无子组件 一、接口 Slider(options?: {value?: number, min?: number, max?: number, step?: number, style?: SliderStyle, direction?: Ax…

如何确定IP地址的具体位置?

IP地址通过几种方法帮助确定具体位置&#xff0c;尽管它们的准确性和精度因不同的情况而异。以下是几种确定具体位置的主要方法&#xff1a; 地理IP数据库&#xff1a;这是最常用的方法之一&#xff0c;它使用IP地址和地理位置数据的映射来确定用户的位置。这些数据库存储了大量…

节省工时超 1500人/天,国泰基金探索金融业人机协同新业态

“十四五”时期是我国经济实现从高速增长转变为高质量发展的关键历史时期&#xff0c;“十四五”规划向金融行业提出了数字化转型与科技监管的新要求。在新一轮科技革命和产业变革趋势下&#xff0c;新一代信息技术与金融行业融合加速&#xff0c;金融行业面临着监管要求与自身…

coreldraw2018零售版最新下载步骤

安装前一定要先退出杀毒软件&#xff1a;360杀毒、360安全卫士、腾讯管家等。 第一步&#xff1a;打开安装包 CorelDRAW2018版win下载如下:https://wm.makeding.com/iclk/?zoneid55678 CorelDRAW2018版mac下载如下:https://wm.makeding.com/iclk/?zoneid55679 第二步&…

AutoSAR入门:开发工具链介绍

1、AutoSAR愿景/目标 AutoSAR的目标&#xff0c;旨在进行嵌入式软件的标准化。 2、AutoSAR在BMS中的应用 国外公司BMS 做的比较好的有联电、大陆、德尔福、AVL 和FEV 等等&#xff0c; 现在基本上都是按照AUTOSAR架构以及ISO26262功能安全的要求来做&#xff0c;软件功能更多&…

Flutter笔记:发布一个Flutter头像模块 easy_avatar

Flutter笔记 发布一个头像Flutter模块 easy_avatar 作者&#xff1a;李俊才 &#xff08;jcLee95&#xff09;&#xff1a;https://blog.csdn.net/qq_28550263 邮箱 &#xff1a;291148484163.com 本文地址&#xff1a;https://blog.csdn.net/qq_28550263/article/details/1339…

Stable Diffusion WebUI几种解决手崩溃的方法

1. 添加与手相关负面提示词 如何提价提示词呢? 首先有一个embeddings模型文件bad-hands-5,我们可以去各个大模型网站去搜,我是在C站上面下载的。 附上C站地址:https://civitai.com/ 下载好之后,你需要将文件放入stable-diffusion-webui\embeddings目录中。位置如下所示…

【Linux-常用命令-基础命令-解压rar文件-unrar-x-命令-笔记】

【Linux-常用命令-基础命令-解压rar文件-unrar-x-命令-笔记】 1、前言2、操作3、自己的操作 1、前言 最近&#xff0c;在使用Linux的时&#xff0c;使用相关基础命令是&#xff0c;总是容易忘记&#xff0c;上网一搜&#xff0c;大部分都写的比较繁琐&#xff0c;解压不同文件…

执法记录仪主板_基于MTK6877联发科5G主板方案

4G/5G智能执法记录仪是一种集成了先进的人工智能和传感器技术的设备&#xff0c;不仅可以记录事件发生的过程&#xff0c;还能够辅助工作人员进行人车识别、安全预警。这种记录仪使用联发科MT6877芯片作为主板方案&#xff0c;该芯片采用了6纳米工艺制程&#xff0c;拥有八核CP…

揭秘108个CMD命令,让你成为计算机大神

今天整理了一些cmd命令 &#x1f449;操作方法&#xff1a;快捷键winR&#xff0c;输入cmd回车&#xff0c;然后就可以输入cmd命令了&#xff0c;赶紧收藏起来&#xff0c;用的时候更方便 想了解更多网工知识&#xff0c;获取《网工大礼包》&#xff0c;可关注公众号&…

PTE-精听学习(二)

目录 时间分配 消音题可以帮忙 节约时间的 剩余9个题目一定要剩余出10分钟以上 MSA 单选题看时间 评分标准 ​编辑 SMW 单词长 空挡 会早一点 单词短 beep短 会晚一点 做题方法 1.先猜 2.不准记笔记 3.搭配 HIW 大分题不是小分题 评分标准 3-6个是比较常见…

zabbix-proxy代理服务器配置

下载zabbix源 rpm -Uvh https://repo.zabbix.com/zabbix/5.0/rhel/7/x86_64/zabbix-release-5.0-1.el7.noarch.rpm 安装 yum -y install zabbix-proxy-mysql zabbix_get 查看相关文件路径 rpm -ql zabbix-proxy-mysql 创建数据库 mysq -uroot -proot mysql> create database…

Kubeadm部署k8s集群

目录 主机准备 主机配置 修改主机名&#xff08;三个节点分别执行&#xff09; 配置hosts&#xff08;所有节点&#xff09; 关闭防火墙、selinux、swap、dnsmasq(所有节点) 安装依赖包&#xff08;所有节点&#xff09; 系统参数设置(所有节点) 时间同步(所有节点) 配…

vite中配置 https 安全超文本网络协议

vite中配置 https 安全超文本网络协议 1、本地模拟生成证书2、安装证书3、vite 中使用插件支持 https 协议 前言&#xff1a; https 的配置是相对安全的&#xff0c;但是需要购买证书&#xff0c;它是 SSL/TLS HTTP 的安全超文本网络协议 此版本配置的是在 vite 开发服务器上临…

uni-table多选获取当前行数据 - - -亲测有效

废话不多说&#xff0c;直接上代码 因为全选的时候,只能返回当前的索引,所有要处理一下 代码如下: selectionChange(e) {let arrList [] // 选择的行数据let selectedIndexs [] // 选择的下标数组selectedIndexs e.detail.index// 将数组中的值&#xff0c;作为table表格数…

ArGIS Engine专题(13)之矢量要素图层符号化(单一符号化渲染)

一、结果预览 二、简介 要素符号化是指为地理要素(如点、线、面等)设置视觉表示样式的过程。通过符号化,可以将地理要素以不同的颜色、大小、形状、填充等方式呈现,以便更好地表达地理数据的含义和特征。 本文主要实现了四大类要素符号化方式,包括单一符号化渲染、唯一值渲…