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

【C++笔记】C++string类模拟实现

【C++笔记】C++string类模拟实现

  • 一、实现模型和基本接口
    • 1.1、各种构造和析构
    • 1.2、迭代器
  • 二、各种插入和删除接口
    • 2.1、插入接口
    • 2.2、删除接口
    • 2.3、resize接口
  • 三、各种运算符重载
    • 3.1、方括号运算符重载
    • 3.2、各种比较运算符重载
  • 四、查找接口
    • 4.1、查找字符
    • 4.2、查找子串
  • 五、流插入流提取运算符重载
    • 5.1、流插入运算符重载
    • 5.2、流提取运算符重载

C++的string类也就是字符串,它是一个比较早的类,所以就没有被归到STL里。
这里实现的string只是为了粗浅的了解一下string的底层原理,所以可定不会有库里面的那么详细,而且这里也只会实现一些常用的接口,一些不常用的接口实现起来也没什么意思。

一、实现模型和基本接口

既然是管理字符串的,那我们就直接封装一个char*即可:

class String {
public :
private :char* _str; // 时刻被操作的字符串size_t _size; // 长度size_t _capacity; // 容量
};

然后我们实现的各个接口都是为了操作类中封装的这个_str即可。

1.1、各种构造和析构

构造函数:
其实构造函数有很多种实现方式,但我们日常用的最多的应该就是字符串构造,因为他本身就是存储字符串的嘛。
所以我们仅提供一个全缺省的构造函数即可:

String(const char* str = "") {_size = strlen(str);_capacity = strlen(str);_str = new char[_capacity + 1];strcpy(_str, str);}

需要注意的是,这里的容量表示的是该字符串最多能存多少个字符,但我们都知道字符串的结束标志’\0’是不能少的,每个字符串的结尾都必须存一个’\0’,所以我们这里开空间是中要比容量多1。
拷贝构造:
拷贝构造也很简单,直接开一段新空间然后复制参数中_str的内容即可。

