当前位置: 首页 > 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…...

前端面试记录

js 1. 函数式编程 将计算过程视为一系列的函数调用,函数的输出完全由输入决定&#xff0c;不依赖于或改变程序的状态,使得函数式编程的代码更加可预测和易于理解。 函数式编程的三个核心概念&#xff1a;纯函数、高阶函数和柯里化。 高阶函数&#xff1a;函数可以作为参数传…...

裁员了,很严重,大家做好准备吧!

最近刷到这样一个故事&#xff1a; 一个网友在大厂当牛马接近10年&#xff0c;部门优秀员工&#xff0c;业绩一直很稳&#xff0c;没想到&#xff0c;今年公司引进AI降本增效&#xff0c;开始大幅裁员&#xff0c;有些部门一夜之间被连锅端&#xff01; 上个月果然轮到他了&a…...

uniapp组件uni-datetime-picker选择年月后在ios上日期不显示

uniapp组件uni-datetime-picker选择年月后在ios上日期不显示 操作步骤&#xff1a; ios 选择年月 预期结果&#xff1a; 日期变为选择年月的日期 实际结果&#xff1a; 日期不显示 bug描述&#xff1a; uni-datetime-picker 2.2.22 ios点击年月选择后日期不显示 解决方案 …...

01_快速入门

读取数据 import pandas as pd# df pd.read_excel(https://xxxx/xxx//xx.xslx) # 读取网络数据 # df pd.read_excel(rd:\data\xx.xslx) # 读取本地文件 # 如果是csv文件&#xff0c;用read_csv()函数 df pd.read_csv(seaborn/iris.csv)查看数据 df.head() # 前5条记录 d…...

数据结构之分文件编译学生管理

list.h #ifndef LIST_H_ #define LIST_H_ #define MAX 30 typedef struct {int id;//学号char name[20];//姓名char major[20];//专业int age;//年龄 }student,*Pstudent;typedef struct {student data[MAX];//储存学生信息的数组int len;//统计学生个数 }list,*Plist;Plist c…...

TypeScript入门 (二)控制语句

引言 大家好&#xff0c;我是GISer Liu&#x1f601;&#xff0c;一名热爱AI技术的GIS开发者。本系列文章是我跟随DataWhale 2024年9月学习赛的TypeScript学习总结文档。本文主要讲解TypeScript中控制语句的部分&#xff1b;希望通过我的知识点总结&#xff0c;能够帮助你更好地…...

MVP 最简可行产品

MVP&#xff08;最小可行产品&#xff09;是一种产品开发策略&#xff0c;其主要目的是用最少的时间和资源&#xff0c;开发一个包含最基本必要功能的产品。这样做的目的是能够以最小的成本进入市场&#xff0c;获取用户反馈&#xff0c;再根据反馈逐步优化产品。 MVP是什么 …...

数仓工具:datax

datax可以理解为sqoop的优化版&#xff0c; 速度比sqoop快 因为sqoop底层是map任务&#xff0c;而datax底层是基于内存 DataX 是一个异构数据源离线同步工具&#xff0c;致力于实现包括关系型数据库(MySQL、Oracle等)、HDFS、Hive、ODPS、HBase、FTP等各种异构数据源之间稳定…...

CSS传统布局方法(补充)——WEB开发系列37

开发技术不断演进&#xff0c;布局方式也经历了多个阶段的变革。从最初的基于表格布局到 CSS 的浮动布局&#xff0c;再到今天的弹性盒&#xff08;Flexbox&#xff09;与 CSS Grid 网格布局&#xff0c;每一种布局方式都有其独特的背景和解决特定问题的优势。 一、CSS Grid 出…...

【系统架构设计师】软件架构的风格(经典习题)

更多内容请见: 备考系统架构设计师-核心总结索引 文章目录 【第1题】【第2题】【第3~4题】【第5题】【第6题】【第7题】【第8题】【第9题】【第10题】【第11题】【第12题】【第13题】【第14题】【第15~16题】【第17题】【第18~19题】【第20~21题】【第22题】【第23题】【第24~…...