C++:模拟实现string

news2024/11/16 6:00:51

前言:

        为了更好的理解string底层的原理,我们将模拟实现string类中常用的函数接口。为了与std里的string进行区分,所以用命名空间来封装一个自己的strin类。

string.h

#pragma once
#define _CRT_SECURE_NO_WARNINGS 1

#include<iostream>
#include<assert.h>
#include<string>
using namespace std;
namespace manbo
{
	class string
	{
		public:
			//迭代器
			typedef char* iterator;
		
			static size_t npos;

			//构造函数
			string(const char* s);
			
			//默认构造
			string();

			//拷贝构造
			string(const string& s);

			//析构函数
			~string();
			
			//返回字符串
			const char* c_str()const ;

			char& operator[](size_t pos);
			const char& operator[](size_t pos)const ;

			const size_t size()const;

			iterator begin()
			{
				return _str;
			}

			iterator end()
			{
				return _str + _size;
			}

			const iterator begin()const 
			{
				return _str;
			}

			const iterator end()const 
			{
				return _str + _size;
			}

			void reserve(size_t n = 0);
			void push_back(char ch);
			string& append(const char*s);
			string& operator+=(const char* s);
			string& operator+=(char ch);
			string& insert(size_t pos, const char* s);
			string& erase(size_t pos, size_t len = npos);

			size_t find(const char* s, size_t pos = 0) const;
			size_t find(char c, size_t pos = 0) const;

			string substr(size_t pos, size_t len =npos) const;

			void resize(size_t n, char ch = '\0');
			void clear();

			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;

			void swap(string& s2);
			string& operator=(string temp);
			
		private:
			size_t _size;
			size_t _capaticy;
			char* _str;
	};

	ostream& operator<<(ostream& out, const string& s);
	istream& operator>>(istream& in, string& s);
}

        string里有三个私有成员变量 size,capacity,*str,分别表示字符数组的有效数据个数,容量,以及指向字符数组的指针。另外还有一个公有的char类型的指针iterator(迭代器)以及size_t类型的公有静态成员变量npos,并初始化值为-1实则会整型的最大值。

string.cpp

namespace manbo
{
	string::string(const char* s)
		:_size(strlen(s))
		, _capaticy(_size)
		, _str(new char[_size + 1])
	{
		memcpy(_str, s,_size+1);
	}

	string::string()
		:_size(0)
		, _capaticy(0)
		, _str(new char[1])
	{
		_str[0] = '\0';
	}

	string::string(const string& s)
	{
		_str = new char[s._size + 1];
		_size = s._size;
		_capaticy = s._capaticy;
		memcpy(_str,s._str,s._size+1);
	}

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

	const char* string::c_str()const 
	{
		return _str;
	}

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

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

	const size_t string ::size()const
	{
		return _size;
	}


	void string::reserve(size_t n)
	{
		if (n>_capaticy)
		{
			char* temp = new char[n + 1];
			memcpy(temp, _str,_size+1);
			_capaticy = n;
			delete[] _str;
			_str = temp;
		}
	}

	void string::push_back(char ch)
	{
		if (_size==_capaticy)
		{
			reserve(_capaticy == 0 ? 4 : 2 * _capaticy);
		}
		_str[_size++] = ch;
		_str[_size] = '\0';
	}

	string& string:: append(const char*s)
	{
		size_t len = strlen(s);
		if (_size+len>_capaticy)
		{
			reserve(2 * (_size + len));
		}
		memcpy(_str + _size,s,len+1);
		_size += len;
		return *this;
	}

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

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

	string& string::insert(size_t pos, const char* s)
	{
		assert(pos >= 0 && pos <= _size);
		size_t n = strlen(s);
		size_t len = _size + n;
		_size += n;
		if (len>_capaticy)
		{
			reserve(2 *len);
		}
		size_t end = _size;
		
		while (end>=pos&&end!=npos)
		{
			_str[end + n] = _str[end];
			end--;
		}
		
		for (int i = 0; i <n ; i++)
		{
			_str[pos + i] = s[i];

		}
		return *this;
	}

	string& string::erase(size_t pos, size_t len)
	{
		assert(pos < _size);;
		if (len==npos||pos+len>=_size)
		{
			_str[pos] = '\0';
			_size = pos;
		}
		else
		{
			int sum = 0;
			size_t begin = pos + len;
			while (begin<=_size)
			{
				sum++;
				_str[pos] = _str[begin];
				pos++, begin++;
			}
			_size = pos + sum;
		}
		return *this;
	}

