当前位置: 首页 > news >正文

C++——string的模拟实现(下)

目录

成员函数

3.4 修改操作

(3)insert()函数

(4)pop_back()函数

(5)erase()函数

(6)swap()函数

3.5 查找操作

(1)find()函数

 (2)substr()函数

3.6 重载函数

(1)operator=赋值函数

(2)其他比较函数

(3)流插入和流提取

完整代码

结束语


第一篇链接:C++——string的模拟实现(上)

成员函数

3.4 修改操作
(3)insert()函数

insert() 函数用于在字符串的指定位置插入一个字符或字符串。

注意事项:

在移动字符串内容时,需要确保不会覆盖或丢失任何字符。

使用 memcpy() 时,要确保源和目标内存区域不重叠,否则可能导致未定义行为。

string.h:

	// insert()函数 void insert(size_t pos, char ch);	//插入字符void insert(size_t pos, const char* str);	//插入字符串

string.cpp:

// insert()函数
// 插入字符
void string::insert(size_t pos, char ch)
{assert(pos <= _size);if (_capacity == _size){size_t newcapacity = _capacity == 0 ? 4 : 2 * _capacity;reserve(newcapacity);}size_t end = _size + 1;// 挪动元素while (pos < end){_str[end] = _str[end - 1];end--;}_str[pos] = ch;		//将ch放置到pos这个位置++_size;			//更新_size
}// 插入字符串
void string::insert(size_t pos, const char* str)
{assert(pos <= _size);size_t len = strlen(str);	// 要插入的字符串长度if (_size + len > _capacity){reserve(_size + len);}// 从后向前移动字符串内容以腾出空间  for (size_t i = _size; i >= pos; --i){_str[i + len] = _str[i];}// 复制新字符串到指定位置  memcpy(_str + pos, str, len);// 添加新的字符串结束符  _str[_size + len] = '\0';// 更新字符串长度  _size += len;
}

来个简单的代码测试一下:

(4)pop_back()函数

pop_back() 函数用于移除字符串末尾的字符。

实现:将字符串末尾的字符设置为 '\0'。 更新字符串长度 _size。

string.h:

// pop_back()函数
void pop_back();

string.cpp:

// pop_back()函数
void string::pop_back()
{_str[_size - 1] = '\0';--_size;
}
(5)erase()函数

erase() 函数用于从字符串中移除指定位置的字符或子字符串。

string.h:

// erase()函数
void erase(size_t pos = 0, size_t len = npos);

string.cpp:

