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

C++中string类的模拟实现

目录

1.string类的结构

2.默认成员函数

2.1.默认构造函数

2.2拷贝构造函数 

2.3赋值运算符重载 

2.4析构函数

 3.迭代器(Iterators)

4.string类的空间操作(Capacity)

4.1size()

4.2capacity()

4.3clear() 

4.4reserve()

5.元素访问(Element access)

6.string类的修改操作(Modifiers) 

6.1push_back()

6.2append() 

6.3operator+=()

6.4swap()

6.5insert() 

6.6 erase()

7.字符串操作(String operations) 

7.1c_str()

7.2find()

7.3substr()

8.非成员函数重载(Non-member function overloads) 

8.1关系运算符(relational operators)

8.2输入输出重载(operator>> and operator<<) 

 8.2.1输出运算符重载

8.2.2输入运算符重载

9.参考代码

9.1string.h 

9.2string.cpp

9.3Test.cpp 


1.string类的结构

		char* _str = nullptr;size_t _capacity = 0;size_t _size = 0;//这里可以直接给默认值,相当于定义,因为有const,只有整型可以//static const size_t npos = -1;static const size_t npos;

        string类结构里有一个_str指针,指向存储字符的数组,_capacity表示当前string的空间大小,_size表示当前string中的有效元素个数,静态常量npos默认等于-1,表示整形的最大值。 

2.默认成员函数

2.1.默认构造函数

		//默认构造函数string()//直接给空指针在使用.c_str()时进行打印对空指针进行了解引用:_str(new char[1] {'\0'})//:_str(nullptr),_size(0),_capacity(0){}//带参的构造string(const char* str){_size = strlen(str);//_capacity不包含\0_capacity = _size;//开空间的时候多开一个用于存储\0_str = new char[_capacity + 1];strcpy(_str, str);}

        这里的默认构造函数不能给_str空指针,如果是个空串进行打印的话,会对空指针进行解引用会导致程序崩溃。 因为要存一个'\0',所以空串也要开一个空间。

        这里可以把上述两个构造合成一个构造函数。

//将上述两个构造函数合并成一个全缺省的构造函数
string(const char* str = "")	//空的常量字符串默认包含一个\0
{_size = strlen(str);_capacity = _size;_str = new char[_capacity + 1];strcpy(_str, str);	//strcpy先拷贝再判断,会拷贝\0
}

2.2拷贝构造函数 

        1.传统写法

//传统写法
string(const string& s)
{_str = new char[s._capacity + 1];    //多开一个空间给'\0'strcpy(_str, s._str);                //拷贝数据_size = s._size;_capacity = s._capacity;
}

        2.现代写法

void swap(string& s) 
{std::swap(_str, s._str);std::swap(_size, s._size);std::swap(_capacity, s._capacity);
}//现代写法
string(const string& s)
{string tmp(s._str);swap(tmp);
}

        这里调用库里面的交换函数,交换string结构里面的数据。然后在拷贝函数中用被拷贝的string对象s中的_str构造一个临时对象,然后进行交换,函数结束之后这个临时对象自动销毁,构造出一个与s一样的新对象。