	size_t string::find(char c, size_t pos) const
	{
		for (size_t i = pos; i < _size; i++)
		{
			if (_str[i] == c)
				return i;
		}
		return npos;
	}
	size_t string:: find(const char* s, size_t pos) const
	{
		char* temp = strstr(_str, s);
		if (!temp)
		{
			return npos;
		}
		else
		{
			return temp-_str ;
		}
	}

	string string::substr(size_t pos, size_t len) const
	{
		assert(pos < _size);
		string temp;
		if (len == npos || pos + len >= _size)
		{
			temp.reserve(_capaticy);
			for (size_t i = pos; i < _size; i++)
			{
				temp += _str[i];
			}
		}
		else
		{
			temp.reserve(len + 1);
			for (size_t i = pos; i < len+pos; i++)
			{
				temp += _str[i];
			}
		}
		return temp;
	}
	
	size_t string::npos = -1;

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

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

	// hello hello		false
	// hello*** hello	false
	// hello hello**	true
	bool string:: operator<(const string& s) const
	{
		size_t s1, s2;
		s1 = s2 = 0;
		while (s1<_size&&s2<s._size)
		{
			if (_str[s1] < s._str[s2])
				return true;
			else if (_str[s1] > s._str[s2])
				return false;
			else
			{
				s1++, s2++;
			}
		}
		if (_size>s.size())
		{
			return false;
		}else if(_size == s.size())
		{
			return false;
		}
		return true;
	}

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

	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 || *this > s;
	}

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

	void string:: swap( string& s)
	{
		std::swap(_str, s._str);
		std::swap(_capaticy, s._capaticy);
		std::swap(_size, s._size);
	}
	//实现深拷贝
	string& string::operator=(string temp)
	{
		swap(temp);
		return *this;
	}
}