// erase()函数
void string::erase(size_t pos,size_t len)
{assert(pos < _size);				 if (len == npos || len >= _size - pos){_str[pos] = '\0';		// 位置pos置为'\0'_size = pos;			// 有效元素个数为pos个}else	// len小于后面的字符个数{// 将后面的字符拷贝到pos位置strcpy(_str + pos, _str + pos + len);_size -= len;			// 更新有效元素}
}

erase()需要额外定义一个类成员变量npos来实现,它为无符号数的-1,一般为整型的最大值。

string.h:

public:static const size_t npos;

string.cpp:

const size_t string::npos = -1;

简单的对上面两个函数进行测试:

(6)swap()函数

swap() 函数用于交换两个字符串的内容。

string.h:

// swap()函数
void swap(string& str);

string.cpp:

// swap()函数
void string::swap(string& str)
{// 这里我们调用std库中的swap()函数std::swap(_str, str._str);std::swap(_capacity, str._capacity);std::swap(_size, str._size);
}

测试:

3.5 查找操作
(1)find()函数

find() 函数用于在字符串中查找指定字符或子字符串的位置。

我们在这里实现从指定位置开始向后遍历查找指定字符或者子字符串。

如果找到,则返回子字符串在字符串中的起始位置;否则返回 npos。

string.h:

// find()函数
size_t find(char ch, size_t pos);
size_t find(const char* str, size_t pos);

string.cpp:

// find()函数
// 寻找字符
size_t string::find(char ch, size_t pos)
{for (int i = pos; i < _size; i++){if (_str[i] == ch){return i;}}return npos;
}// 从pos开始寻找字符串
size_t string::find(const char* str, size_t pos)
{char* p = strstr(_str + pos, str);if (p){return p - _str;}else{return npos;}
}
 (2)substr()函数

substr() 函数用于获取字符串的子字符串。

string.h:

// substr()函数
string substr(size_t pos = 0, size_t len = npos);

string.cpp:

// substr()函数
string string::substr(size_t pos, size_t len)
{string str;if (len == npos || len >= _size - pos){for (size_t i = pos; i < _size; i++){str += _str[i];}}else{for (size_t i = pos; i < pos + len; i++){str += _str[i];}}return str;
}
3.6 重载函数

在C++中,函数重载允许我们为同一函数名创建多个版本,这些版本可以有不同的参数列表(参数的数量或类型不同)。通过这种方式,我们可以使代码更加简洁和易于理解。

(1)operator=赋值函数

赋值运算符(operator=)用于将一个对象的内容复制到另一个对象中。对于自定义的字符串类,我们需要自己实现这个运算符,以确保正确地管理内存。

string.h:

// operator=赋值函数
string& operator=(const string& s);

string.cpp:

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

来测试一下:

这里我们可以对以上的代码进行优化:

// operator= 函数
string& string::operator=(const string& str)
{if (this != &str){string tmp(str._str);	// 调用构造函数swap(tmp);				// 将tmp与this交换}return *this;
}

原始实现中,我们首先检查自赋值(即对象试图将自己赋值给自己),然后分配足够的内存来存储新字符串,复制内容,并释放旧内存。这种方法虽然有效,但可能会导致性能问题,特别是当字符串很长时,因为涉及到多次内存分配和释放。

优化后的实现采用了“拷贝-交换”技术。这种方法通过创建一个临时对象来存储要赋值的字符串,然后使用swap函数交换临时对象和当前对象的内容。由于swap函数通常实现得非常高效(只需交换指针),这种方法可以显著提高性能,并减少内存分配的次数。

(2)其他比较函数

每个比较运算符都基于strcmp函数的返回值来实现。

这些函数之间是可以复用的。

string.h:

// 比较函数
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;

string.cpp:

// 比较函数
bool string::operator<(const string& str) const
{return strcmp(_str, str._str) < 0;
}
bool string::operator<=(const string& str) const
{return *this < str || *this == str;
}
bool string::operator>(const string& str) const
{return !(*this <= 0);
}
bool string::operator>=(const string& str) const
{return !(*this <= str);
}
bool string::operator==(const string& str)const
{return strcmp(_str, str._str) == 0;
}
bool string::operator!=(const string& str)const
{return !(*this == str);
}void string::clear()
{_str[0] = '\0';_size = 0;
}
(3)流插入和流提取

我们接下来试着实现流插入和流提取:

注意,我们不能将这两个函数定义放在string类里

在 C++ 中,当我们使用 std::cout << d1 或 std::cin >> d1 这样的表达式时,左侧的 std::cout 或 std::cin 是对象,而右侧的 d1 是我们想要输出或输入的数据。运算符函数需要能够接受这两个对象作为参数。 如果 << 或 >> 运算符被定义为 std::string 的成员函数,那么它们将需要额外的 this 指针来访问类的成员变量,这将导致需要三个参数(this 指针,左操作数,右操作数),这与标准的运算符用法不兼容。

string.h:

//流插入和流提取
istream& operator>>(istream& is, string& str);
ostream& operator<<(ostream& os, const string& str);

string.cpp:

// 流输入
istream& operator>>(istream& is, string& str)
{// 清除字符串 str 中的现有内容  str.clear();char ch;// 从输入流 is 中读取第一个字符到 ch 中  ch = is.get();// 定义一个字符数组(缓冲区)buffchar buff[128];size_t i = 0;// 循环读取字符,直到遇到空格或换行符为止  while (ch != ' ' && ch != '\n'){// 将字符 ch 存储到缓冲区 buff 的当前位置  buff[i++] = ch;  if (i == 127){// 在缓冲区末尾添加字符串结束符 '\0'buff[i++] = '\0';str += buff;// 重置索引 i,为下一轮存储字符做准备  i = 0;}// 从输入流中读取下一个字符到 ch 中  ch = is.get();}// 循环结束后,检查缓冲区中是否还有未处理的字符  if (i > 0){// 在缓冲区末尾添加字符串结束符 '\0'  buff[i] = '\0';// 将缓冲区的内容追加到字符串 str 中  str += buff;}return is;
}
// 流提取
ostream& operator<<(ostream& os, const string& str)
{for (size_t i = 0; i < str.size(); i++){os << str[i];}return os;
}

测试一下:

完整代码

string.h:

#include<iostream>
#include<assert.h>
#include<stdbool.h>
using namespace std;namespace My_string
{class string{public:typedef char* iterator;			//将char*重命名为iteratortypedef const char* const_iterator;//const版本的iteratorconst_iterator begin() const;	//提供const_iterator begin()函数const_iterator end() const;		//提供const_iterator end()函数//非const版本的iteratoriterator begin();				//提供iterator begin()函数iterator end();					//提供iterator end()函数string(const char* str = " ");	//构造函数~string();						//析构函数string(const string& str);		//拷贝构造函数const char* c_str() const;		// c_str()函数size_t size() const;			// size()函数size_t capacity() const;		// capacity()函数bool empty() const;				// empty()函数// resize()函数void resize(size_t n, char ch = '\0');// 非const版本char& operator[](size_t pos);	//operator[]函数// const版本const char& operator[](size_t pos)const;// 预留空间void reserve(size_t n);// 尾插一个字符void push_back(char ch);// 尾插一个字符串void append(const char* str);//operator+=函数可以构成重载,函数名相同,参数不同string& operator+=(char ch);			// 字符相加string& operator +=(const char* str);	// 字符串相加// insert()函数 void insert(size_t pos, char ch);	//插入字符void insert(size_t pos, const char* str);	//插入字符串// erase()函数void erase(size_t pos = 0, size_t len = npos);// pop_back()函数void pop_back();// find()函数size_t find(char ch, size_t pos);size_t find(const char* str, size_t pos);// substr()函数string substr(size_t pos = 0, size_t len = npos);// operator=赋值函数string& operator=(const string& s);// swap()函数void swap(string& str);// 比较函数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;// clear()函数void clear();public:static const size_t npos;private:char* _str;			// 指向字符串的指针size_t _size;		// 有效字符个数size_t _capacity;	// 有效空间个数};//流插入和流提取istream& operator>>(istream& is, string& str);ostream& operator<<(ostream& os, const string& str);
}

string.cpp:

#include"string.h"
namespace My_string 
{const size_t string::npos = -1;string::iterator string::begin(){return _str;}string::iterator string::end(){return _str + _size;}string::const_iterator string::begin() const{return _str;}string::const_iterator string::end() const{return _str + _size;}// 构造函数string::string(const char* str){_size = strlen(str);_capacity = _size;_str = new char[_capacity + 1];		// +1用于储存'\0'strcpy(_str, str);}// 析构函数string::~string(){delete[] _str;_str = nullptr;_size = _capacity = 0;}// 拷贝构造函数(1)string::string(const string& str){_str = new char[str._capacity + 1];	//额外多给一个空间,用于存放'/0'strcpy(_str, str._str);		//拷贝数据_capacity = str._capacity;	//设置容量_size = str._size;			//设置有效数据个数}// 拷贝构造函数(2)//string::string(const string& str)//{//	string tmp(str._str);//	std::swap(tmp._str, _str);//	std::swap(tmp._size, _size);//	std::swap(tmp._capacity, _capacity);//}// 拷贝构造函数(3)//string::string(const string& str)//{//	string tmp(str._str);//	swap(tmp);			// 这里的swap我们接下来会定义//}// c_str()函数const char* string::c_str() const{return _str;}// size()函数size_t string::size() const{return _size;}// capacity()函数size_t string::capacity() const{return _capacity;}// empty()函数bool string::empty() const{return _size == 0;}// operator[]函数char& string::operator[](size_t pos){assert(pos < _size);return _str[pos];}// const版本const char& string::operator[](size_t pos)const{assert(pos < _size);return _str[pos];}// 预留空间void string::reserve(size_t n){if (n > _capacity){char* tmp = new char[n + 1];strcpy(tmp, _str);delete[] _str;_str = tmp;_capacity = n;}}// resize()函数void string::resize(size_t n, char ch){if (n > _size){if (n > _capacity){reserve(n);}// 使用 memset 函数将字符 ch // 填充到新添加的空间中memset(_str + _size, ch, n - _size);}_size = n;_str[n] = '\0';}//尾插一个字符void string::push_back(char ch){if (_capacity == _size){size_t newcapacity = _capacity == 0 ? 4 : 2 * _capacity;reserve(newcapacity);}_str[_size] = ch;_str[_size + 1] = '\0';_size++;}//尾插一个字符串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()函数push_back(ch);		return *this;}string& string::operator+=(const char* str){append(str);return *this;}// insert()函数// 插入字符void string::insert(size_t pos, char ch){assert(pos <= _size);if (_capacity == _size){size_t newcapacity = _capacity == 0 ? 4 : 2 * _capacity;reserve(newcapacity);}size_t end = _size + 1;// 挪动元素while (pos < end){_str[end] = _str[end - 1];end--;}_str[pos] = ch;		//将ch放置到pos这个位置++_size;			//更新_size}// 插入字符串void string::insert(size_t pos, const char* str){assert(pos <= _size);size_t len = strlen(str);	// 要插入的字符串长度if (_size + len > _capacity){reserve(_size + len);}// 从后向前移动字符串内容以腾出空间  for (size_t i = _size; i >= pos; --i){_str[i + len] = _str[i];}// 复制新字符串到指定位置  memcpy(_str + pos, str, len);// 添加新的字符串结束符  _str[_size + len] = '\0';// 更新字符串长度  _size += len;}// erase()函数void string::erase(size_t pos,size_t len){assert(pos < _size);				 if (len == npos || len >= _size - pos){_str[pos] = '\0';		// 位置pos置为'\0'_size = pos;			// 有效元素个数为pos个}else	// len小于后面的字符个数{// 将后面的字符拷贝到pos位置strcpy(_str + pos, _str + pos + len);_size -= len;			// 更新有效元素}}// pop_back()函数void string::pop_back(){_str[_size - 1] = '\0';--_size;}// find()函数// 寻找字符size_t string::find(char ch, size_t pos){for (int i = pos; i < _size; i++){if (_str[i] == ch){return i;}}return npos;}// 从pos开始寻找字符串size_t string::find(const char* str, size_t pos){char* p = strstr(_str + pos, str);if (p){return p - _str;}else{return npos;}}// substr()函数string string::substr(size_t pos, size_t len){string str;if (len == npos || len >= _size - pos){for (size_t i = pos; i < _size; i++){str += _str[i];}}else{for (size_t i = pos; i < pos + len; i++){str += _str[i];}}return str;}// operator= 函数//string& string::operator=(const string& str)//{//	if (this != &str)//	{//		char* tmp = new char[str._capacity + 1];//		strcpy(tmp, str._str);//		delete[] _str;//		_str = tmp;//		_size = str._size;//		_capacity = str._capacity;//	}//	return *this;//}// operator= 函数string& string::operator=(const string& str){if (this != &str){string tmp(str._str);	// 调用构造函数swap(tmp);				// 将tmp与this交换}return *this;}// swap()函数void string::swap(string& str){// 这里我们调用std库中的swap()函数std::swap(_str, str._str);std::swap(_capacity, str._capacity);std::swap(_size, str._size);}// 比较函数bool string::operator<(const string& str) const{return strcmp(_str, str._str) < 0;}bool string::operator<=(const string& str) const{return *this < str || *this == str;}bool string::operator>(const string& str) const{return !(*this <= 0);}bool string::operator>=(const string& str) const{return !(*this <= str);}bool string::operator==(const string& str)const{return strcmp(_str, str._str) == 0;}bool string::operator!=(const string& str)const{return !(*this == str);}void string::clear(){_str[0] = '\0';_size = 0;}// 流输入istream& operator>>(istream& is, string& str){// 清除字符串 str 中的现有内容  str.clear();char ch;// 从输入流 is 中读取第一个字符到 ch 中  ch = is.get();// 定义一个字符数组(缓冲区)buffchar buff[128];size_t i = 0;// 循环读取字符,直到遇到空格或换行符为止  while (ch != ' ' && ch != '\n'){// 将字符 ch 存储到缓冲区 buff 的当前位置  buff[i++] = ch;  if (i == 127){// 在缓冲区末尾添加字符串结束符 '\0'buff[i++] = '\0';str += buff;// 重置索引 i,为下一轮存储字符做准备  i = 0;}// 从输入流中读取下一个字符到 ch 中  ch = is.get();}// 循环结束后,检查缓冲区中是否还有未处理的字符  if (i > 0){// 在缓冲区末尾添加字符串结束符 '\0'  buff[i] = '\0';// 将缓冲区的内容追加到字符串 str 中  str += buff;}return is;}// 流提取ostream& operator<<(ostream& os, const string& str){for (size_t i = 0; i < str.size(); i++){os << str[i];}return os;}
}

test.cpp:

#include"string.h"
#include<iostream>using namespace std;void test1()
{// 测试构造函数  My_string::string s1("Hello");cout << "s1: " << s1.c_str() << endl;// 测试拷贝构造函数  /*My_string::string s2(s1);cout << "s2 (s1): " << s2.c_str() << endl;	*/
}void test2()
{My_string::string str("Hello");str[0] = 'h';cout << str.c_str() << endl;//使用operator[]函数打印for (size_t i = 0; i < str.size(); i++){cout << str[i] << " ";}cout << endl;
}void test3()
{My_string::string str("hello");for (auto i : str){cout << i << " ";}cout << endl;My_string::string::iterator it1 = str.begin();while (it1 != str.end()){cout << *it1 << " ";++it1;}cout << endl;My_string::string::iterator it2 = str.end();if (it2 != str.begin()) { // 检查避免直接解引用 end()  --it2; // 先移动到一个有效的位置  while (it2 != str.begin()){std::cout << *it2 << " ";--it2;}std::cout << *it2 << " "; // 输出最后一个字符(begin() 之前的字符)  }std::cout << std::endl;
}void test4()
{My_string::string str("hello");cout << str.c_str() << endl;str.push_back('A');cout << str.c_str() << endl;str.append("world");cout << str.c_str() << endl;str += 'C'; cout << str.c_str() << endl;
}void test5()
{My_string::string str("hello world");str.insert(6, 'x');cout << str.c_str() << endl;str.insert(6, "yyyyy");cout << str.c_str() << endl;str.insert(0, 'X');cout << str.c_str() << endl;
}void test6()
{My_string::string str("hello world");str.pop_back();cout << str.c_str() << endl;str.erase(2, 3);cout << str.c_str() << endl;
}void test7()
{My_string::string str("hello world");cout << str.find('l', 0) << endl;cout << str.find("ld", 0) << endl;
}void test8()
{My_string::string str1("hello");My_string::string str2("world");cout << str1.c_str() << endl;cout << str2.c_str() << endl;str1.swap(str2);cout << str1.c_str() << endl;cout << str2.c_str() << endl;
}void test9()
{My_string::string str("hello World");cout << str.substr(2, 2) << endl;cout << str.substr(7, 3) << endl;
}void test10()
{My_string::string str1("hello world");My_string::string str2("xxxxxxxxxxx");str1 = str2;cout << str1.c_str() << endl;cout << str2.c_str() << endl;My_string::string str3("yyyyy");str1 = str3;cout << str1.c_str() << endl;cout << str3.c_str() << endl;
}void test11()
{My_string::string str("hello");str.resize(10, '*');cout << str.c_str() << endl;str.reserve(15);cout << str.c_str() << endl;
}void test12()
{My_string::string str("XXX");cin >> str;cout << str << endl;
}int main()
{//test1();//test2();//test3();//test4();//test5();//test6();//test7();//test8();//test9();//test10();//test11();test12();return 0;
}

结束语

实验周太忙啦!!!一直没时间写。。。

感谢各位大佬的阅读!!!

求点赞收藏评论关注!!!

相关文章:

C++——string的模拟实现(下)

目录 成员函数 3.4 修改操作 (3)insert()函数 (4)pop_back()函数 (5)erase()函数 (6)swap()函数 3.5 查找操作 (1)find()函数 (2)substr()函数 3.6 重载函数 (1)operator赋值函数 (2)其他比较函数 (3)流插入和流提取 完整代码 结束语 第一篇链接&#xff1a;C——…...

面试 Java 基础八股文十问十答第二十九期

面试 Java 基础八股文十问十答第二十九期 作者&#xff1a;程序员小白条&#xff0c;个人博客 相信看了本文后&#xff0c;对你的面试是有一定帮助的&#xff01;关注专栏后就能收到持续更新&#xff01; ⭐点赞⭐收藏⭐不迷路&#xff01;⭐ 1&#xff09;类加载过程 类加载…...

454.四数相加||

题目: 454. 四数相加 II - 力扣&#xff08;LeetCode&#xff09; 思路: 考虑到时间复杂度问题&#xff0c;本题最重要的是要将四个数组划分成两个部分&#xff0c;每个部分(n^2)的时间复杂度&#xff0c;选取数据结构时&#xff0c;考虑到既要存储元素(key),又要有元素次数…...

禅道源码部署

文章目录 禅道部署1.环境部署安装httpd和mariadb安装php 2.安装禅道首先进行httpd服务的配置安装禅道 禅道部署 1.环境部署 安装lamp环境 组件版本httpdyum安装mariadbyum安装phpphp-7.4.33 选择一个php版本就行&#xff0c;我们这里选择的是7.4.33 安装httpd和mariadb [r…...

️ Vulnhuntr:利用大型语言模型(LLM)进行零样本漏洞发现的工具

在网络安全领域&#xff0c;漏洞的发现和修复是保护系统安全的关键。今天&#xff0c;我要向大家介绍一款创新的工具——Vulnhuntr&#xff0c;这是一款利用大型语言模型&#xff08;LLM&#xff09;进行零样本漏洞发现的工具&#xff0c;能够自动分析代码&#xff0c;检测远程…...

【Android】多渠道打包配置

目录 简介打包配置签名配置渠道配置配置打包出来的App名称正式包与测试包配置 打包方式开发工具打包命令行打包 优缺点 简介 多渠道打包 是指在打包一个 Android 应用时&#xff0c;一次编译生成多个 APK 文件&#xff0c;每个 APK 文件针对一个特定的渠道。不同的渠道可能代表…...

Spring Boot Configuration和AutoConfiguration加载逻辑和加载顺序调整

在spring中, AutoConfiguration也是一个种Configuration,只是AutoConfiguration是不能使用proxy的。 而且spring对于两者的加载顺序也不是一视同仁,是有顺序的。spring会先加载@SpringBootApplication可达的且标注了@Configuration的类,这个过程会将@AutoConfiguration标注…...

点餐系统需求分析说明书(软件工程分析报告JAVA)

目录 1 引言 4 1.1 编写目的 4 1.2 项目背景 4 1.3 定义 4 1.4 预期的读者 5 1.5 参考资料 5 2 任务概述 5 2.1 目标 5 2.2 运行环境 5 2.3 条件与限制 6 3 数据描述 6 3.1 静态数据 6 3.2 动态数据 6 3.3 数据库介绍 6 3.4 对象模型 6 3.5 数据采集 7 4 动态模型 7 4.1 脚本 …...

Python条形图 | 指标(特征)重要性图的绘制

在数据科学和机器学习的工作流程中&#xff0c;特征选择是一个关键步骤。通过评估每个特征对模型预测能力的影响&#xff0c;我们可以选择最有意义的特征&#xff08;指标&#xff09;&#xff0c;从而提高模型的性能并减少过拟合。本文将介绍如何使用 Python 的 Seaborn 和 Ma…...

危险物品图像分割系统:一键训练

危险物品图像分割系统源码&#xff06;数据集分享 [yolov8-seg-GFPN&#xff06;yolov8-seg-CSwinTransformer等50全套改进创新点发刊_一键训练教程_Web前端展示] 1.研究背景与意义 项目参考ILSVRC ImageNet Large Scale Visual Recognition Challenge 项目来源AAAI Global…...

城市景色视频素材下载好去处

在制作短视频、Vlog 或商业宣传片时&#xff0c;城市景色视频素材能为作品增添现代感与活力。繁华都市、流光溢彩的夜景、清晨街道等都是展现城市魅力的好素材。那么城市景色视频素材去哪里下载呢&#xff1f; 蛙学网 是专为短视频创作者打造的素材平台&#xff0c;城市景色素材…...

基于SSM美容院管理系统的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;用户管理&#xff0c;套餐类型管理&#xff0c;美容预约管理&#xff0c;生日提醒管理&#xff0c;管理员管理&#xff0c;系统管理 员工账号功能包括&#xff1a;系统首页&#xff0c;个人中心&#…...

Threejs 实现3D 地图(04)3d 地图的柱状图和文字显示

3d 地图的数据展示 代码仓库&#xff1a; King/threejs-3d-map 核心代码&#xff1a; function createText(feature, level, font) {if (feature.properties.name) {const [x_XYZ, y_XYZ] handleProject(feature.properties.center)// 缺点&#xff1a;首次渲染很慢 无法使…...

Oracle 第2章:安装与配置Oracle

安装与配置Oracle数据库是一项复杂但有序的过程。以下是对Oracle数据库安装与配置的概述&#xff0c;包括系统需求与硬件推荐&#xff0c;以及详细的安装步骤。 系统需求与硬件推荐 系统需求 在安装Oracle数据库之前&#xff0c;需要确保目标系统满足Oracle官方规定的最低要…...

动态规划 —— 斐波那契数列模型-解码方法

1. 解码方法 题目链接&#xff1a; 91. 解码方法 - 力扣&#xff08;LeetCode&#xff09;https://leetcode.cn/problems/decode-ways/description/ 2. 题目解析 1. 对字母A - Z进行编码1-26 2. 11106可以解码为1-1-10-6或者11-10-6, 但是11-1-06不能解码 3. 0n不能解码 4. …...

PPT / Powerpoint中利用LaTeX输入公式

PPT / Powerpoint中利用LaTeX输入公式_ppt插入latex公式-CSDN博客文章浏览阅读2.8w次&#xff0c;点赞42次&#xff0c;收藏75次。新版的Word&#xff08;Office 2016后&#xff1f;&#xff09;是支持LaTeX公式输入的&#xff0c;但是Powerpoint并不支持。下面介绍如何利用。_…...

C++ 模板专题 - 类型擦除

一&#xff1a;概述 C 中的类型擦除&#xff08;Type Erasure&#xff09;是一种技术&#xff0c;允许你在不暴露具体类型信息的情况下&#xff0c;通过统一的接口处理不同的类型。这种技术常用于实现泛型编程&#xff0c;特别是在需要支持多种不同类型的情况下&#xff0c;如容…...

RuoYi-Vue项目 重点代码讲解

1. RuoYi-Vue项目 常规说明&#xff1a; ruoyi-admin&#xff1a;后台接口开发&#xff08;主要存放控制层相关代码&#xff09;ruoyi-common&#xff1a;通用工具ruoyi-framework&#xff1a;框架核心ruoyi-generator&#xff1a;代码生成&#xff08;可以移除&#xff09;r…...

pandas习题 024:用字典构造 DataFrame

编码题)用 Python 的字典构造一个 DataFrame,它有 a、b 两列,三行数据。其中 a 列值为 1、4、7,b 列值为 2、5、8,索引为 x、y、z。 即: ‘’’ a b x 1 2 y 4 5 z 7 8 ‘’’ import pandas as pddf = pd.DataFrame({a: [1, 4,...

如何在Node.js中执行解压缩文件操作

一、解压文件 1.安装依赖&#xff1a; 安装adm-zip依赖包&#xff1a;npm install adm-zip --save 安装iconv-lite依赖包&#xff1a;npm install iconv-lite --save 解压前的file文件夹结构&#xff1a; update-1.0.2.zip压缩包内容&#xff1a; 2.在depresssFile.js文件&…...

CTF show Web 红包题第六弹

提示 1.不是SQL注入 2.需要找关键源码 思路 进入页面发现是一个登录框&#xff0c;很难让人不联想到SQL注入&#xff0c;但提示都说了不是SQL注入&#xff0c;所以就不往这方面想了 ​ 先查看一下网页源码&#xff0c;发现一段JavaScript代码&#xff0c;有一个关键类ctfs…...

(十)学生端搭建

本次旨在将之前的已完成的部分功能进行拼装到学生端&#xff0c;同时完善学生端的构建。本次工作主要包括&#xff1a; 1.学生端整体界面布局 2.模拟考场与部分个人画像流程的串联 3.整体学生端逻辑 一、学生端 在主界面可以选择自己的用户角色 选择学生则进入学生登录界面…...

Fabric V2.5 通用溯源系统——增加图片上传与下载功能

fabric-trace项目在发布一年后,部署量已突破1000次,为支持更多场景,现新增支持图片信息上链,本文对图片上传、下载功能代码进行梳理,包含智能合约、后端、前端部分。 一、智能合约修改 为了增加图片信息上链溯源,需要对底层数据结构进行修改,在此对智能合约中的农产品数…...

NXP S32K146 T-Box 携手 SD NAND(贴片式TF卡):驱动汽车智能革新的黄金组合

在汽车智能化的汹涌浪潮中&#xff0c;车辆不再仅仅是传统的交通工具&#xff0c;而是逐步演变为高度智能的移动终端。这一转变的核心支撑&#xff0c;来自于车内关键技术的深度融合与协同创新。车载远程信息处理盒&#xff08;T-Box&#xff09;方案&#xff1a;NXP S32K146 与…...

scikit-learn机器学习

# 同时添加如下代码, 这样每次环境(kernel)启动的时候只要运行下方代码即可: # Also add the following code, # so that every time the environment (kernel) starts, # just run the following code: import sys sys.path.append(/home/aistudio/external-libraries)机…...

计算机基础知识解析:从应用到架构的全面拆解

目录 前言 1、 计算机的应用领域&#xff1a;无处不在的数字助手 2、 计算机的进化史&#xff1a;从算盘到量子计算 3、计算机的分类&#xff1a;不止 “台式机和笔记本” 4、计算机的组件&#xff1a;硬件与软件的协同 4.1 硬件&#xff1a;五大核心部件 4.2 软件&#…...

R 语言科研绘图第 55 期 --- 网络图-聚类

在发表科研论文的过程中&#xff0c;科研绘图是必不可少的&#xff0c;一张好看的图形会是文章很大的加分项。 为了便于使用&#xff0c;本系列文章介绍的所有绘图都已收录到了 sciRplot 项目中&#xff0c;获取方式&#xff1a; R 语言科研绘图模板 --- sciRplothttps://mp.…...

C语言中提供的第三方库之哈希表实现

一. 简介 前面一篇文章简单学习了C语言中第三方库&#xff08;uthash库&#xff09;提供对哈希表的操作&#xff0c;文章如下&#xff1a; C语言中提供的第三方库uthash常用接口-CSDN博客 本文简单学习一下第三方库 uthash库对哈希表的操作。 二. uthash库哈希表操作示例 u…...

PHP 8.5 即将发布:管道操作符、强力调试

前不久&#xff0c;PHP宣布了即将在 2025 年 11 月 20 日 正式发布的 PHP 8.5&#xff01;作为 PHP 语言的又一次重要迭代&#xff0c;PHP 8.5 承诺带来一系列旨在提升代码可读性、健壮性以及开发者效率的改进。而更令人兴奋的是&#xff0c;借助强大的本地开发环境 ServBay&am…...

springboot 日志类切面,接口成功记录日志,失败不记录

springboot 日志类切面&#xff0c;接口成功记录日志&#xff0c;失败不记录 自定义一个注解方法 import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target;/***…...