初识c++(string和模拟实现string)

一、标准库中的string类

string类的文档介绍:cplusplus.com/reference/string/string/?kw=string

1、auto和范围for

auto

在早期C/C++中auto的含义是:使用auto修饰的变量,是具有自动存储器的局部变量,后来这个

不重要了。C++11中,标准委员会变废为宝赋予了auto全新的含义即:auto不再是一个存储类型

指示符,而是作为一个新的类型指示符来指示编译器,auto声明的变量必须由编译器在编译时期

推导而得。

用auto声明指针类型时,用auto和auto*没有任何区别,但用auto声明引用类型时则必须加&

当在同一行声明多个变量时,这些变量必须是相同的类型,否则编译器将会报错,因为编译器实际

只对第一个类型进行推导,然后用推导出来的类型定义其他变量。

auto不能作为函数的参数,可以做返回值,但是建议谨慎使用

auto不能直接用来声明数组

#include<iostream>
using namespace std;
int func1()
{return 10;
}
// 不能做参数
void func2(auto a)
{}
// 可以做返回值,但是建议谨慎使用
auto func3()
{return 3;
}
int main()
{int a = 10;auto b = a;auto c = 'a';auto d = func1();// 编译报错:rror C3531: “e”: 类型包含“auto”的符号必须具有初始值设定项auto e;cout << typeid(b).name() << endl;//查看变量类型cout << typeid(c).name() << endl;cout << typeid(d).name() << endl;int x = 10;auto y = &x;auto* z = &x;auto& m = x;cout << typeid(x).name() << endl;cout << typeid(y).name() << endl;cout << typeid(z).name() << endl;auto aa = 1, bb = 2;// 编译报错:error C3538: 在声明符列表中,“auto”必须始终推导为同一类型auto cc = 3, dd = 4.0;// 编译报错:error C3318: “auto []”: 数组不能具有其中包含“auto”的元素类型auto array[] = { 4, 5, 6 };return 0;
}

范围for

对于一个有范围的集合而言,由程序员来说明循环的范围是多余的,有时候还会容易犯错误。因此

C++11中引入了基于范围的for循环。for循环后的括号由冒号“ :”分为两部分:第一部分是范围

内用于迭代的变量,第二部分则表示被迭代的范围,自动迭代,自动取数据,自动判断结束。

范围for可以作用到数组和容器对象上进行遍历

范围for的底层很简单,容器遍历实际就是替换为迭代器,这个从汇编层也可以看到。

#include<iostream>
#include <string>
#include <map>
using namespace std;
int main()
{int array[] = { 1, 2, 3, 4, 5 };// C++98的遍历for (int i = 0; i < sizeof(array) / sizeof(array[0]); ++i){array[i] *= 2;}for (int i = 0; i < sizeof(array) / sizeof(array[0]); ++i){cout << array[i] << endl;}// C++11的遍历for (auto& e : array)e *= 2;for (auto e : array)cout << e << " " << endl;string str("hello world");for (auto ch : str){cout << ch << " ";}cout << endl;return 0;
}

2、string常见接口

1、 string类对象的常见构造

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

void Teststring()
{string s1; // 构造空的string类对象s1string s2("hello bit"); // 用C格式字符串构造string类对象s2string s3(s2); // 拷贝构造s3
}

2、string类对象的容量操作

在这里插入图片描述

注意:

  1. size()与length()方法底层实现原理完全相同,引入size()的原因是为了与其他容器的接

口保持一致,一般情况下基本都是用size()。

  1. clear()只是将string中有效字符清空,不改变底层空间大小。

  2. resize(size_t n) 与 resize(size_t n, char c)都是将字符串中有效字符个数改变到n个,不

同的是当字符个数增多时:resize(n)用0来填充多出的元素空间,resize(size_t n, char

c)用字符c来填充多出的元素空间。注意:resize在改变元素个数时,如果是将元素个数