ostream& manbo:: operator<<(ostream& out, const string& s)
{
	for (auto ch:s)
	{
		out << ch;
	}
	cout << endl;
	return out;
}
istream&manbo:: operator>>(istream& in, string& s)
{
	s.clear();

	char ch;
	ch = in.get();
	while (ch == '\0' || ch == '\n')
	{
		ch = in.get();
	}
	char buff[128];
	int i = 0;

	while (ch!='\0'&&ch!='\n')
	{
		buff[i++] = ch;
		if (i==127)
		{
			buff[i] = '\0';
			s += buff;
			i = 0;
		}
		ch = in.get();
	}

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

string::string(const char* s)

        以下是函数的解释:

        1.这是string类的构造函数,它接受一个const char*类型的参数s。这个参数代表一个 C语言 风格的字符串(即以 null 终止的字符数组)。

        2.初始化列表用于在构造函数体执行之前初始化类的成员变量。这里对三个成员变量进行了初始化:

                2.1strlen(s)计算字符串s的长度(不包括 null 终止符)。将这个长度赋值给_size成员变量,表示字符串的实际字符数。

                2.2_capaticy是字符串的容量。在这个实现中,容量被设置为与字符串长度相同,即_size

                2.3new char[_size + 1]分配了一块动态内存,大小为_size+1。这里+1是为了存储字符串的 null 终止符('\0')。将这块内存的指针赋值给_str,_str用于存储实际的字符串内容。

        3.构造函数体的内容是将源字符串 s 的内容复制到新分配的内存区域_str中。memcpy函数用于内存块的复制:复制从s开始的_size+1字节到_str。这里的_size+1是因为我们要复制整个字符串,包括 null 终止符。

    string::string()        

        以下是函数解释

        1.这是string类的默认构造函数。它不接受任何参数,并用于创建一个空的 string对象。    

        2.初始化列表用于在构造函数体执行之前初始化类的成员变量。这里对三个成员变量进行了初始化:

                2.1初始化_size成员变量为 0,表示字符串的长度为零。因为这是一个空字符串,所以长度为零。

                2.2初始化_capaticy成员变量为 0,表示字符串的容量也为零。

                2.3使用new char[1]分配了一块大小为 1 字节的动态内存。这块内存用于存储字符串及其终止符'\0'。

        

string::string(const string& s)

        以下是关于函数的解释

        这段代码是一个拷贝构造函数,用于创建一个string类的新对象,它是现有string对象的副本

  string::~string()      

        以下是函数的解释

        1.释放_str指针在堆上申请的空间,并将_str置为空指针

        2.将_size与_capaticy重新置为0;

const char* string::c_str()const 

         以下是函数的解释

        1.返回_str所指向的字符串。

char& string::operator[](size_t pos)

        以下是函数的解释

        1.这段代码定义了string类的一个成员函数operator[ ],用于访问字符串中的字符。这个函数是一个重载的下标运算符,允许通过下标直接访问字符串中的字符。

        2.assert是一个宏,用于在调试阶段检查条件是否为真。如果条件不为真,程序会中断并输出错误信息。这里检查pos是否在有效范围内,如果是则程序继续执行。

        3.return _str[pos];如果索引pos合法,函数返回_str[pos]。 _str是一个指向字符数组的指针,因此_str[pos] 表示数组中第 pos个位置的字符,并且返回的是引用所以可以对返回的值进行修改会影响到_str[pos]里的值。

const char& string::operator[](size_t pos)const

        以下是函数的解释

        与上个函数类似,但传入的对象以及返回的引用都被const进行修饰,此函数可以传const对象,因为这是一个权限的平移,而上个函数不能传const对象因为会产生权限的放大。并且对返回的引用只能进行读取而不能进行修改。

 const size_t string ::size()const   

   

        以下是函数的解释

        因为_size是成员变量默认是私有的所以不能直接返回,并且也不能随意修改,通过size() 函数来获取_size的值。

void string::reserve(size_t n)

                以下是函数的解释

                1.这段代码是一个成员函数reserve,用于调整string类的内部字符数组的容量,以便容纳至少n个字符的数据;

                2.判断n > _capaticy,检查n是否大于当前已分配的容量_capaticy,如果大于就扩容;

                3.new char[n + 1],在堆上分配一个新的字符数组,大小为n+1。因为额外的 1 个字符位置用于存储字符串的终止符'\0',并temp指针进行接收.

                4.memcpy(temp, _str, _size + 1)使用memcpy函数将旧字符数组_str的内容(包括终止符所以要+1)复制到新分配的内存temp中

                5.释放原_str的内容

                6.将_str重新指向新分配内存的指针temp的地址

void string::push_back(char ch)

         以下是函数的解释

        1.这个push_back函数用于向string对象的末尾添加一个字符,并处理容量的扩展。

        2.if (_size == _capaticy):检查当前字符串的大小是否等于当前容量。如果等于,说明字符串需要扩展容量,那么则调用创建好的reserve函数进行扩容,如果一开始是给空字符串那么_capacity会等于0,0乘任何数都得0,所以要加以进行判断。

        3.将字符ch添加到当前字符串的末尾,在赋值后递增_size,更新字符串的当前长度;

        4.在字符串末尾添加终止符'\0',标志着字符串的结束

    string& string:: append(const char*s)

        以下是关于函数的解释

        1.append函数用于将一个 C 风格的字符串(const char* s)追加到string对象的末尾

        2.strlen(s):计算要追加的字符串s的长度(不包括终止符 '\0'),并且赋值给len

        3.检查当前字符串的总长度(包括要追加的部分)是否超过当前容量,如果超过则调用reserve函数进行扩容

        4.拷贝字符串s从原string对象末尾('\0')的位置,并更新_size的值。

    string& string::operator+=(const char* s)

         以下是关于函数的解释

        operatir+=运算符重载,其参数为字符串,使用此operatir+=会复用append函数,在原字符串末尾追加字符串s,并返回*this(原对象)的引用。

        string& string::operator+=(char ch)

          以下是关于函数的解释

          operatir+=运算符重载,其参数为单个字符,使用此operatir+=会复用push_backd函数,在原字符串末尾追加字符ch,并返回*this(原对象)的引用。      

        string& string::insert(size_t pos, const char* s)

                以下是关于函数的解释

                1.insert函数用于在string对象中的指定位置插入字符串

                2.assert:检查插入位置pos是否在有效范围内(即不小于 0 且不大于当前字符串的_size)

                3.strlen(s)计算待插入的字符串s的长度,并将其赋值给n

                4.更新当前字符串的大小_size,将更新后的_size赋值给len,并判断是否需要扩容

                5.end:初始化为新的字符串长度_size,这是待会插入操作开始前的字符串末尾。        

                6.while循环:从字符串的末尾向插入位置pos移动字符,为腾出空间插入新字符串,_str[end + n] = _str[end]:将字符移动到新的位置并将end--.。注意,npos是一个静态成员变量,通常定义为size_t(-1),表示无效位置。在这里,它的作用是防止end变成负值,从而避免无限循环。

                7.for循环:将待插入的字符串s 的字符逐个复制到目标位置pos开始的位置

                8.返回 *this(当前对象)的引用,以支持链式调用。

string& string::erase(size_t pos, size_t len)

        以下是关于函数的介绍

        1.erase函数用于从string对象中删除指定位置的字符,删除的长度由 len 参数指定(缺省值为npos)。它的实现包括了处理不同情况的逻辑,以确保删除操作正确地更新字符串的内容和大小。

        2.assert:检查pos 是否在有效范围内(即 pos 应小于当前字符串的大小_size)

        3.if语句:处理特殊情况

                3.1如果len的值是npos(表示删除到字符串的末尾)或者pos + len超过了 _size,则删除从pos位置到字符串末尾的所有字符。

                3.2_str[pos] = '\0';:将删除位置设置为字符串结束符'\0',这会将字符串从pos位置截断,并更新字符串的大小 _size,以表示新的字符串长度。

        4.else语句:处理len小于字符串剩余长度的情况

                4.1 int sum = 0;:初始化一个计数器sum,用于记录实际移动的字符数。

                4.2 size_t begin = pos + len;:确定开始移动的字符位置。

                4.3 while (begin <= _size)遍历从begin到字符串末尾的所有字符,并将它们向前移动到删除的区域(这里字符'\0'也会向前移动,所以不需要再添加'\0'),以覆盖掉删除的字符。

        5._size = pos + sum;:更新字符串的大小_size,它应该等于新末尾的位置加上实际移动的字符数。

    

size_t string::find(char c, size_t pos) const

        以下是关于函数的介绍

        通过遍历来查找传入的字符c,如果找到就返回下标,如果没找到则返回npos。

size_t string:: find(const char* s, size_t pos) const

        以下是关于函数的介绍

        1.运用c语言的库函数strstr查找子串并用char类型的指针temp进行接受

        2.如果temp是NULL那么就没找到返回npos,如果找到了则将temp的地址-_str的首地址,最终会算出子串的第一个字符的下标位置。

    string string::substr(size_t pos, size_t len) const

                

        以下是关于函数的介绍

        1.substr函数用于生成当前字符串对象的子字符串。它的实现包括对子字符串的提取和处理

        2.assert(pos < _size);确保pos 在有效范围内。这里_size表示当前字符串的实际大小

        3.string temp;创建一个名为 temp的 string 对象,用于存储提取的子字符串。

        4.if (len == npos || pos + len >= _size),如果len是npos(表示提取从pos到字符串末尾)或者pos + len 超过了当前字符串的大小 _size,则处理这两种情况:

                4.1预先为temp对象开好_capaticy个空间,目的是避免频繁的扩容

                4.2 for循环,从pos位置开始遍历到字符串末尾,将每个字符添加到temp字符串中。

        5 当len小于等于字符串的剩余长度时,提取从pos开始的长度为len的子字符串

                5.1为temp字符串扩容,len+1是为了确保有足够的空间来存储len个字符和一个'\0'

                5.2 for循环从pos位置开始,遍历len个字符,将每个字符添加到 temp 字符串中。

注意:这里并不需要专门再结尾添加'\0',因为temp +=会去调用operator+=的运算符重载,而operator+=里又会调用push_back函数,再push_back函数里会对字符末尾进行添加'\0'的操作

void string::resize(size_t n, char ch)

        以下是关于函数的解释

        1.resize函数用于调整string对象的大小,并且可以用特定的字符填充新增的部分。

        2.如果传入的n是小于_size的那么直接将字符串_str[n]替换为'\0',并将_size更新为n;

        3.如果是n大于_size那么先将string对象的内存进行扩容,确保字符串的存储空间足够,然后从_size位置到n 位置填充字符ch。接着在_str[n]插入终结符 '\0',并更新_size为n。

void string::clear()

         以下是关于函数的解释

        clear顾名思义是清理的意思,那么直接在_str[0]的位置插入终止符'\0',并把_size更新为0,这里没有将_capacity置空是为了怕对象还要进行插入数据,防止多次扩容消耗性能。

bool string:: operator<(const string& s) const

        以下是关于函数的解释

        .operator<函数定义了一个 <操作符,用于比较当前 string 对象与另一个 string对象的大小。它主要用于ASCII比较(即按字母顺序比较)

        

其他的operator比较符重载

string& string::operator=(string temp)

        以下是关于函数的解释  

        1.接受一个string对象temp的形参

        2.在函数体内调用swap(temp),这将当前对象的内容与temp对象的内容交换。

        3.交换后,当前对象就变成了 temp 的内容,temp变成了当前对象的旧内容,并且因为temp是局部参数,在函数调用的时候自动进行析构,防止了内存泄漏

ostream& manbo:: operator<<(ostream& out, const string& s)

        以下是关于函数的解释

        1.operator<<函数是一个重载的输出流操作符,用于将string对象的内容输出到输出流

        2.范围for循环,auto ch自动推导ch的类型为s中的字符类型,循环遍历s中的每一个字符,并将其逐个输出到流out中

        3.返回流out以支持链式操作。比如:out<<s1<<s2;

istream&manbo:: operator>>(istream& in, string& s)

        以下是关于函数的解释

        1.operator>>函数是一个重载的输入流操作符,用于从输入流读取字符串,并将其存储到string对象s中。

        2.s.clear();使s变为空字符串,以确保读取的内容覆盖之前的内容.

        3.char ch;ch = in.get();使用in.get()从流中读取一个字符并存储在ch中。

        4.while循环跳过开头无用的字符如'\0'或'\n',直到读取到第一个有用的字符

        5.使用一个字符数组buff作为缓冲区来临时存储字符,i用于确认buff数组的位置。

        6.while循环, 只要字符不是'\0'和'\n',就将字符存入缓冲区buff。缓冲区buff里有 127 个字符时(留一个位置给终止符'\0'),将缓冲区内容+=到s中,并重置i。

        7.如果i>0表示buff里有剩余的字符,将这些字符+=到s对象中

        8. 返回流in的引用,以支持链式输入操作。比如:cin>>s1>>s2;

        

测试文件:

void test01()
{
	manbo::string s1;
	manbo::string s2="Hello world";
	cout << s2.c_str() << endl;
	cout << s1.c_str() << endl;
	manbo::string const s3 = "asdddd";
}

void test02()
{
	manbo::string const s2 = "Hello world";
	manbo::string::iterator it = s2.begin();
	while (it!=s2.end())
	{
		cout << *it;
		it++;
	}
	cout << endl;
}

void test03()
{
	manbo::string  s2 = "Hello world";
	s2.insert(6, "******");
	cout << s2.c_str() << endl;
	s2.erase(0);
	cout << s2.c_str() << endl;
}

void test04()
{
	manbo::string  s2 = "Hello world";
	size_t pos1 = s2.find("world");
	size_t pos2 = s2.find('e');
	cout << pos2 << endl;
}

void test05()
{

	manbo::string s1 = "https://www.bilibili.com/video/BV1fW421X7gD/?spm_id_from=333.1007.tianma.6-1-19.click";
	//解析网址,分协议   域名  资源
	size_t pos1 = s1.find("://");
	if (pos1 == manbo::string::npos)
	{
		cout << "No Find";
		exit(1);
	}
	manbo::string agreement = s1.substr(0, pos1);
	cout << "协议:" << agreement.c_str()<< endl;

	size_t pos2 = s1.find('/', pos1 + 3);
	if (pos2 == manbo::string::npos)
	{
		cout << "No Find";
		exit(1);
	}

	manbo::string domain = s1.substr(pos1 + 3, pos2 - (pos1 + 3));
	cout << "域名:" << domain.c_str()<< endl;

	manbo::string resource = s1.substr(pos2 + 1);
	cout << "资源:" << resource.c_str() << endl;
}

void test06()
{
	string s1 = "hello world";
	manbo::string s2 = "hello world";
	//s1.resize(4,'x');
	//s2.resize(4,'x');
	s1 += '\0';
	s1 += "******";

	s2 += '\0';
	s2 += "******";
	cout << s1 << endl;
	cout << s2<< endl;

	manbo::string s3;

	cin >> s3;
	cout << s3;

	cin >> s3;
	cout << s3;
}

void test07()
{
	manbo::string s1="hello";
	manbo::string s2="hello world";
	cout << (s1 < s2) << endl;
	cout << (s1 == s2) << endl;
	cout << (s1 > s2) << endl << endl;

	manbo::string s3 = "hello world";
	manbo::string s4 = "hello";
	cout << (s3 < s4) << endl;
	cout << (s3 == s4) << endl;
	cout << (s3 > s4) << endl<<endl;

	manbo::string s5 = "hello";
	manbo::string s6 = "hello";
	cout << (s5 < s6) << endl;
	cout << (s5 == s6) << endl;
	cout << (s5 > s6) << endl << endl;
}

void test08()
{
	manbo::string s1 = "hello";
	manbo::string s2 = "hello world";
	s1 = s2;
	cout << s1;

}

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

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

相关文章

arm 的寄存器概述(8)

关于寄存器的概述。 带 三角形的是 这种模式下 独有的寄存器&#xff0c;也就是说&#xff0c;FIQ模式下与 SYstem/user 模式下&#xff0c;虽然都有r8 寄存器&#xff0c;但是不是一个东西。 r13 (SP ) 这是堆栈指针&#xff0c; r15(PC ) 这是 code 的指针。 r14(LR ), 这…

自动化与高效设计:推理技术在FPGA中的应用

想象一下&#xff0c;你正在设计一个复杂的电路系统&#xff0c;就像在搭建一座精巧的积木城堡。你手头有各种形状和功能的积木块&#xff0c;这些积木块可以组合成任何你需要的结构。在这个过程中&#xff0c;你有两种主要的方法&#xff1a;一种是手动挑选和搭建每一块积木&a…

安装JDK与配置环境变量

安装JDK与配置环境变量 JDK安装包所在路径&#xff1a;/opt/software/jdk-8u221-linux-x64.tar.gz 详细步骤 安装JDK与配置环境变量一、进入JDK安装目录/opt/software二、解压“jdk-8u221-linux-x64.tar.gz”安装包至当前目录三、查看/opt/software/目录下解压文件四、编辑系统…

鹅厂探索国漫新方向,谁家新作能不负期待?

上周一年一度的腾讯视频动漫大赏年度发布会结束了&#xff0c;但动漫迷们的讨论却没有停止。此次的片单分为“气”“大怪”“阁”三大主题&#xff0c;今天来和大家回顾解读一下“气”和“阁”有哪些看点吧。 首先想谈一谈“阁”&#xff0c;它是平台在内容升级思路上的体现&am…

C指针汇总——藏在数组名与指针之间的异同及使用细节

指针与数组的异同 数组名&#xff1a; 是一个指针常量(数组名的值是数组首元素的指针常量)&#xff0c;指向数组的首元素。大小固定为整个数组的大小。无法被改变或重新赋值(这里指数组名不能被赋值(指针常量不能指向其它地址)&#xff0c;数组元素是可以被重新设置的)。无法进…

企业CAD图纸加密软件推荐!2024年好用的10款CAD图纸加密软件排行

在现代企业中&#xff0c;CAD图纸作为重要的设计和工程数据&#xff0c;其安全性和保密性至关重要。为了防止图纸被非法获取、篡改或滥用&#xff0c;选择一款高效的CAD图纸加密软件显得尤为重要。本文将为您推荐2024年市场上十款好用的CAD图纸加密软件&#xff0c;帮助企业保护…

2024最新50道NLP和人工智能领域面试题+答案(中文+英文双版本)

编者按&#xff1a;分享一个很硬核的免费人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c; 可以当故事来看&#xff0c;轻松学习。 中文版本 自然语言处理 (NLP)已成为语言学、人工智能和计算机科学交叉领域的变革性领域。随着文本数据量的不断增加&…

图形编辑器基于Paper.js教程15:在Paper.js中实现拖拽图片导入画布功能

在现代Web开发中&#xff0c;用户体验是至关重要的。而拖拽文件上传的功能&#xff0c;不仅直观易用&#xff0c;还提升了用户与界面的交互体验。在这篇文章中&#xff0c;我们将探讨如何使用Paper.js和HTML5的拖放API&#xff0c;来实现将图片文件直接拖拽并导入到Paper.js的画…

如何让图片清晰度变高?介绍三种转变方案

如何让图片清晰度变高&#xff1f;在数字化时代&#xff0c;图片的质量直接影响着信息传递的效果。但由于拍摄条件、传输方式或存储时间的限制&#xff0c;我们时常会遇到图片清晰度不足的问题。还好随着技术的进步&#xff0c;现在有多种方法可以有效提升图片的清晰度。下文将…

arm 的模式+异常(7)

1 Byte , 8 bit, HarlfWord , 16bit , word ,32bit. 2 在内存中每一字节都有一个地址与它对应。 3 操作系统的8种模式 用户模式&#xff1a; 不能访问硬件资源&#xff0c;但是可以通过系统调用来访问。 疑问&#xff1a; 那不还是可以访问硬件资源吗&#xff1f; 系统模…

Zookeeper集群如何实现强一致性和高可用,集群数据同步过程

在分布式系统中&#xff0c;通常会面临如下问题&#xff1a; 分布式协调&#xff1a;在分布式环境下&#xff0c;多个节点需要协同工作&#xff0c;确保多个服务之间数据的一致性以及系统的可靠性。 分布式锁&#xff1a;在分布式系统中&#xff0c;多个节点可能需要同时访问共…

ppt模板软件哪个好?这5个工具提供各种类型的PPT模板

在筹备一场关于中元节的精彩演讲时&#xff0c;你是否曾陷入过寻找完美PPT模板的困境&#xff1f;那些千篇一律的设计是否让你觉得乏味&#xff0c;渴望一份创意与美感并存的视觉呈现&#xff1f; 别担心&#xff0c;今天&#xff0c;我将为你揭晓几款宝藏级软件&#xff0c;它…

如何为 Nextcloud 配置自动数据库备份 - 应用程序

自动数据库备份模块简化了生成数据库计划备份的过程。这些备份可以存储在各种位置&#xff0c;包括本地驱动器、FTP 服务器、SFTP 服务器、Dropbox、Google Drive、OneDrive、NextCloud 和 Amazon S3 云存储。用户还可以选择启用自动删除过期备份的功能。此外&#xff0c;用户可…

大模型越狱攻击成功率 (ASR) 评判方法

JailbreakBench (24.04) • Rule-based. The rule-based judge from Zou et al. (2023) based on string matching, • GPT-4. The GPT-4-0613 model used as a judge (OpenAI, 2023), • HarmBench. The Llama-2-13B judge introduced in HarmBench (Mazeika et al., 2024), …

Xinstall助力App推广:落地页跳转,轻松提升转化率

在移动互联网时代&#xff0c;App的推广与运营成为了各行各业的关键一环。然而&#xff0c;许多推广者在落地页跳转App这一环节上遇到了不小的挑战。用户点击落地页后&#xff0c;往往需要经过繁琐的步骤才能跳转到App&#xff0c;这不仅降低了用户体验&#xff0c;还严重影响了…

gaussian-splatting环境配置

本文总结了在windows11下配置gaussian-splatting训练环境的步骤&#xff0c;主要包括gaussian-splatting库的下载、python环境配置、cudatoolkit和pytorch安装、diff-gaussian-rasterization/Simple-knn/plyfile/tdqm库安装&#xff0c;接着利用官方提供的已做好SFM的数据训练模…

vue中点击导航栏,动态改变样式,经典写法

vue中点击导航栏&#xff0c;动态改变样式&#xff0c;经典写法 在vue中&#xff0c;我们通常会有这样的情况&#xff0c;在多个子模块之间&#xff0c;点击其中一个子模块&#xff0c;修改当前点击的子模块的样式。如图&#xff0c;点击B模块时&#xff0c;模块B样式改变&…

【LeetCode】433.最小基因变化

1. 题目 2. 思想 这题的思想很经典&#xff0c;使用bfs求最短路径。相似的题目还有这道题。 把每次合理的变换都记录在队列中&#xff0c;然后先进先出&#xff0c;同时记录出执行的次数&#xff0c;得到最后的结果。同时需要把历史上曾经入队的基因串都放到字典里&#xff0…

IAM 编程访问和 AWS CLI

添加图片注释&#xff0c;不超过 140 字&#xff08;可选&#xff09; IAM 编程访问&#xff08;欢迎来到雲闪世界。&#xff09; IAM 编程访问是指使用访问密钥通过 API 和命令行工具访问 AWS 服务和资源。 当您为 IAM 用户启用编程访问时&#xff0c;您将生成可用于验证和…

萝卜快跑和端到端的自动驾驶(1)

先看一篇论文 2311.18636 (arxiv.org) 这篇论文里有一个非常好的图 比较了一下模块化任务(级联任务)和端到端自动驾驶的区别 首先什么叫模块化任务(级联) 如上图所示&#xff0c;左边的方块中的子方块&#xff0c;是展示了自动驾驶获取数据的途径&#xff0c;这里包括&…