String(const String& str) {// 只用来提示构造函数被调用cout << "String(const String& str)" << endl;_str = new char[str._capacity + 1];strcpy(_str, str._str);_size = str._size;_capacity = str._capacity;}

但是依然要注意,我们这里开空间一定要比容量多1。
析构函数:
因为我们至始至终都只管理着一个外部资源也就是_str,所以析构函数要做的工作也就很简单了,直接释放掉_str即可:

~String() {// 只用来提示析构函数被调用cout << "~String()" << endl; delete[] _str;_str = nullptr;_size = 0;_capacity = 0;}

然后我们可以先提供一个简易的打印接口,来试验我们以上所写的接口:

const char* get_str() const {return _str;}

在这里插入图片描述
从运行的结果来看,以上写的接口是没什么问题的。

1.2、迭代器

C++中的迭代器是一个很棒的设计,有了迭代器,我们就可以使很多类的遍历方法变得相同。
但这只是写的时候相同,迭代器其实是屏蔽了底层的原理,然后使用一套统一的方法来遍历,例如:
在这里插入图片描述
如上,字符串、vector和链表的底层肯定是不一样的,但它们展现出来的遍历方式却是一样的,这就是iterator迭代器的妙处。
这样一来即使有一些容器我们并不知道它的底层实现原理怎样,但是我们也还是可以照常遍历它们。

相信大家从上面对it的解引用也可以看得出,其实迭迭代器底层就是模拟的指针的行为。
但迭代器也并非都是用原生指针来实现的,对于像string和vector指针顺序结构,使用原生指针是完全可以的。但是对于list这种链式结构和各种树形结构使用原生指针的话就不行了,这需要对原生指针就行再次封装才行。

而现在的string使用原生指针是完全可以的:

class String {
public :
typedef char* iterator;
private :char* _str; // 时刻被操作的字符串size_t _size; // 长度size_t _capacity; // 容量
};

迭代器我们往往只需要提供两个位置即开始和结尾即可:

iterator begin() {return _str;
}
// 迭代器结束位置
iterator end() {return _str + _size;
}

这样我们就可以使用迭代器来遍历我们模拟实现的string类了:
在这里插入图片描述
有了迭代器,我们就可以使用一个更简便的遍历方式——范围for,因为范围for的底层就是使用迭代器实现的,编译器只是把范围for的语法傻傻的替换成迭代器而已:
在这里插入图片描述

二、各种插入和删除接口

2.1、插入接口

尾插一个字符
string中的_size指的是字符串的长度,但是因为字符串的下标其实是从0开始的,所以实际上_size所指向的位置其实是’\0’的位置:
在这里插入图片描述

所以当我们要尾插一个字符的时候,这个字符其实是要放在_size的位置。

void push_back(char ch) {// 检查扩容if (_size == _capacity) {reverse(_capacity == 0 ? 4 : 2 * _capacity);}_str[_size] = ch;_size++;_str[_size] = '\0';
}

如上,要插入数据就必定会遇到空间不足的情况,所以我们在正式插入之前必须先检查是否需要扩容。扩容的逻辑很简单,就是申请一块新容量的空间然后拷贝数据到新空间然后释放就空间在在让_str指向新空间即可:

void reverse(size_t newCapacity) {if (newCapacity > _capacity) {char* temp = new char[newCapacity + 1];strcpy(temp, _str);delete[] _str;_str = temp;_capacity = newCapacity;}
}

尾插一个字符串(追加)
尾插一个字符串的逻辑其实和尾插一个字符的逻辑大差不差,只不过是字符变多了而已。

void append(const char* str) {assert(str);// 检查扩容size_t len = strlen(str);if (_size + len > _capacity) {reverse(_size + len);}strncpy(_str + _size, str, len);_size += len;// 因为strcpy并不会连带'\0'一起拷贝,所以我们得自己补上_str[_size] = '\0'; 
}

随机插入一个字符
在pos位置插入一个字符ch。
因为string也属于顺序结构,对于顺序结构来说随机插入最烦人的就是挪动数据,例如这里我们要把从pos位置其后面的所有数据都向后移动一个位置:
在这里插入图片描述
未完成这个操作我们可以定义一个end指向_size的位置 (使end从_size开始是为了连‘‘0’一起移动,到最后就不需要再手动加上’\0’了),也就是’\0’的位置:
在这里插入图片描述
然后循环操作_str[end + 1] = _str[end],并让end–直到end与pos重合为止。

void insert(size_t pos, char ch) {assert(pos <= _size);// 检查扩容if (_size == _capacity) {reverse(_capacity == 0 ? 4 : 2 * _capacity);}// 挪动数据int end = _size;while (end >= (int)pos) {_str[end + 1] = _str[end];end--;}_str[pos] = ch;_size++;
}

随机插入一个字符串
随机插入一个字符串的逻辑也和随机插入一个字符的逻辑大差不差,我们几乎可以复用之前的逻辑,然后只需要改动挪动数据的间隔即可。

void insert(size_t pos, const char* str) {assert(pos <= _size);// 检查扩容size_t len = strlen(str);if (_size + len > _capacity) {reverse(_size + len);}// 挪动数据int end = _size;while (end >= (int)pos) {// 这里只需要将1改成len即可_str[end + len] = _str[end];end--;}// 拷贝数据strncpy(_str + pos, str, len);_size += len;}

写完我们可以顺势来检验一下:
在这里插入图片描述

2.2、删除接口

从pos位置开始,删除len个字符。
这个接口的逻辑就比insert要简单了,我们只需要将后面的数都向前挪动len个位置,覆盖掉前面的数据即可。
例如pos = 5,len = 6的情况:
在这里插入图片描述
为了完成这个操作,定义一个变量begin,让它从pos + len位置开始,然后循环执行_str[begin - len] = _str[begin],并让begin++,直到begin和_size重合(连带’\0’一起挪动):
在这里插入图片描述
有了以上分析,那我们写起代码来也就水到渠成了:

void erase(size_t pos, size_t len) {assert(pos < _size);size_t begin = pos + len;// 挪动数据while (begin <= _size) {_str[begin - len] = _str[begin];begin++;}_size -= len;
}

2.3、resize接口

有时候我们可能需要重置长度,特别是想要删除后面的数据只保留前面若干个数据的时候,我们或许会觉得使用erease可能太麻烦了。
所以我们要用到resize,这个接口可以一键保留前几个字符,或者扩大容量,后面的空间以某个字符进行填充。

实现这个接口其实要分两种情况:
当newSize < _size时候,我们要做的其实很简单,就是直接让_size = newSize,然后再让_str[_size] = '\0’即可。
而当newSize > _size时候我们才要进行填充,特别是当newSize > _capacity时,我们就需要先扩容再进行填充。

void resize(size_t newSize, char ch = '\0') {if (newSize > _size) {if (newSize > _capacity) {reverse(newSize);}// 填充字符memset(_str + _size, ch, newSize - _size);}_size = newSize;_str[_size] = '\0';
}

三、各种运算符重载

有了各种运算符重载我们就可以像内置类型一样使用我们的自定义类型了。

3.1、方括号运算符重载

有了方括号运算符重载,我们就可以像数组一样使用方括号[]来对我们定义的字符串进行遍历了。
它的实现原理很简单,就是返回_str[i]位置的引用即可:

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

但方括号运算符重载也要分const和非const版本的,因为有些时候我们只是想读取数据而不想修改数据,有些时候我们即想读也想改。

紧接着我们就可以来测试一下了:
在这里插入图片描述

3.2、各种比较运算符重载

小于运算符重载
既然我们都是在对_str进行操作,那当然就可以直接使用strcmp进行比较了:

bool operator<(const String& str) {return strcmp(_str, str._str) < 0;
}

等于运算符重载

bool operator==(const String& str) {return strcmp(_str, str._str) == 0;
}

小于等于运算符重载
其实实现了上面这两个之后,其他的都变得很简单了,我们直接复用即可,这不仅对于string这个类如此。几乎所有类都可以这样,因为这都是一些逻辑判断而已。

bool operator<=(const String& str) {return (*this < str) || (*this == str);
}

大于运算符重载

bool operator>(const String& str) {return !(*this <= str);
}

大于等于运算符重载

bool operator>=(const String& str) {return (*this > str) || (*this == str);
}

不等于运算符重载

bool operator!=(const String& str) {return !(*this == str);
}

四、查找接口

4.1、查找字符

从pos位置开始查找,返回字符ch在String中第一次出现的位置,找不到则返回起始位置。
这个逻辑其实很简单,从pos位置开始匹配即可。

size_t find(char ch, size_t pos = 0) const {assert(pos < _size);for (size_t i = pos; i < _size; i++) {if (ch == _str[i]) {return i;}}return pos;
}

我们可以测试一下:
在这里插入图片描述

4.2、查找子串

从pos位置开始查找,返回子串str在String中第一次出现的位置。
这个接口我们可以直接使用C++的前身C语言中的库函数strstr:
在这里插入图片描述
但是通过查看上面文档中的描述我们就会发现,strstr返回的并不是整数而是一个指针——指向子串在字符串中第一次出现的位置。
但这并不是什么大问题,不要忘了指针是可以相减的,并且相减得的结果也是一个整数,所以我们可以拿strstr的返回值减去_str,也就得到了我们想要的结果。

size_t find(const char* str, size_t pos = 0) const {assert(pos < _size);return strstr(_str + pos, str) - _str;
}

我们同样可以来测试一下:
在这里插入图片描述

五、流插入流提取运算符重载

5.1、流插入运算符重载

虽然我们已经有了三种遍历字符串的方式(方括号、迭代器、范围for),但好像觉得都不是很方便。因为我们内置的字符数组其实是可以直接使用cout打印的:
在这里插入图片描述
如果用这个和其他的遍历方式进行比较,毫无疑问这个就是最方便的遍历方式了。
那我们实现的string能不能也只用这样的方法呢?
当然可以,我们只需要对String重载流插入运算符即可。

我们之前已经了解过了,因为参数的顺序问题,流插入和流提取运算符重载最好是重载成全局函数。
而又因为在类外边不能访问私有成员,所以我们要将这两个函数声明称String类的友元函数:

class Stirng {// 流插入流提取友元声明friend ostream& operator<<(ostream& _cout, const String& str);friend istream& operator>>(istream& _cin, String& str);
public :
private :char* str;size_t _size;size_t _capacity;
};

然后我们就可以开始动手写代码了:

ostream& operator<<(ostream& _cout, const String& str) {for (auto it : str) {_cout << it;}return _cout;
}

这里还要补充的一点就是关于const迭代器的事项,如果我们没有定义实现const迭代器,那我们直接使用范围for是会报错的:
在这里插入图片描述
原因就在于我们这里传的是一个const对象,而我们这里只实现了非const的迭代器,const对象是不能调用非const函数的。
想要解决这个问题我们就要把const迭代器实现了:
在这里插入图片描述
然后在实现const迭代器版本的begin和end:
在这里插入图片描述
这样我们的代码才能正确运行:
在这里插入图片描述

5.2、流提取运算符重载

流提取就相当于C语言中的scanf函数和C++中的cin运算符:
在这里插入图片描述
想要重载这个操作符我们在正式接收数据的时候需要先将原字符串内的数据清空:

// 清理数据
void clear() {_size = 0;
}

然后在接收数据插入字符串。

然后我们就可以动手写代码了:

// 流提取运算符重载
istream& operator>>(istream& _cin, String& str) {// 先清理数据str.clear();char ch = _cin.get();while (ch != ' ' && ch != '\n') {str += ch;ch = _cin.get();}return _cin;
}

这里还需要注意的一点就是,像scanf和cin都是默认以空格和换行符为多个字符的分隔的,也就是说他们不会接收空格和换行符。所以要想接收到空格和换行符不能直接用cin,而是要使用cin.get()。

相关文章:

【C++笔记】C++string类模拟实现

【C笔记】Cstring类模拟实现 一、实现模型和基本接口1.1、各种构造和析构1.2、迭代器 二、各种插入和删除接口2.1、插入接口2.2、删除接口2.3、resize接口 三、各种运算符重载3.1、方括号运算符重载3.2、各种比较运算符重载 四、查找接口4.1、查找字符4.2、查找子串 五、流插入…...

操作系统之课后习题——引论

&#xff08;一&#xff09;简答题 1.在计算机系统上配置OS的目标是什么&#xff1f;作用主要表现在哪几个方面&#xff1f; 答&#xff1a; 在计算机系统上配置OS&#xff0c;主要目标是实现&#xff1a;方便性、有效性、可扩充性和开放性&#xff1b; OS的作用主要表现在以下…...

【PHP代码审计】反序列化漏洞实战

文章目录 概述资源下载地址Typecho代码审计-漏洞原理call_user_func()_applyFilter()、get()与__get__toString()__construct()install.php POC利用漏洞利用复现利用链执行phpinfo()GET利用POST利用 getshell生成payload漏洞利用蚁剑连接 总结 概述 序列化&#xff0c;“将对象…...

Socks5 与 HTTP 代理在网络安全中的应用

目录 Socks5和HTTP代理在网络安全中的应用。 Socks5代理和HTTP代理的优点和缺点。 选择合适的代理IP需要考虑的因素&#xff1a; 总结 在网络安全领域中&#xff0c;Socks5和HTTP代理都扮演着重要的角色。作为两种不同的代理技术&#xff0c;它们在网络安全中的应用各有特点…...

进阶C语言-指针的进阶(中)

指针的进阶 &#x1f4d6;5.函数指针&#x1f4d6;6.函数指针数组&#x1f4d6;7.指向函数指针数组的指针&#x1f4d6;8.回调函数 &#x1f4d6;5.函数指针 数组指针 - 指向数组的指针 - 存放的是数组的地址 - &数组名就是数组的地址。 函数指针 - 指向函数的指针 - 存放的…...

保姆级-微信小程序开发教程

一&#xff0c;注册微信小程序 如果你还没有微信公众平台的账号&#xff0c;请先进入微信公众平台首页&#xff0c;点击 “立即注册” 按钮进行注册。注册的账号类型可以是订阅号、服务号、小程序以及企业微信&#xff0c;我们选择 “小程序” 即可。 接着填写账号信息&#x…...

数据库-DQL

DQL&#xff1a;用来查询数据库表中的记录 关键字&#xff1a;SELECT 语法&#xff1a; select&#xff1a;字段列表 from&#xff1a;表名列表 where&#xff1a;条件列表 group by&#xff1a;分组列表 having&#xff1a;分组后条件列表 order by&#xff1a;排序字段列表…...

19 螺旋矩阵

螺旋矩阵 题解1 循环&#xff08;4个标志——根据顺时针&#xff09;题解2 方向 给你一个 m 行 n 列的矩阵 matrix &#xff0c;请按照 顺时针螺旋顺序 &#xff0c;返回矩阵中的所有元素。 提示&#xff1a; - m matrix.length - n matrix[i].length - 1 < m, n <…...

数据结构与算法:概述

目录 算法 评价标准 时间的复杂度 概念 推导原则 举例 空间的复杂度 定义 情形 运用场景 数据结构 组成方式 算法 在数学领域&#xff0c;算法是解决某一类问题的公式和思想&#xff1b; 计算机科学领域&#xff0c;是指一系列程序指令&#xff0c;用于解决特定的…...

顺序表详解

&#x1f493; 博客主页&#xff1a;江池俊的博客⏩ 收录专栏&#xff1a;数据结构探索&#x1f449;专栏推荐&#xff1a;✅C语言初阶之路 ✅C语言进阶之路&#x1f4bb;代码仓库&#xff1a;江池俊的代码仓库&#x1f525;编译环境&#xff1a;Visual Studio 2022&#x1f38…...

基于RabbitMQ的模拟消息队列之六——网络通信设计

自定义基于TCP的应用层通信协议。实现客户端对服务器的远程调用 编写服务器及客户端代码 文章目录 基于TCP的自定义应用层协议一、请求1.请求格式2.创建Request类 二、响应1.响应格式2.创建Response类 三、客户端-服务器交互四、type五、请求payload1.BasicAruguments(方法公共…...

算法:数组中的最大差值---“打擂台法“

文章来源&#xff1a; https://blog.csdn.net/weixin_45630258/article/details/132737088 欢迎各位大佬指点、三连 1、题目&#xff1a; 给定一个整数数组 nums&#xff0c;找出给定数组中两个数字之间的最大差值。要求&#xff0c;第二个数字必须大于第一个数字。 2、分析特…...

三种方式查看 JVM 垃圾收集器

一、引言 不同版本的 JVM 默认使用的垃圾收集器是不同的&#xff0c;目前的新生代和老年代的垃圾收集器如下图所示&#xff0c;新生代和老年代之间的连线表示这些垃圾收集器可以进行搭配使用 垃圾收集器的名字和 JVM 里面的参数对照表如下&#xff0c;即在 JVM 里面并不是存储的…...

React中函数式组件与类组件有何不同?

Function Component 与 Class Component 有何不同 目录 Function Component 与 Class Component 有何不同 文章核心观点&#xff1a; 解释一下&#xff1a; 总结&#xff1a; 文章核心观点&#xff1a; Function components capture the rendered values.函数式组件捕获…...

windows11安装docker时,修改默认安装到C盘

1、修改默认安装到C盘 2、如果之前安装过docker&#xff0c;请删除如下目录&#xff1a;C:\Program Files\Docker 3、在D盘新建目录&#xff1a;D:\Program Files\Docker 4、winr&#xff0c;以管理员权限运行cmd 5、在cmd中执行如下命令&#xff0c;建立软联接&#xff1a; m…...

python模块之 aiomysql 异步mysql

mysql安装教程 mysql语法大全 python 模块pymysql模块&#xff0c;连接mysql数据库 一、介绍 aiomysql 是一个基于 asyncio 的异步 MySQL 客户端库&#xff0c;用于在 Python 中与 MySQL 数据库进行交互。它提供了异步的数据库连接和查询操作&#xff0c;适用于异步编程环境 …...

开开心心带你学习MySQL数据库之第八篇

索引和事务 ~~ 数据库运行的原理知识 面试题 索引 索引(index) > 目录 索引存在的意义,就是为了加快查找速度!!(省略了遍历的过程) 查找速度是快了&#xff0c;但是付出了一定的代价!! 1.需要付出额外的空间代价来保存索引数据 2.索引可能会拖慢新增,删除,修改的速度 ~~ …...

yml配置动态数据源(数据库@DS)与引起(If you want an embedded database (H2, HSQL or Derby))类问题

1&#xff1a;yml 配置 spring:datasource:dynamic:datasource:master:url: jdbc:mysql://192.168.11.50:3306/dsdd?characterEncodingUTF-8&useUnicodetrue&useSSLfalse&tinyInt1isBitfalse&allowPublicKeyRetrievaltrue&serverTimezoneUTCusername: ro…...

yolov5运行过程遇到的小问题(随时更新)

1.关于git的问题 解决办法&#xff1a;插入下面代码 import os os.environ["GIT_PYTHON_REFRESH"] "quiet"2.页面太小无法完成操作 解决办法: 如果不好使再考虑降低Batch_Size大小或者调整虚拟内存可用硬盘空间大小&#xff01;&#xff08;调整虚拟内存…...

使用FabricJS创建Image对象的JSON表示

本篇文章介绍一下如何创建图像的 JSON 表示形式 使用 FabricJS 的对象。我们可以通过创建一个实例来创建一个 Image 对象 织物.图像。由于它是FabricJS的基本元素之一&#xff0c;我们也可以轻松地 通过应用角度、不透明度等属性来自定义它。为了创建 JSON Image 对象的表示&am…...

【牛客刷题】反转固定区间链表、每k个节点一组反转

链表内指定区间反转_牛客题霸_牛客网 ListNode* reverseList(ListNode* head, ListNode* tail) {ListNode* pre nullptr;ListNode* cur head;while (cur ! tail) { 最后cur就是tailListNode* temp cur->next;cur->next pre;pre cur;cur temp;}return pre;}ListNode…...

算法:数组常见套路1---双指针、取模、打擂台法

文章来源&#xff1a; https://blog.csdn.net/weixin_45630258/article/details/132738318 欢迎各位大佬指点、三连 一、数组的合并–双指针[快慢指针] 1、题目&#xff1a; 给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2&#xff0c;另有两个整数 m 和 n &#xff0…...

App 出海实践:Google Play 结算系统

作者&#xff1a;业志陈 现如今&#xff0c;App 出海热度不减&#xff0c;是很多公司和个人开发者选择的一个市场方向。App 为了实现盈利&#xff0c;除了接入广告这种最常见的变现方式外&#xff0c;就是通过提供各类虚拟商品或者是会员服务来吸引用户付费了&#xff0c;此时 …...

国际慈善日 | 追寻大爱无疆,拓世科技集团的公益之路

每年的9月5日&#xff0c;是联合国大会正式选定的国际慈善日。这一天的设立&#xff0c;旨在通过提高公众对慈善活动的意识&#xff0c;鼓励慈善公益活动通过各种形式在全球范围内得到增强和发展。这是一个向慈善公益事业致敬的日子&#xff0c;同时也是呼吁全球团结一致共同发…...

关于DNS的一些认识

目录 什么是DNS&#xff1f; 一台具有单个DNS的机器可以拥有多个地址吗&#xff1f; 一台计算机可以有多个属于不同顶级域的DNS名字吗&#xff1f; 什么是DNS&#xff1f; DNS是域名系统&#xff08;Domain Name System&#xff09;的缩写&#xff0c;它是互联网中用于将域名…...

游戏性能优化

Unity性能优化主要包括以下方面&#xff1a; 1.渲染性能 。包括减少Draw Calls、减少三角面数、使用LOD、使用批处理技术、减少实时光源等&#xff0c;以提高游戏的帧率和渲染效率。 2.内存性能 。包括使用对象池、使用合适的纹理、使用异步加载资源等&#xff0c;以减少内存占…...

公开游戏、基于有向图的游戏

目录 〇&#xff0c;背景 一&#xff0c;公开游戏、策梅洛定理 1&#xff0c;公开游戏 2&#xff0c;策梅洛定理 二&#xff0c;有向图游戏 1&#xff0c;狭义有向图游戏 2&#xff0c;广义有向图游戏 3&#xff0c;狭义有向图游戏的SG数 4&#xff0c;Bash Game 力扣…...

CSS学习笔记05

CSS笔记05 定位 position CSS 属性position - 用于指定一个元素在文档中的定位方式。top&#xff0c;right&#xff0c;bottom 和 left 属性则决定了该元素的最终位置。position 有以下常用的属性值&#xff1a; position: static; - 默认值。指定元素使用正常的布局行为&am…...

Linux查看指定端口是否被占用

在Linux中&#xff0c;可以使用多种方法来检查一个特定端口&#xff08;例如3306&#xff0c;通常由MySQL使用&#xff09;是否被占用&#xff1a; 使用netstat命令: 如果系统中已安装了netstat&#xff0c;可以使用以下命令检查3306端口&#xff1a; netstat -tuln | grep 330…...

【Python 自动化】小说推文一键生成思路概述

最近看了一下小说推文成品软件的思路&#xff0c;发现可以完全迁移到我的 BookerAutoVideo 上面来。这篇短文里面&#xff0c;我试着分析一下整个推文视频生成的流程&#xff0c;以及简要阐述一下有什么工具。 整体流程是这样&#xff1a; 分句 原文是按照段落组织的&#xf…...

ssm实战项目网站开发/爱站seo工具包

ASP.NET MVC设计实例前文我们介绍了MVC设计模式实现基本原理及组成&#xff0c;其基本组成主要包括控制器、视图、模板等部分。目前绝大多数Web端程序设计语言已经支持MVC设计模式&#xff0c;进行Web应用程序开发&#xff0c;本文主要以ASP.NET为例对MVC模式显示进行简单说明。…...

政务网站队伍建设情况汇报/小网站

Vue.js 一、Vue基础知识 Vue概述 目标&#xff1a;MVVM模式应用特点&#xff0c;Vue概念 小结&#xff1a; MVVM通过视图与模型的双向绑定&#xff0c;简化前端操作。Vue是一款前端渐进式框架&#xff0c;能提高前端开发效率。 搭建示例工程 目标&#xff1a;使用HBuild…...

专做商品折扣的网站/网络营销相关的岗位有哪些

使用场景&#xff1a;cell滑动删除&#xff1a;逻辑如下...

如何做网站讯息/引流获客app下载

之前和最近一个项目用到了Doctrine&#xff0c;由于是别人搭建的&#xff0c;自己没有很了解&#xff0c;最近又开始做的时候发现拙荆见肘&#xff0c;于是看了一下doctrine教程&#xff0c;本文就是加上自己理解的doctrine教程文档笔记了。Doctrine2 配置需求需要php5.3.3及以…...

网站页脚模板/个人网站推广方法

一个640x640的YUV420P图像占用的字节数为&#xff1a;640 x 640 x 3 / 2 2304000 字节。 YUV420P是一种视频编码格式&#xff0c;其中图像是分为三个通道&#xff1a;Y(亮度)、U(蓝色差)和V(红色差)。每个像素由一个Y值和两个UV值组成。因此&#xff0c;一个像素占用1个字节的…...

免费自己制作网站方法/辽源seo

先去下载https://dev.mysql.com/downloads/mysql/解压完是这个样子将这个文件放入到C盘并将文件名字改掉成MySQL配置初始化的my.ini文件的文件解压后的目录并没有的my.ini文件&#xff0c;没关系可以自行创建在安装根目录下添加的my.ini(新建文本文件&#xff0c;将文件类型改为…...