增多,可能会改变底层容量的大小,如果是将元素个数减少,底层空间总大小不变。

  1. reserve(size_t res_arg=0):为string预留空间,不改变有效元素个数,当reserve的参

数小于string的底层空间总大小时,reserver不会改变容量大小。

3、string类对象的访问及遍历操作

在这里插入图片描述

4、string类对象的修改操作

在这里插入图片描述

注意:

  1. 在string尾部追加字符时,s.push_back© / s.append(1, c) / s += 'c’三种的实现方式差

不多,一般情况下string类的+=操作用的比较多,+=操作不仅可以连接单个字符,还可

以连接字符串。

  1. 对string操作时,如果能够大概预估到放多少字符,可以先通过reserve把空间预留

好。

5、string类非成员函数

在这里插入图片描述

6、vs和g++下string结构的说明

注意:下述结构是在32位平台下进行验证,32位平台下指针占4个字节。

vs下string的结构

string总共占28个字节,内部结构稍微复杂一点,先是有一个联合体,联合体用来定义

string中字符串的存储空间:

当字符串长度小于16时,使用内部固定的字符数组来存放

当字符串长度大于等于16时,从堆上开辟空间

union _Bxty
{ // storage for small buffer or pointer to larger onevalue_type _Buf[_BUF_SIZE];pointer _Ptr;char _Alias[_BUF_SIZE]; // to permit aliasing
} _Bx;

这种设计也是有一定道理的,大多数情况下字符串的长度都小于16,那string对象创建

好之后,内部已经有了16个字符数组的固定空间,不需要通过堆创建,效率高。

其次:还有一个size_t字段保存字符串长度,一个size_t字段保存从堆上开辟空间总的

容量

最后:还有一个指针做一些其他事情。

故总共占16+4+4+4=28个字节。

在这里插入图片描述

g++下string的结构**

G++下,string是通过写时拷贝实现的,string对象总共占4个字节,内部只包含了一个

指针,该指针将来指向一块堆空间,内部包含了如下字段:

空间总大小

字符串有效长度

引用计数

struct _Rep_base
{size_type _M_length;size_type _M_capacity;_Atomic_word _M_refcount;
};

二、string类的模拟实现

1、构造和析构

对于构造和析构这种频繁调用的函数可以直接在类里面写设为inline

构造:

string(const char* str = "")//空拷贝时就一个\0套到下面可以实现。
{_size = strlen(str);//// _capacity计算大小不包含\0_capacity = _size;_str = new char[_capacity + 1];strcpy(_str, str);//把原来的数据拷贝过来。
}

拷贝构造:(拷贝构造一定要深拷贝)

string(const string& s)//拷贝构造
{_size = s._size;_capacity = _capacity;_str = new char[_capacity + 1];strcpy(_str, s._str);//把原来的数据拷贝过来。
}

析构

~string()
{delete[] _str;_str = nullptr_capacity = _size = 0;
}

