C++之string类

1.string类的重要性:C语言中,字符串是以“\0”结尾的一些字符的集合,为了操作方便,C标准库中提供了一些str系列的库函数,但是这些库函数与字符串是分离开的,不太符合OPP的思想,而且底层空间需要用户自行管理,稍不留神可能会越界访问。

string是一个对象,使用字符的顺序表实现的,就是一个字符顺序表。

基本构造:

class string
{
private:size_t size;size_t capacity;char* str;//指向一个数组动态开辟的
};

2.string类的接口使用:使用前记得写上#include <string.h>

*可以直接实例化不给数据,也可以给字符串去构造string,也可以拷贝构造:

void test1()
{string s1;string s2("hello world");string s3(s2);//拷贝构造也可以//cin >> s1;cout << s1 << endl;cout << s2 << endl;cout << s3 << endl;
}

* string(const string & str, size_t pos, size_t len = npos);nops是缺省值,该接口是为了拷贝string的一部分,nops是string的const静态的成员变量,值为-1,但其实是把-1给了一个无符号的len瞬间就变成整型的最大值了,42亿九千万字节。

 *通过string(size_t len,string & str)构造对象初始化为len个对应的字符。

*通过s[n]可以访问到字符串对应下标的字符,类似数组,非常方便。

void test1()
{string s2("hello world");//string(const string & str, size_t pos, size_t len = npos);nops是缺省值//拷贝string的一部分//nops是string的const静态的成员变量,值为-1,但其实是把-1给了一个无符号的len瞬间就变成整型的最大值了,42亿九千万字节string s4(s2, 6, 5);//第六个位置开始拷贝五个字符cout << s4 << endl;string s5(s2, 6);//取到字符串结尾,不包含'\0'cout << s5 << endl;string s6("hello world", 5);//取前五个字符cout << s6 << endl;string s7(10, 'x');//十个x初始化cout << s7 << endl;s6[0] = 'x';//可以像数组一样修改cout << s6 << endl;return 0;
}

*利用迭代器和auto关键字遍历字符串:

以前遍历字符串的方式:

void test2()
{string s1("hello world");cout << s1 << endl;//遍历字符串s1:for (size_t i = 0; i < s1.size(); i++)//size()可以获取字符长度{cout << s1[i] << " ";}cout << endl;
}

下面是利用迭代器和auto的方式遍历字符串,感受一下三者的区别:

void test2()
{string s1("hello world");cout << s1 << endl;string s2(s1);s2[0] = 'x';//迭代器遍历://迭代器规定,不管底层什么定义的,首先属于对应容器的类域string::iterator it = s2.begin();//用迭代器定义一个对象,有点像指针但不一定是指针 while (it != s2.end())//begin是返回空间开始位置的迭代器,所以it指向了开始{//end是\0位置的迭代器cout << *it << "";//运算符重载*//也可以*it+=2,使里面的asci码值改变换字母++it;//直到it到end位置结束}cout << endl;
}
void test2()
{string s1("hello world");cout << s1 << endl;string s2(s1);s2[0] = 'x';for (auto ch : s2)//自动从s2里面取每一个值给这个ch变量{  //auto表示自动推导成char,自动赋值、自动迭代、自动判断结束ch -= 2;//修改字符对应的asci码值换字母了,但是s2没变,因为ch是局部变量//如果想要修改的话for里面auto加引用cout << ch << " ";}//底层是迭代器cout << endl;
}

 auto ch : s2 表示创建一个叫ch的变量,然后从s2里面一个一个的把字符传给ch去读取。底层依旧是迭代器。

附赠一个迭代器遍历链表:

void test()
{//链表迭代器遍历list<int> lt = { 1,2,3,4,5,6,7 };list<int> ::iterator lit = lt.begin();while (lit != lt.end()){cout << *lit << " ";++lit;}cout << endl;
}

*auto的意义:

//auto用法和意义:
int func()
{//...return 1;
}
void test3()
{int a = 10;auto b = a;//自动推导b的类型为intauto c = 'a';//自动推导c的类型为charauto d = func();//自动推导返回值,但是像这些都没什么意义,但如果是一个函数里面有多层其他函数的迭代,那么就可以瞬间知道函数的返回值类型//auto e;//编译报错,e必须要有初始值cout << typeid(d).name() << endl;//打印类型//真正的意义是简化代码:/*map<string, string>dict;map<string, string>::iterator mit = dict.begin();可以替换为:auto mit= dict.begin();*///以前遍历数组的方式:int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++){arr[i] *= 2;}for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++){cout << arr[i] << endl;}//利用auto遍历:for (auto& e : arr)e *= 2;for (auto e : arr)cout << e << " " << endl;//一些小点://auto a = 1, b = 1;//可以//auto c = 2, d = 2.2;//不可以//void func(auto a);//不能做参数但可以做返回值,谨慎使用//逆向迭代器遍历容器:string s1("hello world");string::reverse_iterator rit = s1.rbegin();//末尾while (rit != s1.rend())//其实这是头{cout << *rit << " " << endl;rit++;//这里的++是重载的,倒着++}cout << endl;const string s3("hello world");string::const_iterator cit = s3.begin();//const只能读不能写//==auto cit = s3.begin();while (cit != s3.end()){cout << *cit << endl;cit++;}string::const_reverse_iterator rcit = s3.rbegin();//反向遍历//==auto rcit = s3.rbegin();while (rcit != s3.rend()){cout << *rcit << endl;rcit++;}}

 *注意,auto不能作为函数的参数,可以作为返回值,但谨慎使用。auto不能用来直接声明数组。

*其他接口:

void test4()
{string s1("hello world");s1.max_size();//获取最大长度,了解s1.length();//获取长度s1.capacity();//获取容量int n = 100;s1.reserve(n);//提前开好n个字节的空间,不包含\0。//大于原来空间就扩容,小的话不一定会缩小,但肯定不会对内容造成影响s1.clear();//清理数据,但可能会清掉容量}
void test5()
{string s("hello world");s.push_back(' ');s.push_back('x');s.append("xxxxxx");//在后面补上字符串
}void test6()
{string s("hello world");s.erase(6, 1);//在第六个位置删除一个字符cout << s << endl;s.erase(s.begin());//迭代器头删cout << s << endl;s.erase(s.end());cout << s << endl;string ss("hello world");s.replace(5, 1, "%%");//第五个位置替换为一个字符string sss("hello world en");size_t pos = sss.find(' ');//查找某个位置的字符串,返回第一个匹配的字符的下标位置while (pos != string::npos){sss.replace(pos, 1, "%%");//替换pos = sss.find(' ');//替换后继续找//但是这个是每次都要从头开始找//所以可以写成://pos = sss.find(" ", pos + 2);//但是效率还是很低,一个空格替换一次}cout << sss << endl;//解决一个空格替换一次的低效:string tmp;for (auto ch : sss){if (ch == ' ')tmp += "%%";elsetmp += ch;}cout << tmp << endl;}void test7()
{//调用文件:string file;cin >> file;file* fout = fopen(file.c_str(), "r");char ch = fgetc(fout);while (ch != eof){cout << ch << endl;ch = fgetc(fout);}fclose(fout);
}

三个练习:

仅仅、方向迭代,输入abcd输出dcba

class solution1
{//判断是否是字符:bool isleter(char ch){if (ch >= 'a' && ch <= 'z'){return true;}if (ch >= 'a' && ch <= 'z'){return true;}else return false;}string resveronlyletters(string s){int left = 0, right = s.size() - 1;while (left < right){while (left < right && !isleter(s[left])){++left;}while (left < right && !isleter(s[right])){--right;}swap(s[left++], s[right--]);}return s;}
};

字符串中第一个唯一字符

class solution2
{int firstunichar(string s){int count[26] = { 0 };//利用映射统计各个字母出现次数for (auto ch : s){count[ch - 'a']++;}//循环判断是否只有出现一次的字母for (size_t i = 0; i < s.size(); i++){if (count[s[i]-'a'] == 1){return i;}}return -1;}
};

 字符串相加

class solution3
{string addstrings(string num1, string num2){string str;int end1 = num1.size() - 1;int end2 = num2.size() - 1;//进位:int next = 0;while (end1 >= 0 || end2 >= 0){int val1 = 0 ? num1[end1--] - '0' : 0;int val2 = 0 ? num1[end2--] - '0' : 0;int ret = val1 + val2 + next;next = ret / 10;ret = ret % 10;str.insert(str.begin(), '0'+ret);}if (next == 1)str.insert(str.begin(), '1');return str;}
};

*find接口:

void test8()//find系列
{//size_t pos = s.find(' ');//查找某个位置的字符串,返回第一个匹配的字符的下标位置string s("test.cpp");size_t pos = s.find('.');//获取文件的后缀string suffix = s.substr(pos);//从pos位置开始的len个字符单独拿出来变成一个新string//没给第二个值就是有多长去多长cout << suffix << endl;//假如文件名变为:string ss("test.cpp.zip");//这时候要取后缀为.zip,就可以倒着找size_t poss = ss.rfind('.');string suffixx = ss.substr(poss);string sss("ainizhoujielun");//将里面的aijn替换为*size_t posss = sss.find_first_of("aijn");//找到一个替换为*while (posss != sss.npos)//小于这个字符串的最长值{sss[posss++] = '*';posss = sss.find_first_of("aijn", posss + 1);}cout << sss << endl;string str1("/usr/bin/man");//路径还要同时兼容windows和linuxstring str2("c:\\windows\\winhelp.exe");//linux系统下的份分割是\//就可以用find_last_of 倒着找,如果是l的\或者w的/都进行返回void spilitfilename(const std::string & str); spilitfilename(str1);spilitfilename(str2);//find_not_last_of不是的返回,将非目标替换
}
void spilitfilename(const std::string& str)
{std::cout << "spilitfilename" << str << '\n';std::size_t found = str.find_last_of("/\\");//倒着找\,返回的数字,之前的分割std::cout << "path" << str.substr(0, found) << '\n';std::cout << "file" << str.substr(found + 1) << '\n';
}void test9()
{string s1("hello");string s2 = s1 + " world";string s3 = "world " + s1;//但是重载的+得是全局的,因为左操作数被string牢牢占据
}

练习:查找字符串最后一个单词,例如输入hello world输出5

//查找字符串最后一个单词:
//例如输入hello world输出5
int main()
{string str;getline(cin, str);//默认遇到换行才会停止,也可以自定义,比如遇到星号才停止getline(cin, str,'*')size_t pos = str.rfind(' ');cout << str.size() - (pos + 1) << endl;return 0;
}

3.string类的模拟实现:

.h文件:

#pragma once
#define _CRT_SECURE_NO_WARNINGS//模拟实现string
#include <iostream>
#include <assert.h>
#include <stdlib.h>
using namespace std;namespace byd
{class string{public://构造:string():_str(new char[1] {'\0'}),_size(0),_capacity(0)//初始化列表先声明的先走{}//构造:string(const char* str='\0')//常量字符串后面会给\0{_size = strlen(str);//_capacity没有包含\0_capacity = _size;_str = new char[_capacity + 1];strcpy(_str, str);//先拷贝再判断,遇到\0截止}//自己写拷贝构造://但是这个是传统写法,就是自己开空间自己赋值拷贝string(const string& s)//s2(s1)左边是this{_str = new char[s._capacity + 1];//开和str一样大的空间//拷贝:strcpy(_str, s._str);_size = s._size;_capacity = s._capacity;}//不深拷贝的问题就是拷贝之后指针是一样的,指向了同一块空间,会被析构两次,一个被修改另一个也会被修改//所以有了新的写法://s2(s1);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(_str, tmp._str);swap(_size, tmp._size);swap(_capacity, tmp._capacity);*///==:封装成上面这个swap函数swap(tmp);}//假设有个s1叫hello,s2指向空,tmp被初始化为hello,然后交换之后s2变成了hello//同理,重载=也可以这样写://s1 = s2;string& operator=(const string& s){if (this != &s){string tmp(s._str);swap(tmp);//交换完之后tmp里面的东西是s2的,出了作用域就都被销毁了}return *this;}//重载://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;//	}//}//也可以这样:string& operator=(string tmp)//传值调用拷贝构造,tmp是一个新的东西,自己和s3拷贝构造了{swap(tmp);return *this;}~string(){delete[] _str;_str = nullptr;_size = _capacity = 0;}const char* c_str(){return _str;}//一些基本函数接口:size_t size() const//返回长度{return _size;}char& operator[](size_t pos)//返回对应下标字符{assert(pos < _size);return _str[pos];}const char& operator[](size_t pos) const//返回const不能修改{assert(pos < _size);return _str[pos];}//迭代器伪实现:typedef char* iterator;//屏蔽了底层的实现细节,提供了统一的类似访问容器的方式,不需要关心容器底层结构和细节iterator begin(){return _str;}iterator end(){return _str + _size;}size_t capacity(){return _capacity;}void reserve(size_t n);//声明和定义分离void push_back(char ch);void append(const char* str);string& operator+=(char str);string& operator+=(const char str);void insert(size_t pos, char ch);void inserts(size_t pos, char* str);void erase(size_t pos, size_t len);string str(size_t pos, size_t len);size_t find(const char* str, size_t pos = 0);string substr(size_t pos, size_t len);string operator+=(const char* str);private:char* _str;size_t _size;size_t _capacity;static const size_t npos = -1;//静态不能在类里给缺省值,因为不走初始化列表,要走声明和定义分离,但是这个地方可以,因为有了static const。};void test_string1();void test_string2();bool operator<(const string& s1, const string& s2);ostream& operator<<(ostream& out, const string& s);
}

.cpp文件:

#include "String.h"
#include <iostream>
using namespace std;namespace byd
{void string::reserve(size_t n){if (n > _capacity){char* tmp = new char[n+1];//创建新空间strcpy(tmp, _str);//拷贝原来空间到新空间delete[] _str;_str = tmp;//改变原来_str的地址_capacity = n;}}void string::push_back(char ch){//先扩容:if (_size = _capacity){reserve(_capacity == 0 ? 4 : _capacity * 2);}_str[_size] = ch;_size++;_str[_size] = '\0';//输出程序碰到\0结束,必须要写,不然会出现乱码。}string& string::operator+=(char ch){push_back(ch);return *this;}void string::append(const char* str){size_t len = strlen(str);if (_size + len > _capacity){reserve(_size + len > _capacity * 2 ?  _size + len : _capacity * 2);//如果大于2倍,需要多少开多少}strcpy(_str + _size, str);_str += len;}string& string::operator+=(const char* str){append(str);return *this;}void string::insert(size_t pos, char ch)//插入一个字符{assert(pos < _size);if (_size == _capacity){reserve(_capacity == 0 ? 4 : _capacity * 2);}//挪动数据:size_t end = _size + 1;//while (end >= pos)//大坑,当一个操作符两边操作数不一样时两边会发生转换,pos会变成无符号去和它比较。while(end>=(int)pos)//强转解决{_str[end + 1] = _str[end];end--;}//这样子挪动数据会把\0移除_str[pos] = ch;_size++;}//用指针的方式改写insert:void string::inserts(size_t pos, char* str)//插入字符串{assert(pos < _size);size_t len = strlen(str);if (len == 0){return;}if (_size == _capacity){reserve(_size + len > _capacity * 2 ? _size + len : _capacity * 2);}size_t end = _size + len;//挪动数据:while (end > pos + len - 1){_str[end - len] = _str[end];end--;}for (size_t i = 0; i < len; i++){_str[pos + i] = str[i];}}void string::erase(size_t pos, size_t len)//len是字符长度{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;}}size_t string::find(const char* str, size_t pos = 0){assert(pos < _size);const char* ptr = strstr(_str + pos, str);if (ptr == nullptr){return npos;}else return ptr - _str;}string string::substr(size_t pos, size_t len){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;}bool operator<(const string & s1, const string & s2){return strcmp(s1.c_str, s2.c_str);}string string::operator+=(const char* str){append(str);return *this;}ostream& operator<<(ostream& out, const string& s){for (auto ch : s){out << ch;}return out;}istream& operator>>(istream& in, string& s){s.clear();const int N = 1024;char buff[N];int i = 0;char ch;//char ch;//in >> ch;//默认提取不到空格和换行//ch = in.get();//while (ch != ' ' && ch != '\n')//{//	s += ch;//	ch = in.get();//但是这种是一次一次来然后扩容的,需改进//}ch = in.get();while (ch != ' ' && ch != '\n'){buff[i++] = ch;if (i == N - 1){buff[i] = '\0';s += buff;i = 0;}ch = in.get();}return in;}void test_string1(){//string s1;string s2("hello world");//cout << s1.c_str<< endl;//当初始化列表中:_str(nullptr)这样子程序会崩溃,因为s1啥都没有只有空指针,空指针去解引用没遇到\0不会停下//cout << s1.c_str << endl;byd::string::iterator it = s2.begin();while (it != s2.end()){cout << *it << " ";it++;}cout << endl;for (auto e : s2){cout << e << " ";}cout << endl;}void test_string2(){string s1("hello world");s1 += 'x';s1 += '#';}
}

*单独一提:深拷贝的现代实现方式:

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(_str, tmp._str);swap(_size, tmp._size);swap(_capacity, tmp._capacity);*///==:封装成上面这个swap函数swap(tmp);
}//假设有个s1叫hello,s2指向空,tmp被初始化为hello,然后交换之后s2变成了hello

有字符串s1和s2,创建tmp然后用s1拷贝构造tmp,然后让tmp和s2里面东西去交换,这样就可以简单方便的实现深拷贝并且tmp出了作用域之后会调用析构函数自动销毁,把原来那部分需要自己做的事情全部交给了编译器去完成实现。相比于原来的:

string(const string& s)//s2(s1)左边是this
{_str = new char[s._capacity + 1];//开和str一样大的空间//拷贝:strcpy(_str, s._str);_size = s._size;_capacity = s._capacity;
}

同理,重载=函数就可以写成:

string& operator=(const string& s)
{if (this != &s){string tmp(s._str);swap(tmp);//交换完之后tmp里面的东西是s2的,出了作用域就都被销毁了}return *this;
}

如果做一下优化:

string& operator=(string tmp)//传值调用拷贝构造,tmp是一个新的东西,自己和s3拷贝构造了
{swap(tmp);return *this;
}

巧妙地利用了传值调用拷贝构造让编译器自动实现了拷贝构造,大大简化了代码,相比于原来的重载operator=:

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

当然底层的运行并没有简化,只是看上去代码更简洁了而已。

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

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

相关文章

【D3.js in Action 3 精译_038】4.2 D3 折线图的绘制方法及曲线插值处理

当前内容所在位置&#xff08;可进入专栏查看其他译好的章节内容&#xff09; 第一部分 D3.js 基础知识 第一章 D3.js 简介&#xff08;已完结&#xff09; 1.1 何为 D3.js&#xff1f;1.2 D3 生态系统——入门须知1.3 数据可视化最佳实践&#xff08;上&#xff09;1.3 数据可…

测试-正交表与工具pairs的介绍使用(1)

目录 正交表 生成正交表 步骤 实操 注意事项 编写测试用例 根据正交表编写测试用例 补充遗漏的重要测试用例 正交表 关于长篇大论也不多介绍了&#xff0c;我们只需要知道正交法的⽬的是为了减少⽤例数⽬&#xff0c;⽤尽量少的⽤例覆盖输⼊的两两组合 正交表的构成&…

抗晃电马达保护器在工业厂房中的应用

安科瑞刘鸿鹏 摘要 随着工业自动化水平的提高&#xff0c;生产线上电动机作为关键设备的使用频率不断增加。然而&#xff0c;工厂生产环境中的电力波动&#xff0c;尤其是晃电现象&#xff0c;会对电动机的正常运转造成干扰&#xff0c;甚至导致设备停机和生产中断。抗晃电型…

linux之调度管理(2)-调度器 如何触发运行

一、调度器是如何在程序稳定运行的情况下进行进程调度的 1.1 系统定时器 因为我们主要讲解的是调度器&#xff0c;而会涉及到一些系统定时器的知识&#xff0c;这里我们简单讲解一下内核中定时器是如何组织&#xff0c;又是如何通过通过定时器实现了调度器的间隔调度。首先我们…

RHCE循环执行的例行性任务--crontab(周期性)

1.每分钟执行命令 2.每小时执行 3.每天凌晨3点半和12点半执行脚本 4.每隔6小时&#xff0c;相当于6,12,18,24点半执行脚本 5.30半点&#xff0c;8-18/2表示早上8点到下午18点之间每隔2小时执行脚本代表 6.每天晚上9点30重启nginx 7.每月1号和10号4点45执行脚本 8. 每周六和周日…

ETLCloud异常问题分析ai功能

在数据处理和集成的过程中&#xff0c;异常问题的发生往往会对业务运营造成显著影响。为了提高ETL&#xff08;提取、转换、加载&#xff09;流程的稳定性与效率&#xff0c;ETLCloud推出了智能异常问题分析AI功能。这一创新工具旨在实时监测数据流动中的潜在异常&#xff0c;自…

Java项目实战II基于Spring Boot的个人云盘管理系统设计与实现(开发文档+数据库+源码)

目录 一、前言 二、技术介绍 三、系统实现 四、文档参考 五、核心代码 六、源码获取 全栈码农以及毕业设计实战开发&#xff0c;CSDN平台Java领域新星创作者&#xff0c;专注于大学生项目实战开发、讲解和毕业答疑辅导。 一、前言 基于Spring Boot的个人云盘管理系统设计…

还在为慢速数据传输苦恼?Linux 零拷贝技术来帮你!

前言 程序员的终极追求是什么&#xff1f;当系统流量大增&#xff0c;用户体验却丝滑依旧&#xff1f;没错&#xff01;然而&#xff0c;在大量文件传输、数据传递的场景中&#xff0c;传统的“数据搬运”却拖慢了性能。为了解决这一痛点&#xff0c;Linux 推出了 零拷贝 技术&…

密码学是如何保护数据传输的安全性?

密码学通过一系列算法和协议来保护数据传输的安全性。 一、加密技术 对称加密算法 原理&#xff1a;使用相同的密钥进行加密和解密。应用&#xff1a;在数据传输过程中&#xff0c;发送方和接收方共享一个密钥&#xff0c;数据在传输前被加密&#xff0c;接收方使用相同的密钥…

python怎么打开py文件

1、首先在资源管理器里复制一下py文件存放的路径&#xff0c;按下windows键&#xff0b;r&#xff0c;在运行里输入cmd&#xff0c;回车打开命令行&#xff1a; 2、在命令行里&#xff0c;先切换到py文件的路径下面&#xff0c;接着输入“python 文件名.py ”运行python文件&a…

云计算——ACA学习 云计算核心技术

作者简介&#xff1a;一名云计算网络运维人员、每天分享网络与运维的技术与干货。 座右铭&#xff1a;低头赶路&#xff0c;敬事如仪 个人主页&#xff1a;网络豆的主页​​​​​ 写在前面 本系列将会持续更新云计算阿里云ACA的学习&#xff0c;了解云计算及网络安全相关…

企业办公管理软件排名 | 九款企业管理软件助你制胜职场!(好用+实用+全面)

在寻找合适的企业办公管理软件时&#xff0c;你是否感到困惑不已&#xff0c;不知道从众多选项中选择哪一个&#xff1f; 一款好的管理软件不仅能简化工作流程&#xff0c;还能增强数据安全性&#xff0c;优化决策支持。 以下是九款备受推崇的企业管理软件&#xff0c;它们将助…

DNS服务器

DNS服务器 1、简介 DNS域名解析服务器&#xff0c;它作为将域名和IP地址相互映射的一个分布式数据库&#xff0c;端口号为53&#xff0c;通常使用UDP协议&#xff0c;但是在没有查询到完整的信息时&#xff0c;会以TCP这个协议来重新查询&#xff0c;所以在启动NDS服务器时&a…

顾荣辉在新加坡金融科技节发表主旨演讲:安全不仅是竞争优势,更是共同责任

在全球数字化和去中心化进程中&#xff0c;Web3的作用日益凸显&#xff0c;安全问题也日益成为行业的焦点。在这一背景下&#xff0c;顾荣辉教授于新加坡金融科技节&#xff08;SFF&#xff09;上发表主旨演讲《超越代码&#xff0c;引领信任》。顾教授在演讲中深入阐述了安全在…

Leetcode328奇偶链表,Leetcode21合并两个有序链表,Leetcode206反转链表 三者综合题

题目描述 思路分析 这题的思路就和我们的标题所述一样&#xff0c;可以看作是这3个题的合并&#xff0c;但是稍微还有一点点区别 比如&#xff1a;奇偶链表这道题主要是偶数链在了奇数后面&#xff0c;字节这个的话是奇偶链表分离了 所以字节这题的大概思路就是&#xff1a; …

「Mac玩转仓颉内测版1」入门篇1 - Cangjie环境的搭建

本篇详细介绍在Mac系统上快速搭建Cangjie开发环境的步骤&#xff0c;涵盖VSCode的下载与安装、Cangjie插件的离线安装、工具链的配置及验证。通过这些步骤&#xff0c;确保开发环境配置完成&#xff0c;为Cangjie项目开发提供稳定的基础支持。 关键词 Cangjie开发环境搭建VSC…

2023数学分析【南昌大学】

计算 求极限 lim ⁡ n → ∞ ( 1 n 2 + 1 2 + 1 n 2 + 2 2 + ⋯ + 1 n 2 + n 2 ) \mathop{\lim }\limits_{n \to \infty } \left( \frac{1}{{\sqrt {n^2 + 1^2} }} + \frac{1}{{\sqrt {n^2 + 2^2} }} + \cdots + \frac{1}{{\sqrt {n^2 + n^2} }} \right) n→∞lim​(n2+12 ​1…

从技术创新到商业应用,智象未来(HiDream.ai)创新不止步

在人工智能领域的最新动态中&#xff0c;智象未来&#xff08;HiDream.ai&#xff09;公司&#xff0c;作为全球领先的多模态生成式人工智能技术先驱&#xff0c;已经引起了广泛的行业瞩目。该公司专注于深度学习和计算机视觉技术的融合&#xff0c;致力于开发和优化视觉多模态…

ssm基于Vue的戏剧推广网站+vue

系统包含&#xff1a;源码论文 所用技术&#xff1a;SpringBootVueSSMMybatisMysql 免费提供给大家参考或者学习&#xff0c;获取源码看文章最下面 需要定制看文章最下面 目 录 摘 要 I Abstract II 第1章 绪论 1 1.1 课题背景 1 1.2 课题意义 1 1.3 研究内容 1 第2…

利用泰勒公式近似计算10的平方根

文章目录 1. 泰勒公式是什么2、利用泰勒公式计算 10 \sqrt{10} 10 ​第 1 步&#xff1a;泰勒级数展开第 2 步&#xff1a;计算各阶导数第 3 步&#xff1a;在 x 9 x 9 x9 处计算各阶导数第 4 步&#xff1a;构建各阶泰勒展开式第 5 步&#xff1a;计算 f ( 10 ) f(10) f(1…