2.3赋值运算符重载 

         1.写法1

		string& operator=(const string& s){if (this != &s)    //检测是否是自己给自己赋值{delete[] _str;    //释放原来对象的空间_str = new char[s._capacity + 1];    //new一个和s一样大的空间strcpy(_str, s._str);    //拷贝数据_size = s._size;_capacity = s._capacity;}return *this;}

        2.写法2 

		string& operator=(const string& s){if (this != &s){string tmp(s);swap(tmp);}return *this;}

        这个和拷贝函数的现代写法思路一样。

        3.写法3

		string& operator=(string tmp){swap(tmp);	//这里虽然tmp被交换了,但是形参的改变不影响实参return *this;}

        这里直接使用传值传参,然后进行交换,函数结束之后并不会影响实参。 

2.4析构函数

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

 3.迭代器(Iterators)

		// iteratortypedef char* iterator;typedef const char* const_iterator;iterator begin(){return _str;}iterator end(){return _str + _size;}const_iterator begin() const    //函数重载,重载迭代器用于const对象{return _str;}const_iterator end() const{return _str + _size;}

         因为string的底层是利用数组进行存储的,所以这里直接利用原始指针作为迭代器即可,用两个typedef关键字将char*类型和const char*类型改为迭代器的名字。

4.string类的空间操作(Capacity)

4.1size()

		size_t size() const{return _size;}

4.2capacity()

		size_t capacity() const{return _capacity;}

4.3clear() 

         清除string对象里面的数据,但是这里不缩容_capacity不改变。

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

4.4reserve()

         该函数在string.cpp里面实现的,所以加上了类域限定符.

	void string::reserve(size_t n){if (n > _capacity){char* tmp = new char[n + 1];strcpy(tmp, _str);delete[] _str;_str = tmp;_capacity = n;}}

5.元素访问(Element access)

        这里仅实现[]的重载。 

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

6.string类的修改操作(Modifiers

6.1push_back()

        尾插一个字符.

	void string::push_back(char c){//扩容if (_size == _capacity){reserve(_capacity == 0 ? 4 : _capacity * 2);}_str[_size] = c;++_size;_str[_size] = '\0';}

6.2append() 

        尾插一个字符串.这里扩容保持一个对齐的原则,如果需要的空间大于原来空间的两倍,则需要多少开多少,如果小于原来的两倍,则开2倍.

	void string::append(const char* str){size_t len = strlen(str);    //计算尾插的str大小if (_size + len > _capacity){//需要的空间大于原空寂的2倍,需要多少开多少,小于2倍开2倍reserve((_size + len) > (2 * _capacity) ? (_size + len) : (2 * _capacity));}strcpy(_str + _size, str);_size += len;}

6.3operator+=()

        +=运算符的重载实现能加一个字符,也能加一个字符串,复用上述两个接口进行实现.

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

6.4swap()

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

6.5insert() 

	// 在pos位置上插入字符c/字符串strvoid string::insert(size_t pos, char c){assert(pos <= _size);if (_size == _capacity){reserve(_capacity == 0 ? 4 : _capacity * 2);}//这里用size_t类型头插会出错,因为end永远都小于不了0//size_t end = _size;	//从最后一个\0开始往后挪动数据//用int end在与pos比较时会提升为size_t类型,也会出错//int end = _size;//while (end >= (int)pos)//{//	_str[end + 1] = _str[end];//	end--;//}//挪动数据,_size处是\0,从后面的\0开始挪动size_t end = _size + 1;while (end > pos)    {_str[end] = _str[end - 1];end--;}_str[pos] = c;++_size;}
	//在pos位置插入字符串void string::insert(size_t pos, const char* str){assert(pos <= _size);size_t len = strlen(str);if (_size + len > _capacity){//大于2倍,需要多少扩多少,小于2倍,扩2倍reserve((_size + len) > (2 * _capacity) ? (_size + len) : (2 * _capacity));}//挪动数据size_t end = _size + len;while (end >= pos + len - 1){_str[end] = _str[end - len];--end;}//插入字符串for (size_t i = 0; i < len; i++){_str[pos + i] = str[i];}_size += len;}

6.6 erase()

        如果需要删除的len的长度大于从pos到最后位置的长度,则修正len之后进行删除.

	// 删除pos位置上之后的len个元素void string::erase(size_t pos, size_t len){assert(pos < _size);//如果删除的元素个数大于从pos到最后的个数,修正一下lenif (len >= _size - pos){_str[pos] = '\0';_size = pos;}else{for (size_t i = pos + len; i <= _size; i++){_str[i - len] = _str[i];}_size -= len;}}

7.字符串操作(String operations) 

7.1c_str()

        这里返回string对象中的数组指针,可以说是返回C语言类型的字符串对象.

		//返回string中的指向字符串的指针const char* c_str() const{return _str;}

7.2find()

	// 返回c在string中第一次出现的位置size_t string::find(char c, size_t pos) const{assert(pos < _size);for (size_t i = pos; i < _size; i++){if (_str[i] == c){return i;}}//没找到返回最大的整数return npos;}// 返回子串s在string中第一次出现的位置size_t string::find(const char* s, size_t pos) const{assert(pos < _size);//调用库里面的strstr函数在自身中寻找子串const char* ptr = strstr(_str + pos, s);if (ptr == nullptr){return npos;}else{return ptr - _str;}}

7.3substr()

	//返回子串string string::substr(size_t pos, size_t len) const{assert(pos < _size);//len大于剩余字符的长度,更新一下lenif (len > _size - pos){len = _size - pos;}string sub;sub.reserve(len);for (size_t i = 0; i < len; i++){sub += _str[pos + i];}return sub;}

8.非成员函数重载(Non-member function overloads) 

8.1关系运算符(relational operators)

        字符串的关系运算符与C语言中的compare()类似,这里直接复用库里面的compare()函数.

需要注意的是compare()函数是使用C语言中的字符串格式进行比较的,这里比较的是string对象中_str指向的数组.

//relational operatorsbool 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 || s1 == s2;}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);}

8.2输入输出重载(operator>> and operator<<) 

         这里的输入和输出为什么重载成全局函数请参考C++类和对象(5)--日期类的实现中友元声明中的注释.

 8.2.1输出运算符重载

        遍历string对象一个一个输出即可.

	ostream& operator<<(ostream& _cout, const string& s){for (auto ch : s){_cout << ch;}return _cout;}

8.2.2输入运算符重载

        这里首先先清除s中原有的数据,然后在栈里面开一个256大小的buff(为了减少扩容的次数).这里用get()函数一个一个读取输入的字符,如果用输入运算符的话会忽略输入的空格和换行符.当一个buff满了之后拷贝到s中,跳出循环后如果buff中还有遗留的数据,则全部拷贝到s中.

	istream& operator>>(istream& _cin, string& s){s.clear();const int N = 256;char buff[N];int i = 0;char ch;//in >> ch; 默认会忽略空格和换行符ch = _cin.get();while (ch != ' ' && ch != '\n'){buff[i++] = ch;if (i == N - 1){buff[i] = '\0';s += buff;i = 0;}//in >> ch;ch = _cin.get();}if (i > 0){buff[i] = '\0';s += buff;}return _cin;}

9.参考代码

        string实现在XiaoC这个命名空间中,上述的代码没有做测试,下面给出测试代码,有兴趣可以自行对接口进行测试.

9.1string.h 

#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <assert.h>
#include <string>
using namespace std;namespace XiaoC
{class string{//friend ostream& operator<<(ostream& _cout, const XiaoC::string& s);//friend istream& operator>>(istream& _cin, XiaoC::string& s);public:默认构造函数//string()//	//直接给空指针在使用.c_str()时进行打印对空指针进行了解引用//	:_str(new char[1] {'\0'})//	//:_str(nullptr)//	,_size(0)//	,_capacity(0)//{}//带参的构造//string(const char* str)//{//	_size = strlen(str);//	//_capacity不包含\0//	_capacity = _size;//	//开空间的时候多开一个用于存储\0//	_str = new char[_capacity + 1];//	strcpy(_str, str);//}//将上述两个构造函数合并成一个全缺省的构造函数string(const char* str = "")	//空的常量字符串默认包含一个\0{_size = strlen(str);_capacity = _size;_str = new char[_capacity + 1];strcpy(_str, str);	//strcpy先拷贝再判断,会拷贝\0}//拷贝构造//传统写法//string(const string& s)//{//	_str = new char[s._capacity + 1];//	strcpy(_str, s._str);//	_size = s._size;//	_capacity = s._capacity;//}//现代写法string(const string& s){string tmp(s._str);swap(tmp);}//赋值重载//写法1//string& operator=(const string& s)//{//	if (this != &s)//	{//		delete[] _str;//		_str = new char[s._capacity + 1];//		strcpy(_str, s._str);//		_size = s._size;//		_capacity = s._capacity;//	}//	return *this;//}//写法2//string& operator=(const string& s)//{//	if (this != &s)//	{//		string tmp(s);//		swap(tmp);//	}//	return *this;//}//写法3string& operator=(string tmp){swap(tmp);	//这里虽然tmp被交换了,但是形参的改变不影响实参return *this;}~string(){if (_str){delete[] _str;_str = nullptr;_size = 0;_capacity = 0;}}// iteratortypedef 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;}// modifyvoid push_back(char c);void append(const char* str);string& operator+=(char c);string& operator+=(const char* str);void swap(string& s) {std::swap(_str, s._str);std::swap(_size, s._size);std::swap(_capacity, s._capacity);}//返回string中的指向字符串的指针const char* c_str() const{return _str;}// capacitysize_t size() const{return _size;}size_t capacity() const{return _capacity;}void clear(){_str[0] = '\0';_size = 0;}void reserve(size_t n);// accesschar& operator[](size_t index){assert(index < _size);return _str[index];}const char& operator[](size_t index)const{assert(index < _size);return _str[index];}// 返回c在string中第一次出现的位置size_t find(char c, size_t pos = 0) const;// 返回子串s在string中第一次出现的位置size_t find(const char* s, size_t pos = 0) const;// 在pos位置上插入字符c/字符串strvoid insert(size_t pos, char c);void insert(size_t pos, const char* str);// 删除pos位置上的元素,并返回该元素的下一个位置void erase(size_t pos, size_t len = npos);//返回子串string substr(size_t pos = 0, size_t len = npos) const;private:char* _str = nullptr;size_t _capacity = 0;size_t _size = 0;//这里可以直接给默认值,相当于定义,因为有const,只有整型可以//static const size_t npos = -1;static const size_t npos;};//relational operatorsbool operator<(const string& s1, const string& s2);bool operator==(const string s1, const string& s2);bool operator<=(const string s1, const string& s2);bool operator>(const string s1, const string& s2);bool operator>=(const string s1, const string& s2);bool operator!=(const string s1, const string& s2);ostream& operator<<(ostream& _cout, const string& s);istream& operator>>(istream& _cin, string& s);}

9.2string.cpp

#include "string.h"
namespace XiaoC
{const size_t string::npos = -1;void string::push_back(char c){//扩容if (_size == _capacity){reserve(_capacity == 0 ? 4 : _capacity * 2);}_str[_size] = c;++_size;_str[_size] = '\0';}void string::append(const char* str){size_t len = strlen(str);if (_size + len > _capacity){//大于2倍,需要多少开多少,小于2倍开2倍reserve((_size + len) > (2 * _capacity) ? (_size + len) : (2 * _capacity));}strcpy(_str + _size, str);_size += len;}string& string::operator+=(char c){push_back(c);return *this;}string& string::operator+=(const char* str){append(str);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;}}// 在pos位置上插入字符c/字符串strvoid string::insert(size_t pos, char c){assert(pos <= _size);if (_size == _capacity){reserve(_capacity == 0 ? 4 : _capacity * 2);}//这里用size_t类型头插会出错,因为end永远都小于不了0//size_t end = _size;	//从最后一个\0开始往后挪动数据//用int end在与pos比较时会提升为size_t类型,也会出错//int end = _size;//while (end >= (int)pos)//{//	_str[end + 1] = _str[end];//	end--;//}//挪动数据,_size处是\0,从后面的\0开始挪动size_t end = _size + 1;while (end > pos){_str[end] = _str[end - 1];end--;}_str[pos] = c;++_size;}void string::insert(size_t pos, const char* str){assert(pos <= _size);size_t len = strlen(str);if (_size + len > _capacity){//大于2倍,需要多少扩多少,小于2倍,扩2倍reserve((_size + len) > (2 * _capacity) ? (_size + len) : (2 * _capacity));}size_t end = _size + len;while (end >= pos + len - 1){_str[end] = _str[end - len];--end;}for (size_t i = 0; i < len; i++){_str[pos + i] = str[i];}_size += len;}// 删除pos位置上之后的len个元素void string::erase(size_t pos, size_t len){assert(pos < _size);if (len >= _size - pos){_str[pos] = '\0';_size = pos;}else{for (size_t i = pos + len; i <= _size; i++){_str[i - len] = _str[i];}_size -= len;}}// 返回c在string中第一次出现的位置size_t string::find(char c, size_t pos) const{assert(pos < _size);for (size_t i = pos; i < _size; i++){if (_str[i] == c){return i;}}return npos;}// 返回子串s在string中第一次出现的位置size_t string::find(const char* s, size_t pos) const{assert(pos < _size);const char* ptr = strstr(_str + pos, s);if (ptr == nullptr){return npos;}else{return ptr - _str;}}//返回子串string string::substr(size_t pos, size_t len) const{assert(pos < _size);//len大于剩余字符的长度,更新一下lenif (len > _size - pos){len = _size - pos;}string sub;sub.reserve(len);for (size_t i = 0; i < len; i++){sub += _str[pos + i];}return sub;}//relational operatorsbool 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 || s1 == s2;}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);}ostream& operator<<(ostream& _cout, const string& s){for (auto ch : s){_cout << ch;}return _cout;}istream& operator>>(istream& _cin, string& s){s.clear();const int N = 256;char buff[N];int i = 0;char ch;//in >> ch; 默认会忽略空格和换行符ch = _cin.get();while (ch != ' ' && ch != '\n'){buff[i++] = ch;if (i == N - 1){buff[i] = '\0';s += buff;i = 0;}//in >> ch;ch = _cin.get();}if (i > 0){buff[i] = '\0';s += buff;}return _cin;}
}

9.3Test.cpp

#include "string.h"namespace XiaoC
{//测试构造函数void test_string1(){string s1;string s2("hello world");cout << s1.c_str() << endl;cout << s2.c_str() << endl;}//测试遍历访问void test_string2(){string s1("hello world");cout << s1.c_str() << endl;//[] + 下标访问for (size_t i = 0; i < s1.size(); i++){s1[i] += 2;}cout << s1.c_str() << endl;//范围for底层就是替代为迭代器for (auto e : s1){cout << e << " ";}cout << endl;//通过迭代器遍历访问string::iterator it = s1.begin();while (it != s1.end()){cout << *it << " ";++it;}cout << endl;}//测试增删改查void test_string3(){string s1 = "hello world";s1 += 'x';s1 += 'c';cout << s1.c_str() << endl;s1 += " hello XiaoC";cout << s1.c_str() << endl;string s2 = "abcd";cout << s2.c_str() << endl;s2.insert(0, 'c');cout << s2.c_str() << endl;string s3 = "hello world";cout << s3.c_str() << endl;s3.insert(0, "xxx");cout << s3.c_str() << endl;string s4 = "hello world";cout << s4.c_str() << endl;s4.erase(0, 3);cout << s4.c_str() << endl;string s("test.cpp.zip");size_t pos = s.find('.');string suffix = s.substr(pos);cout << suffix.c_str() << endl;//拷贝构造string copy(s);cout << copy.c_str() << endl;//赋值运算符string s5 = "XiaoC";s5 = s;cout << s5.c_str() << endl;}//测试比较大小void test_string4(){string s1 = "helloworld";string s2 = s1;cout << (s1 == s2) << endl;cout << (s1 < s2) << endl;}//测试输入输出void test_string5(){string s1 = "hello world";cout << s1 << endl;string s2;cin >> s2;cout << s2 << endl;}//测试返回字串void test_string6(){string s1 = "hello world";string s2;s2 = s1.substr(6, 5);cout << s2 << endl;}
}
int main()
{//XiaoC::test_string1();//XiaoC::test_string2();//XiaoC::test_string3();//XiaoC::test_string4();XiaoC::test_string5();//XiaoC::test_string6();return 0;
}

 

 

 

相关文章:

C++中string类的模拟实现

目录 1.string类的结构 2.默认成员函数 2.1.默认构造函数 2.2拷贝构造函数 2.3赋值运算符重载 2.4析构函数 3.迭代器(Iterators) 4.string类的空间操作(Capacity) 4.1size() 4.2capacity() 4.3clear() 4.4reserve() 5.元素访问(Element access) 6.string类的修…...

C++函数在库中的地址

本文讲述C如何直接调用动态库dll或者so中的函数。 首先我们准备一个被调用库&#xff0c;这个库里面有两个函数&#xff0c;分别是C98 与 C11 下的&#xff0c;名称是run2和run1。 被调用库 相关介绍请看之前的文章《函数指针与库之间的通信讲解》。 //dll_ex_im.h #ifndef…...

图像生成大模型imagen

要生成图像&#xff0c;可以使用深度学习模型&#xff0c;比如 OpenAI 的 DALLE、Google 的 Imagen 等。由于这些模型通常需要较大的计算资源和训练数据&#xff0c;下面是一些如何使用这些模型的基本步骤和方法。 使用预训练图像生成模型 选择模型&#xff1a; 常用的模型包括…...

Redis集群知识及实战

1. 为什么使用集群 在哨兵模式中&#xff0c;仍然只有一个Master节点。当并发写请求较大时&#xff0c;哨兵模式并不能缓解写压力。我们知道只有主节点才具有写能力&#xff0c;那如果在一个集群中&#xff0c;能够配置多个主节点&#xff0c;是不是就可以缓解写压力了呢&…...

数据报表轻松管理,强大“后台”不可少

在数据驱动的时代&#xff0c;制作一份高效、精准的数据报表成为企业管理和决策的重要手段。但要做好数据报表&#xff0c;不仅需要一款功能强大的报表工具&#xff0c;还必须有一个强有力的“后台”管理系统来支撑。那么&#xff0c;为什么报表工具需要一个管理后台&#xff1…...

简易CPU设计入门:本CPU项目的指令格式

在这一节里面&#xff0c;主要是理论知识&#xff0c;基本上不讲代码。不过&#xff0c;本项目的代码包&#xff0c;大家还是需要下载的。 本项目的代码包的下载方法&#xff0c;参考下面的链接所指示的文章。 下载本项目代码 本节&#xff0c;其实是要讲本项目CPU的指令集。…...

Datawhile 组队学习Tiny-universe Task01

Task01&#xff1a;LLama3模型讲解 仓库链接&#xff1a;GitHub - datawhalechina/tiny-universe: 《大模型白盒子构建指南》&#xff1a;一个全手搓的Tiny-Universe 参考博客&#xff1a;LLaMA的解读与其微调(含LLaMA 2)&#xff1a;Alpaca-LoRA/Vicuna/BELLE/中文LLaMA/姜子…...

MCU与SOC的区别

自动驾驶中 MCU 与 SoC 的区别 在自动驾驶系统中&#xff0c;**MCU&#xff08;微控制单元&#xff0c;Microcontroller Unit&#xff09;和SoC&#xff08;系统级芯片&#xff0c;System on Chip&#xff09;**都是关键的电子元件&#xff0c;但它们在性能、功能和应用领域等…...

51单片机-DS18B20(温度传感器)AT24C02(存储芯片) IIC通信-实验2-温度实时监测(可设置阈值)

作者&#xff1a;王开心 座右铭&#xff1a;刻苦专研&#xff0c;百折不挠&#xff0c;千磨万击还坚韧&#xff0c;任尔东西南北风&#xff01;干就完了&#xff01;&#xff08;可交流技术&#xff09; 主要利用DS18B20芯片去采集温度&#xff0c;通过采集的温度能够自动保存…...

Vue2接入高德地图API实现搜索定位和点击获取经纬度及地址功能

目录 一、申请密钥 二、安装element-ui 三、安装高德地图依赖 四、完整代码 五、运行截图 一、申请密钥 登录高德开放平台&#xff0c;点击我的应用&#xff0c;先添加新应用&#xff0c;然后再添加Key。 如图所示填写对应的信息&#xff0c;系统就会自动生成。 二、安装…...

msvcp140.dll丢失如何解决?msvcp140.dll丢失的多种解决方法

在计算机使用过程中&#xff0c;我们经常会遇到一些错误提示&#xff0c;其中之一就是“msvcp140.dll丢失”。这个错误通常会导致某些应用程序无法正常运行&#xff0c;给用户带来很大的困扰。那么&#xff0c;当我们遇到msvcp140.dll丢失的情况时&#xff0c;应该如何解决呢&a…...

高效财税自动化软件如何提升企业财务工作的效率与准确性

在当今企业运营中&#xff0c;财务管理发挥着核心作用。它不仅涉及企业正常运转和市场决策&#xff0c;还是推动企业向高质量发展迈进的关键动力。面对激烈的市场竞争与科技革新的双重挑战&#xff0c;财务管理亟需进行持续的转型与提升&#xff0c;为企业高质量发展目标的实现…...

Leetcode 3286. Find a Safe Walk Through a Grid

Leetcode 3286. Find a Safe Walk Through a Grid 1. 解题思路2. 代码实现 题目链接&#xff1a;3286. Find a Safe Walk Through a Grid 1. 解题思路 这一题的话思路上就是一个宽度优先遍历&#xff0c;我们按照health进行排序进行宽度优先遍历&#xff0c;看看在health被消…...

shell脚本语法

shell脚本的变量 系统变量 系统变量是操作系统用来存储配置信息的变量&#xff0c;它们可以控制操作系统的行为和程序的运行环境。系统变量的种类和内容取决于操作系统的类型和版本。以下是一些常见的系统变量类别和它们可能包含的内容&#xff1a; 环境变量&#xff1a;这些…...

TCP 拥塞控制:一场网络数据的交通故事

从前有条“高速公路”&#xff0c;我们叫它互联网&#xff0c;而这条公路上的车辆&#xff0c;则是数据包。你可以把 TCP&#xff08;传输控制协议&#xff09;想象成一位交通警察&#xff0c;负责管理这些车辆的行驶速度&#xff0c;以防止交通堵塞——也就是网络拥塞。 第一…...

(黑马点评) 五、探店达人系列功能实现

5.1 发布和查看探店笔记 5.1.1 发布探店笔记 这块代码黑马已经完成了&#xff0c;在发布探店笔记界面&#xff0c;有两块内容是需要上传的。一是笔记内容&#xff0c;二是笔记配图。其中笔记配图部分黑马使用的是上传到本地前端服务器上面的。我我觉得可以将图片文件发布在阿里…...

SQLiteDatabase insert or replace数据不生效

在Android开发中&#xff0c;如果您在SQLite数据库中更新了数据&#xff0c;但重启应用后更新的数据不再生效&#xff0c;那么可能的原因有&#xff1a; 更新操作没有正确执行&#xff0c;可能是由于SQL语句错误或者数据库没有正确打开。 更新操作在事务中没有被正确提交。 更…...

基于Python实现一个浪漫烟花秀

为了实现一个类似烟花秀的效果&#xff0c;我们可以通过复杂的粒子系统来模拟烟花的升起、绽放和下落效果。以下是一个示例&#xff0c;旨在创建更为动态和逼真的烟花秀效果。 示例代码 这个代码示例将使用 matplotlib 和 numpy&#xff0c;并实现更丰富的视觉效果&#xff1…...

电气自动化入门03:安全用电

视频链接&#xff1a;2.1 电工知识&#xff1a;触电原因与防触电措施_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1PJ41117PW/?p4&vd_sourceb5775c3a4ea16a5306db9c7c1c1486b5 1.电流对人体的危害 电击&#xff1a;电流通过人体。 电伤&#xff1a;电流热效应…...

【深度学习】(2)--PyTorch框架认识

文章目录 PyTorch框架认识1. Tensor张量定义与特性创建方式 2. 下载数据集下载测试展现下载内容 3. 创建DataLoader&#xff08;数据加载器&#xff09;4. 选择处理器5. 神经网络模型构建模型 6. 训练数据训练集数据测试集数据 7. 提高模型学习率 总结 PyTorch框架认识 PyTorc…...

微服务商城-商品微服务

数据表 CREATE TABLE product (id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 商品id,cateid smallint(6) UNSIGNED NOT NULL DEFAULT 0 COMMENT 类别Id,name varchar(100) NOT NULL DEFAULT COMMENT 商品名称,subtitle varchar(200) NOT NULL DEFAULT COMMENT 商…...

【C语言练习】080. 使用C语言实现简单的数据库操作

080. 使用C语言实现简单的数据库操作 080. 使用C语言实现简单的数据库操作使用原生APIODBC接口第三方库ORM框架文件模拟1. 安装SQLite2. 示例代码:使用SQLite创建数据库、表和插入数据3. 编译和运行4. 示例运行输出:5. 注意事项6. 总结080. 使用C语言实现简单的数据库操作 在…...

MySQL中【正则表达式】用法

MySQL 中正则表达式通过 REGEXP 或 RLIKE 操作符实现&#xff08;两者等价&#xff09;&#xff0c;用于在 WHERE 子句中进行复杂的字符串模式匹配。以下是核心用法和示例&#xff1a; 一、基础语法 SELECT column_name FROM table_name WHERE column_name REGEXP pattern; …...

Maven 概述、安装、配置、仓库、私服详解

目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...

零基础在实践中学习网络安全-皮卡丘靶场(第九期-Unsafe Fileupload模块)(yakit方式)

本期内容并不是很难&#xff0c;相信大家会学的很愉快&#xff0c;当然对于有后端基础的朋友来说&#xff0c;本期内容更加容易了解&#xff0c;当然没有基础的也别担心&#xff0c;本期内容会详细解释有关内容 本期用到的软件&#xff1a;yakit&#xff08;因为经过之前好多期…...

10-Oracle 23 ai Vector Search 概述和参数

一、Oracle AI Vector Search 概述 企业和个人都在尝试各种AI&#xff0c;使用客户端或是内部自己搭建集成大模型的终端&#xff0c;加速与大型语言模型&#xff08;LLM&#xff09;的结合&#xff0c;同时使用检索增强生成&#xff08;Retrieval Augmented Generation &#…...

libfmt: 现代C++的格式化工具库介绍与酷炫功能

libfmt: 现代C的格式化工具库介绍与酷炫功能 libfmt 是一个开源的C格式化库&#xff0c;提供了高效、安全的文本格式化功能&#xff0c;是C20中引入的std::format的基础实现。它比传统的printf和iostream更安全、更灵活、性能更好。 基本介绍 主要特点 类型安全&#xff1a…...

Vue ③-生命周期 || 脚手架

生命周期 思考&#xff1a;什么时候可以发送初始化渲染请求&#xff1f;&#xff08;越早越好&#xff09; 什么时候可以开始操作dom&#xff1f;&#xff08;至少dom得渲染出来&#xff09; Vue生命周期&#xff1a; 一个Vue实例从 创建 到 销毁 的整个过程。 生命周期四个…...

6️⃣Go 语言中的哈希、加密与序列化:通往区块链世界的钥匙

Go 语言中的哈希、加密与序列化:通往区块链世界的钥匙 一、前言:离区块链还有多远? 区块链听起来可能遥不可及,似乎是只有密码学专家和资深工程师才能涉足的领域。但事实上,构建一个区块链的核心并不复杂,尤其当你已经掌握了一门系统编程语言,比如 Go。 要真正理解区…...

智能职业发展系统:AI驱动的职业规划平台技术解析

智能职业发展系统&#xff1a;AI驱动的职业规划平台技术解析 引言&#xff1a;数字时代的职业革命 在当今瞬息万变的就业市场中&#xff0c;传统的职业规划方法已无法满足个人和企业的需求。据统计&#xff0c;全球每年有超过2亿人面临职业转型困境&#xff0c;而企业也因此遭…...