赋值

 string& operator=(const string& s){if (this != &s)//两个是不同的{delete[] _str;_str = new char[s._capacity + 1];//开的时候比capacity多开一个保证两个空间相同。strcpy(_str, s._str);_size = s._size;_capacity = s._capacity;}return *this;//两个相同返回本身。}

深浅拷贝问题:

浅拷贝:也称位拷贝,编译器只是将对象中的值拷贝过来。如果对象中管理资源,最后就会导致

多个对象共享同一份资源,当一个对象销毁时就会将该资源释放掉,而此时另一些对象不知道该

资源已经被释放,以为还有效,所以当继续对资源进项操作时,就会发生发生了访问违规。

在这里插入图片描述

深拷贝如果一个类中涉及到资源的管理,其拷贝构造函数、赋值运算符重载以及析构函数必须要显式给出。

一般情况都是按照深拷贝方式提供。

在这里插入图片描述

2、迭代器

string的迭代器本质就是指针。

typedef char* iterator;
iterator begin()
{return _str;
}
iterator end()
{return _str + _size;
}

3、容量操作

size_t size()
{return _size;;
}
size_t capacity()const
{return _capacity;
}
bool empty()const
{return _size == 0;
}
void clear()
{*_str = '\0';//第一个为\0_size = 0;//长度为0
}
char& operator[](size_t index)
{assert(index < _size);return _str[index];
}
const char& operator[](size_t pos) const
{assert(pos < _size);return _str[pos];
}
void string::reserve(size_t n)
{if (n > _capacity)//大了才能改{auto* tmp = new char[n + 1];strcpy(tmp, _str);delete[] _str;_str = tmp;_capacity = n;}else{perror("reserve fail");}
}
void string::resize(size_t n, char c)
{if (_size > n){_str[n] = c;_size = n;}else{reserve(n);//扩空间for (size_t i = _size; i < n; i++){_str[i] = c;}_size = n;}
}

4、修改操作

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;
}
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;
}
size_t string::find(const char* str, size_t pos) const
{assert(pos < _size);const char* ptr = strstr(_str + pos, str);//直接用找字串的函数if (ptr == nullptr){return npos;}else{return ptr - _str;}
}
string& string::insert(size_t pos, char c)
{assert(pos <= _size);if (_size == _capacity){reserve(_capacity == 0 ? 4 : _capacity * 2);}for (size_t i = _size + 1; i > pos; i--){_str[i] = _str[i - 1];}_str[pos] = c;++_size;return *this;
}
string& string::insert(size_t pos, const char* str)
{assert(pos <= _size);if (_size + strlen(str) > _capacity){// 大于2倍,需要多少开多少,小于2倍按2倍扩reserve(_size + strlen(str) > 2 * _capacity ? _size + strlen(str) : 2 * _capacity);}for (size_t i = _size + 1 + strlen(str); i > pos ; i--){_str[i] = _str[i - strlen(str)];}for (size_t i = 0; i < strlen(str); i++)//用strcpy有数据丢失风险{_str[pos + i] = str[i];}_size += strlen(str);return *this;
}
string& 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++)//把len长度删了{_str[i - len] = _str[i];}_size -= len;}
}

5、比较操作

比较操作放在类外面比较好用

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 strcmp(s1.c_str(), s2.c_str()) == 0;
}bool operator!=(const string& s1, const string& s2)
{return !(s1 == s2);
}

6、cout和cin

    ostream& operator<<(ostream& _cout, const str::string& s){for (auto ch : s){_cout << ch;}return _cout;}istream& operator>>(istream& in, string& s){s.clear();//每次读之前清理一下const int N = 256;char buff[N];//定义一个buff数组避免频繁扩容int i = 0;char ch;//in >> ch;//不用>>是因为它默认以空格和换行为分割符。ch = in.get();while (ch != ' ' && ch != '\n'){buff[i++] = ch;if (i == N - 1){buff[i] = '\0';s += buff;//满了就加给si = 0;}ch = in.get();}if (i > 0){buff[i] = '\0';//出来如果每满加\0并给ss += buff;}return in;}
}

7、所有文件

string.h

#define _CRT_SECURE_NO_WARNINGS 1
#pragma once
#include<iostream>
#include<string>
#include<assert.h>
using namespace std;
namespace str
{class string{public:typedef char* iterator;iterator begin(){return _str;}iterator end(){return _str + _size;}typedef const char* const_iterator;const_iterator begin() const{return _str;}const_iterator end() const{return _str + _size;}public:string(const char* str = "")//空拷贝时就一个\0套到下面可以实现。{_size = strlen(str);// _capacity计算大小不包含\0_capacity = _size;_str = new char[_capacity + 1];//多开一个放\0strcpy(_str, str);//把原来的数据拷贝过来。}string(const string& s)//拷贝构造{_size = s._size;_capacity = _capacity;_str = new char[_capacity + 1];strcpy(_str, s._str);//把原来的数据拷贝过来。}string& operator=(const string& s){if (this != &s)//两个是不同的{delete[] _str;_str = new char[s._capacity + 1];//开的时候比capacity多开一个保证两个空间相同。strcpy(_str, s._str);_size = s._size;_capacity = s._capacity;}return *this;//两个相同返回本身。}~string(){delete[] _str;_str = nullptr;_capacity = _size = 0;}void push_back(char c);string& operator+=(char c);void append(const char* str);string& operator+=(const char* str);const char* c_str() const;void clear(){*_str = '\0';//第一个为\0_size = 0;//长度为0}/// capacitysize_t size(){return _size;;}size_t capacity()const{return _capacity;}bool empty()const{return _size == 0;}void resize(size_t n, char c = '\0');void reserve(size_t n);/// accesschar& operator[](size_t index){assert(index < _size);return _str[index];}const char& operator[](size_t pos) const{assert(pos < _size);return _str[pos];}///relational operators// 返回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/字符串str,并返回该字符的位置string& insert(size_t pos, char c);string& insert(size_t pos, const char* str);// 删除pos位置上的元素,并返回该元素的下一个位置string& erase(size_t pos, size_t len);private:char* _str;size_t _capacity;size_t _size;static size_t nops;};ostream& operator<<(ostream& _cout, const str::string& s);istream& operator>>(istream& _cin, str::string& s);static size_t npos = -1;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);bool operator!=(const string& s1, const string& s2);
}

string.c

#include"string.h"
#include<iostream>
using namespace std;
namespace str
{void string::reserve(size_t n){if (n > _capacity)//大了才能改{auto* tmp = new char[n + 1];strcpy(tmp, _str);delete[] _str;_str = tmp;_capacity = n;}else{perror("reserve fail");}}void string::resize(size_t n, char c){if (_size > n){_str[n] = c;_size = n;}else{reserve(n);//扩空间for (size_t i = _size; i < n; i++){_str[i] = c;}_size = n;}}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;}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;}size_t string::find(const char* str, size_t pos) const{assert(pos < _size);const char* ptr = strstr(_str + pos, str);//直接用找字串的函数if (ptr == nullptr){return npos;}else{return ptr - _str;}}string& string::insert(size_t pos, char c){assert(pos <= _size);if (_size == _capacity){reserve(_capacity == 0 ? 4 : _capacity * 2);}for (size_t i = _size + 1; i > pos; i--){_str[i] = _str[i - 1];}_str[pos] = c;++_size;return *this;}string& string::insert(size_t pos, const char* str){assert(pos <= _size);if (_size + strlen(str) > _capacity){// 大于2倍,需要多少开多少,小于2倍按2倍扩reserve(_size + strlen(str) > 2 * _capacity ? _size + strlen(str) : 2 * _capacity);}for (size_t i = _size + 1 + strlen(str); i > pos ; i--){_str[i] = _str[i - strlen(str)];}for (size_t i = 0; i < strlen(str); i++)//用strcpy有数据丢失风险{_str[pos + i] = str[i];}_size += strlen(str);return *this;}string& 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++)//把len长度删了{_str[i - len] = _str[i];}_size -= len;}}const char* string::c_str() const{return _str;}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 strcmp(s1.c_str(), s2.c_str()) == 0;}bool operator!=(const string& s1, const string& s2){return !(s1 == s2);}ostream& operator<<(ostream& _cout, const str::string& s){for (auto ch : s){_cout << ch;}return _cout;}istream& operator>>(istream& in, string& s){s.clear();//每次读之前清理一下const int N = 256;char buff[N];//定义一个buff数组避免频繁扩容int i = 0;char ch;//in >> ch;//不用>>是因为它默认以空格和换行为分割符。ch = in.get();while (ch != ' ' && ch != '\n'){buff[i++] = ch;if (i == N - 1){buff[i] = '\0';s += buff;//满了就加给si = 0;}ch = in.get();}if (i > 0){buff[i] = '\0';//出来如果每满加\0并给ss += buff;}return in;}
}

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

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

相关文章

Cannot perform upm operation: connect ETIMEDOUT 34.36.199.114:443 [NotFound]

版本&#xff1a;Unity 2018 Windows 问题&#xff1a;打开 Package Manager&#xff0c;加载报错 尝试解决&#xff1a; 删除项目文件里的Packages下的mainfest.json文件&#xff0c;然后重新打开项目&#xff08;X&#xff09;重新登录 Unity 账号&#xff08;X&#xff09…

Kotlin 协程 — 基础

Kotlin 协程 — 基础 协程已经存在一段时间了&#xff0c;关于它的各种文章也很多。但我发现想要了解它还比较费时&#xff0c;所以我花了一段时间才真正理解了协程的基础知识以及它的工作原理。因此&#xff0c;我想分享一些我理解到的内容。 什么是协程&#xff1f; 协程代表…

vue项目实战速查记录

1.图片下载到本地 2.本地静态文件访问 3.元素大小相同,相互覆盖 1.图片下载到本地 实现原理:创建a标签,利用a标签下载属性. download(){const link document.createElement(a);link.href "图片地址";link.setAttribute(download, name);document.body.ap…

读论文《Hi-Net: Hybrid-fusion Network for Multi-modalMR Image Synthesis》

论文题目&#xff1a;Hi-Net:用于多模态磁共振图像合成的混合融合网络 论文地址&#xff1a;arxiv 项目地址&#xff1a;github 原项目可能在训练的时候汇报version的错&#xff0c;这是因为生成器和辨别器的优化有些逻辑错误&#xff0c;会改的话多加一个生成操作可以解决&…

React 学习——条件渲染、遍历循环、事件绑定

React特点&#xff1a; 声明式的设计高效&#xff0c;采用虚拟DOM来实现DOM的渲染&#xff0c;最大限度减少DOM的操作灵活&#xff0c;跟其他库灵活搭配使用JSX&#xff0c;俗称JS里面写HTML&#xff0c;JavaScript语法的扩展组件化&#xff0c;模块化&#xff0c;代码容易复用…

pdf的下载,后端返回工作流,前端进行转换

前端将后端返回的工作流进行转换 项目中接触到了pdf的下载和预览的功能&#xff0c;记录一下~ 这里pdf的下载和预览的接口&#xff0c;后端返回的数据结构与其他的接口返回的数据结构有点不同&#xff0c;是直接返回的工作流&#xff0c;在控制台接口的响应预览内容大致是这样…

初学MySQl简单sql语句(1)

目录 SQL语句介绍&#xff1a; DDL创建数据库&#xff1a; char和varchar比较 数值类型 数据库存储引擎 数据库存储引擎——InnoDB 数据库存储引擎——MyISAM 数据库存储引擎-MyISAM 和InnoDB区别 修改和删除数据库表 数据库设计三大范式 一、什么是范式 二、约束作…

css实战案例1:顶部搜索

代码样式&#xff1a; <!DOCTYPE html> <html><head><meta charset"utf-8" /><title></title></head><body><div class"search_box"><!-- 搜索框--><div class"search">搜索…

【Linux】网络基础_2

文章目录 十、网络基础2. IP地址和MAC地址3. 端口号端口号和进程ID 4. 网络字节序 未完待续 十、网络基础 2. IP地址和MAC地址 IP协议有两个版本&#xff0c;IPv4和IPv6&#xff0c; 用的比较多的都是IPv4。IP地址是在IP协议中&#xff0c;用来标识网络中不同主机的地址&…

如何发现快速发现分析生产问题SQL

Performance Schema介绍 Performance Schema提供了有关MySQL服务器内部运行的操作上的底层指标。为了解释清楚Performance Schema的工作机制&#xff0c;先介绍两个概念。 第一个概念是程序插桩&#xff08;instrument&#xff09;。程序插桩在MySQL代码中插入探测代码&#xf…

基本聚集函数和case的应用

文章目录 1.基本聚集函数(1)基本聚集函数的介绍(2)使用基本聚集函数的简单例子&#xff08;1&#xff09;查询最大年龄&#xff0c;最小年龄年龄和平均年龄<1>最大年龄<2>最小年龄<3>平均年龄 (2&#xff09;配合上where语句&#xff0c;查询女士的平均年龄(…

JAVA笔记十四

十四、集合 1.集合概述 (1)集合是存储其它对象的特殊对象&#xff0c;可以将集合当作一个容器 (2)集合的相关接口和类位于java.util包中 (3)集合中的接口和类是一个整体、一个体系 2.集合接口 接口定义了一组抽象方法&#xff0c;实现该接口的类需要实现这些抽象方法&…

Docker核心技术:Docker原理之Cgroups

云原生学习路线导航页&#xff08;持续更新中&#xff09; 本文是 Docker核心技术 系列文章&#xff1a;Docker原理之Cgroups&#xff0c;其他文章快捷链接如下&#xff1a; 应用架构演进容器技术要解决哪些问题Docker的基本使用Docker是如何实现的 Docker核心技术&#xff1a;…

C++初学者指南-5.标准库(第一部分)--标准库最小/最大算法

C初学者指南-5.标准库(第一部分)–标准库min/max算法 文章目录 C初学者指南-5.标准库(第一部分)--标准库min/max算法minmaxminmaxclamp (C17)min_elementmax_elementminmax_element相关内容 C标准库算法是一块新领域&#xff1f;⇒简短介绍 min min(a, b) → a 如果 a < b则…

Linux_实现UDP网络通信

目录 1、实现服务器的逻辑 1.1 socket 1.2 bind 1.3 recvfrom 1.4 sendto 1.5 服务器代码 2、实现客户端的逻辑 2.1 客户端代码 3、实现通信 结语 前言&#xff1a; 在Linux下&#xff0c;实现传输层协议为UDP的套接字进行网络通信&#xff0c;网络层协议为IPv4&am…

k8s+containerd(kvm版)

k8s&#xff08;Kubernetes&#xff09;是由Gogle开源的容器编排引擎&#xff0c;可以用来管理容器化的应用程序和服务&#xff0c;k 高可用&#xff1a;系统在长时间内持续正常地运行&#xff0c;并不会因为某一个组件或者服务的故障而导致整个系统不可用可扩展性&#xff1a…

【SpringBoot】 jasypt配置文件密码加解密

目前我们对yml配置文件中的密码都是明文显示&#xff0c;显然这不安全&#xff0c;有的程序员离职了以后可能会做一些非法骚操作&#xff0c;所以我们最好要做一个加密&#xff0c;只能让领导架构师或者技术经理知道这个密码。所以这节课就需要来实现一下。 我们可以使用jasypt…

爬虫学习3:爬虫的深度爬取

爬虫的深度爬取和爬取视频的方式 深度爬取豆瓣读书 import time import fake_useragent import requests from lxml import etree head {"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 …

陶德:边种田边写代码,3年300万行,一个人写出了“国产大满贯QT”

这是《开发者说》的第12期&#xff0c;本期我们邀请的开发者是陶德&#xff0c;从小在国企矿山里长大&#xff0c;计算机成绩是文科班里最差的一个&#xff0c;毕业两年找不到工作&#xff0c;睡过公园&#xff0c;讨过剩饭&#xff0c;用打魔兽世界的方式磨炼技术&#xff0c;…

.NET 8+Vue2 部署到Window Server

.NET 8Vue2 部署到Window Server 1 配置环境 1.1 下载安装.NET 8 SDK&#xff0c;下载时需注意目标服务器的系统类型&#xff08;64位 or 32位&#xff09; https://dotnet.microsoft.com/zh-cn/download 1.2 下载安装SQL Server数据库&#xff08;服务和管理工具&#xff…