【C++】C++中的String类详解及模拟实现示例

news2024/11/27 1:27:31

文章目录

  • string类简介
    • string类的基本用法
    • string类的常用方法
    • string类的优势
  • string类的模拟实现
    • 存储结构
    • 头文件string.h
    • 源文件string.cpp
    • 源文件test.cpp

string类简介

string类简介在C++编程中,字符串是一种非常常见的数据类型,用于存储文本信息。C++标准库提供了string类来处理字符串,它提供了许多方法和功能,使得字符串操作更加方便和高效。

string类的基本用法

要使用C++中的string类,需要包含头文件。下面是一个简单的示例,演示了如何创建和操作string对象:

#include <iostream>
#include <string>

int main() {
    // 创建一个空的string对象
    std::string str;

    // 初始化string对象
    std::string greeting = "Hello, world!";

    // 获取字符串长度
    int len = greeting.length();

    // 字符串拼接
    std::string message = greeting + " Have a nice day!";

    // 输出字符串
    std::cout << message << std::endl;

    return 0;
}

string类的常用方法

string类提供了丰富的方法来操作字符串,包括查找子串、比较字符串、截取子串等功能。下面是一些常用的方法示例:

std::string str = "This is a C++ string";

// 查找子串
size_t found = str.find("C++");

// 比较字符串
if (str.compare("Another string") == 0) {
    std::cout << "Strings are equal" << std::endl;
}

// 截取子串
std::string sub = str.substr(8, 2);  // 从索引8开始,截取2个字符

string类的优势

与C风格字符串相比,C++的string类具有许多优势。它自动管理内存,避免了内存泄漏和越界访问的问题;提供了丰富的方法和操作符重载,使得字符串操作更加方便和直观;而且在C++11标准中,string类还支持移动语义,进一步提高了性能。

总的来说,C++中的string类是一个强大而灵活的工具,用于处理字符串数据。无论是简单的字符串拼接,还是复杂的字符串处理,string类都能够满足需求并提供高效的解决方案。

string类的模拟实现

除了对string类的简单使用外,为了更好的了解string类的实现原理,我们可以试着实现string类的部分功能,以便我们可以更加深入了string的原理,以便可以更好的使用它。

存储结构

string本质上是一个char类型的顺序表,实现起来与顺序表相似,所以结构上也相似。

using namespace std;
#include <iostream>
#include <assert.h>

// 将自定义字符串类封装在命名空间hd内
namespace hd {
    // 定义string类
    class string {
    public:
        // 成员常量
        const static size_t npos = -1; // 表示未找到的位置,它是无符号整型的最大值,
        //使用 const static 修饰符。
        //这种方式可以确保该常量在程序中只有一个实例,并且不会被修改。
    private:
        // 私有数据成员
        size_t _size = 0; // 字符串大小
        size_t _capacity = 0; // 字符串容量
        char* _str = nullptr; // 指向动态分配的数组
    };
}

头文件string.h

// string.h
#pragma once
#define _CRT_SECURE_NO_WARNINGS 1 // 禁用安全警告,与Visual Studio相关
using namespace std;
#include <iostream>
#include <assert.h>

// 将自定义字符串类封装在命名空间hd内
namespace hd {
    // 定义string类
    class string {
    public:
        // 构造函数、复制构造函数、赋值运算符和析构函数
        string(const char* str = ""); // 默认构造函数,可接受C风格字符串
        string(const string& s); // 复制构造函数
        string(const char* s, size_t n); // 从C风格字符串构造,并指定长度
        string& operator= (string s); // 赋值运算符,使用拷贝交换技术
        ~string(); // 析构函数,释放内存

        // 迭代器相关
        typedef char* iterator; // 迭代器类型定义
        typedef const char* const_iterator; // 常量迭代器类型定义
        iterator begin() const { return _str; } // 返回指向第一个字符的迭代器
        iterator end() const { return _str + _size; } // 返回指向最后一个字符之后的迭代器

        // 容量相关函数
        size_t size() const { return _size; } // 返回字符串的大小
        void resize(size_t n, char c = '\0'); // 改变字符串的大小,如果变大则填充c字符
        void reserve(size_t n = 0); // 预留空间,避免频繁分配内存
        void clear();// 清空字符串
        size_t capacity() const { return _capacity; } // 返回字符串对象的容量
        bool empty() const { return _size == 0; } // 判断字符串对象是否为空

        // 元素访问
        char& operator[] (size_t pos) { assert(pos <= _size); return _str[pos]; } // 下标运算符
        const char& operator[] (size_t pos) const { assert(pos <= _size); return _str[pos]; } // 下标运算符常量版本
        char& at(size_t pos) { assert(pos <= _size); return _str[pos]; } // 安全访问元素
        const char& at(size_t pos) const { assert(pos <= _size); return _str[pos]; } // 安全访问元素常量版本

        // 修改器
        string& operator+= (const string& s) { return append(s); } // 重载+=运算符,用于追加字符串
        string& operator+= (const char* str) { return append(str); } // 重载+=运算符,用于追加C风格字符串
        string& operator+= (char c) { return append(1, c); } // 重载+=运算符,用于追加字符
        string& append(const string& s); // 追加字符串
        string& append(const char* str); // 追加C风格字符串
        string& append(size_t n, char c); // 追加n个字符c
        string& append(const string& s, size_t subpos, size_t sublen); // 追加字符串的子串
        void push_back(char c); // 在字符串末尾添加一个字符
        string& insert(size_t pos, const string& str); // 在指定位置插入字符串
        string& insert(size_t pos, const char* s); // 在指定位置插入C风格字符串
        string& insert(size_t pos, size_t n, char c); // 在指定位置插入n个字符c
        string& erase(size_t pos = 0, size_t len = npos); // 删除从pos开始的len个字符
        void swap(string& s); // 交换两个字符串的内容
        void pop_back() { erase(_size-1, 1); } // 删除最后一个字符
        // 字符串操作
        const char* c_str() const { return _str; } // 返回C风格字符串
        size_t copy(char* s, size_t len, size_t pos = 0); // 复制字符串到s
        size_t find(const string& str, size_t pos = 0) const; // 查找子字符串
        size_t find(const char* s, size_t pos = 0) const; // 查找C风格子字符串
        size_t find(char c, size_t pos = 0) const; // 查找字符
        string substr(size_t pos = 0, size_t len = npos) const; // 返回子串

        // 成员常量
        const static size_t npos = -1; // 表示未找到的位置

    private:
        // 私有数据成员
        size_t _size = 0; // 字符串大小
        size_t _capacity = 0; // 字符串容量
        char* _str = nullptr; // 指向动态分配的数组

    };

    // 非成员函数重载
    istream& operator>> (istream& is, string& str); // 输入运算符重载
    ostream& operator<< (ostream& os, const string& str); // 输出运算符重载
    istream& getline(istream& is, string& str, char delim); // 从输入流读取一行
    istream& getline(istream& is, string& str); // 从输入流读取一行,直到换行符
}

源文件string.cpp

//string.cpp
#include "string.h"

namespace hd
{
    // 构造函数:根据传入的C风格字符串构造字符串对象
    string::string(const char* str)
    {
        _size = strlen(str);  // 计算字符串长度
        _capacity = _size;  // 初始容量为字符串长度
        _str = new char[_capacity + 1];  // 分配内存空间,+1是为了存放字符串结束符'\0'
        strcpy(_str, str);  // 将传入的字符串拷贝到_str中
    }

    // 拷贝构造函数:使用另一个字符串对象构造当前字符串对象
    string::string(const string& s)
    {
        string tmp(s.c_str());  // 利用传入的字符串对象构造临时字符串对象
        swap(tmp);  // 交换当前字符串对象和临时字符串对象的成员变量值
    }

    // 构造函数:根据传入的C风格字符串和长度构造字符串对象
    string::string(const char* s, size_t n) {
        string tmp(s);  // 利用传入的C风格字符串构造临时字符串对象
        tmp[n] = '\0';  // 限制临时字符串对象的长度为n
        tmp._size = n;  // 更新临时字符串对象的大小为n
        swap(tmp);  // 交换当前字符串对象和临时字符串对象的成员变量值
    }

    // 赋值运算符重载:将字符串对象s赋值给当前字符串对象
    string& string::operator=(string s)
    {
        swap(s);  // 交换当前字符串对象和s的成员变量值
        return *this;  // 返回当前字符串对象
    }

    // 析构函数:释放字符串对象所占用的内存空间
    string::~string()
    {
        delete[] _str;
        _str = nullptr;
        _size = 0;
        _capacity = 0;
    }

    // 修改字符串大小,使其包含n个字符,如果n小于当前大小,则截断字符串,如果n大于当前大小,则在末尾填充字符c
    void string::resize(size_t n, char c)
    {
        if (this->size() > n) {
            _str[n] = '\0';  // 截断字符串
            _size = n;
        }
        else {
            reserve(n);  // 扩容字符串,使其能够容纳n个字符
            append(n - this->size(), c);  // 在末尾填充字符c,直到达到长度n
        }
    }

    // 扩展字符串容量,以容纳至少n个字符
    void string::reserve(size_t n)
    {
        if (n > _capacity) {
            char* tmp = new char[n + 1];  // 分配新的内存空间,+1是为了存放字符串结束符'\0'
            strcpy(tmp, _str);  // 将原字符串拷贝到新的内存空间中
            delete[] _str;  // 释放原有内存空间
            _str = tmp;  // 更新字符串指针指向新的内存空间
            _capacity = n;  // 更新字符串容量
        }
    }

    // 在字符串末尾追加另一个字符串对象
    string& string::append(const string& s)
    {
        return append(s.c_str());
    }

    // 在字符串末尾追加C风格字符串
    string& string::append(const char* str)
    {
        size_t len = strlen(str);  // 计算要追加的字符串长度
        if (_size + len > _capacity) {  // 如果追加后的长度大于当前容量,则扩容
            reserve(_size + len);
        }
        strcpy(_str + _size, str);  // 将要追加的字符串拷贝到当前字符串的末尾
        _size += len;  // 更新字符串大小
        return *this;
    }

    // 在字符串末尾追加n个字符c
    string& string::append(size_t n, char c)
    {
        for (size_t i = 0; i < n; ++i) {
            this->push_back(c);
        }
        return *this;
    }

    // 在字符串末尾追加另一个字符串对象的子串,子串起始位置为subpos,长度为sublen
    string& string::append(const string& s, size_t subpos, size_t sublen)
    {
        size_t len = s.size();  // 获取字符串的大小
        if (_size + len > _capacity) {  // 如果追加后的长度大于当前容量,则扩容
            reserve(_size + len);
        }
        const char* cp_str = s.c_str() + subpos;  // 根据起始位置计算子串的指针
        strncpy(_str + _size, cp_str, sublen);  // 将子串拷贝到当前字符串的末尾
        _size += sublen;  // 更新字符串大小
        _str[_size] = '\0';  // 添加字符串结束符
        return *this;
    }

    // 在字符串末尾添加一个字符c
    void string::push_back(char c)
    {
        if (_size == _capacity) {  // 如果字符串已满,则进行扩容
            size_t newcapacity = _capacity == 0 ? 4 : _capacity * 2;
            reserve(newcapacity);
        }
        _str[_size] = c;  // 在末尾添加字符c
        ++_size;  // 更新字符串大小
        _str[_size] = '\0';  // 添加字符串结束符
    }

    // 在字符串的指定位置插入另一个字符串对象
    string& string::insert(size_t pos, const string& str)
    {
        assert(pos <= _size);  // 确保插入位置在合法范围内
        return this->insert(pos, str.c_str());
    }

    // 在字符串的指定位置插入C风格字符串
    string& string::insert(size_t pos, const char* s)
    {
        assert(pos <= _size);  // 确保插入位置在合法范围内
        size_t len = strlen(s);  // 计算要插入的字符串长度
        if (_size + len > _capacity) {  // 如果插入后的长度大于当前容量,则扩容
            reserve(_size + len);
        }
        memmove(_str + pos + len, _str + pos, _size - pos);  // 将插入位置及之后的字符后移
        memcpy(_str + pos, s, len);  // 将要插入的字符串拷贝到指定位置
        _size += len;  // 更新字符串大小
        _str[_size] = '\0';  // 添加字符串结束符
        return *this;
    }

    // 在字符串的指定位置插入n个字符c
    string& string::insert(size_t pos, size_t n, char c)
    {
        assert(pos <= _size);  // 确保插入位置在合法范围内
        string str;
        while (n--) {
            str += c;
        }
        return this->insert(pos, str);
    }

    // 删除字符串中从指定位置开始的指定长度的字符
    string& string::erase(size_t pos, size_t len)
    {
        if (len == npos || pos + len >= _size) {  // 如果要删除的长度超过了字符串的长度,则截断字符串
            _str[pos] = '\0';
            _size = pos;
            return *this;
        }
        else {
            strcpy(_str + pos, _str + pos + len);  // 将要删除的部分后面的字符前移
            _size -= len;  // 更新字符串大小
        }
        return *this;
    }

    // 交换两个字符串对象的成员变量值
    void string::swap(string& s)
    {
        std::swap(_str, s._str);
        std::swap(_size, s._size);
        std::swap(_capacity, s._capacity);
    }

    // 将指定长度的字符从字符串中复制到字符数组s中,返回实际复制的字符数
    size_t string::copy(char* s, size_t len, size_t pos) {
        assert(pos <= _size);  // 确保复制位置在合法范围内
        size_t actual_len = min(len, _size - pos);  // 计算实际要复制的字符数
        strncpy(s, _str + pos, actual_len);  // 将要复制的字符拷贝到数组中
        return actual_len;
    }

    // 查找字符串中指定子串的起始位置,从指定的位置pos开始查找
    size_t string::find(const string& str, size_t pos) const
    {
        assert(pos <= _size);  // 确保查找位置在合法范围内
        return find(str.c_str(), pos);
    }

    // 查找字符串中指定C风格子串的起始位置,从指定的位置pos开始查找
    size_t string::find(const char* s, size_t pos) const
    {
        assert(pos <= _size);  // 确保查找位置在合法范围内
        char* ptr = strstr(_str + pos, s);  // 在字符串中查找子串
        if (ptr == nullptr) {
            return npos;  // 如果找不到子串,则返回特殊值 npos,表示找不到
        }
        else {
            return ptr - _str;  // 如果找到子串,则返回子串在字符串中的起始位置
        }
    }

    // 返回字符串对象的子串,从指定位置pos开始,长度为len
    string string::substr(size_t pos, size_t len) const
    {
        assert(pos <= _size);  // 确保起始位置在合法范围内
        size_t actual_len = min(len, _size - pos);  // 计算实际要复制的字符数
        return string(_str + pos, actual_len);  // 返回从起始位置pos开始,长度为actual_len的子串
    }

    // 清空字符串对象,将大小和容量都重置为0
    void string::clear()
    {
        delete[] _str;  // 释放之前分配的内存空间
        _str = new char[1];  // 分配新的内存空间,大小为1,用于存放字符串结束符'\0'
        _str[0] = '\0';  // 设置字符串结束符
        _size = 0;  // 更新字符串大小
        _capacity = 0;  // 更新字符串容量
    }



    // 重载输出运算符,用于打印字符串对象
    std::ostream& operator<<(std::ostream& os, const string& str)
    {
        os << str.c_str();  // 输出字符串对象的C风格字符串
        return os;
    }
}

源文件test.cpp

//test.cpp
#include "string.h"

int main() {
    hd::string s1; // 默认构造函数
    cout << "s1: " << s1 << endl;

    hd::string s2("Hello"); // 构造函数,接受C风格字符串
    cout << "s2: " << s2 << endl;

    hd::string s3(s2); // 复制构造函数
    cout << "s3: " << s3 << endl;

    hd::string s4("World", 3); // 构造函数,接受C风格字符串和长度
    cout << "s4: " << s4 << endl;

    // 迭代器测试
    cout << "s2: ";
    for (auto it = s2.begin(); it != s2.end(); ++it) {
        cout << *it;
    }
    cout << endl;

    // 容量相关函数测试
    cout << "s2 size: " << s2.size() << endl;
    cout << "s2 capacity: " << s2.capacity() << endl;
    s2.resize(10, 'a');
    cout << "s2 after resize: " << s2 << endl;
    cout << "s2 capacity after resize: " << s2.capacity() << endl;
    s2.reserve(20);
    cout << "s2 capacity after reserve: " << s2.capacity() << endl;
    s2.clear();
    cout << "s2 size after clear: " << s2.size() << endl;
    cout << "s2 capacity after clear: " << s2.capacity() << endl;
    cout << "s2 is empty: " << (s2.empty() ? "true" : "false") << endl;

    // 元素访问测试
    cout << "s3[0]: " << s3[0] << endl;
    cout << "s3.at(1): " << s3.at(1) << endl;

    // 修改器测试
    s3 += " World"; // 追加字符串
    cout << "s3 after append: " << s3 << endl;

    s3.insert(5, " C++"); // 在指定位置插入字符串
    cout << "s3 after insert: " << s3 << endl;

    s3.erase(5, 4); // 删除指定位置的字符
    cout << "s3 after erase: " << s3 << endl;

    s3.pop_back(); // 删除最后一个字符
    cout << "s3 after pop_back: " << s3 << endl;

    // 字符串操作测试
    const char* cStr = s3.c_str();
    cout << "C-style string: " << cStr << endl;

    char buffer[10];
    size_t copiedLen = s3.copy(buffer, 5, 0); // 复制字符串到buffer
    buffer[copiedLen] = '\0';
    cout << "Copied string: " << buffer << endl;

    s3 += "World !";
    size_t pos = s3.find("World"); // 查找子字符串
    if (pos != hd::string::npos) {
        cout << "Position of 'World': " << pos << endl;
    }
    else {
        cout << "Position of 'World': " << -1 << endl;
    }

    hd::string subStr = s3.substr(6, 3); // 返回子串
    cout << "Substring: " << subStr << endl;

    return 0;
}

分别测试库中,和自己实现得出的结果:
这里的resize与reserve的不同,是因为在实现过程中的扩容策略的不同造成的。
在这里插入图片描述
通过全面介绍了C++中string类的基本用法、常用方法和优势,以及string类的模拟实现示例。通过详细的讲解和示例代码,可以深入了解如何在C++中使用string类进行字符串操作,并了解其相对于C风格字符串的优势所在。同时,通过展示一个简单的string类的模拟实现,还可以加深对string类内部原理的理解。

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

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

相关文章

鸿蒙应用开发(二)环境搭建

开发流程 IDE下载 首先下载HUAWEI DevEco Studio&#xff0c;介绍首次启动DevEco Studio的配置向导&#xff1a; 运行已安装的DevEco Studio&#xff0c;首次使用&#xff0c;请选择Do not import settings&#xff0c;单击OK。安装Node.js与ohpm。node.js 是基于 V8 引擎构…

〖大前端 - 基础入门三大核心之JS篇㊿〗- 面向对象之对象的方法、遍历、深浅克隆

说明&#xff1a;该文属于 大前端全栈架构白宝书专栏&#xff0c;目前阶段免费&#xff0c;如需要项目实战或者是体系化资源&#xff0c;文末名片加V&#xff01;作者&#xff1a;哈哥撩编程&#xff0c;十余年工作经验, 从事过全栈研发、产品经理等工作&#xff0c;目前在公司…

堆的基础功能实现和优先级队列

1. 堆的插入与删除 1.1 堆的插入 步骤&#xff1a; 1、先将元素放入到底层空间中(注意&#xff1a;一般是放到整个二叉树的最后一个叶子节点的后边&#xff0c;其次存储空间不够时需要扩容) 2、将最后新插入的节点向上调整&#xff0c;直到满足堆的性质&#xff08;判断该节点…

【金融数据分析】计算沪深300指数行业权重分布并用饼图展示

前言 前面的文章我们已经介绍了如何获取沪深300成分股所述行业以及权重的数据&#xff0c;想要了解这部分内容的小伙伴可以阅读上一篇文章 springbootjdbcTemplatesqlite编程示例——以沪深300成分股数据处理为例-CSDN博客 那么有了上文获取的数据&#xff0c;我们实际上可以…

List 接口

1 List 接口 java.util 中的集合类包含 Java 中某些最常用的类。最常用的集合类是 List 和 Map。 List是一种常用的集合类型&#xff0c;它可以存储任意类型的对象&#xff0c;也可以结合泛型来存储具体的类型对象&#xff0c;本质上就是一个容器。 1.1 List 类型介绍 有序性…

基于Solr的全文检索系统的实现与应用

文章目录 一、概念1、什么是Solr2、与Lucene的比较区别1&#xff09;Lucene2&#xff09;Solr 二、Solr的安装与配置1、Solr的下载2、Solr的文件夹结构3、运行环境4、Solr整合tomcat1&#xff09;Solr Home与SolrCore2&#xff09;整合步骤 5、Solr管理后台1&#xff09;Dashbo…

Redis 五大经典业务问题

一 缓存穿透 缓存穿透是指当请求的数据既不在缓存中也不存在于数据库中时&#xff0c;请求会直接穿透缓存层&#xff0c;到达数据库层。这通常是由于恶意攻击或者程序错误造成的&#xff0c;比如攻击者故意请求不存在的大量数据&#xff0c;导致缓存不命中&#xff0c;所有的请…

python zblog API实现类似XMLRPC/发布文章

我发现python对Zblog的XML发布并不友好&#xff0c;虽然也有对应的模块&#xff0c;但是远远没有XPCRPC更直接方便&#xff0c;但是使用xmlRpc是直接给发布文章带来了不小的便利&#xff0c;但是对系统也并不友好&#xff0c;但是zblog也开放了Api&#xff0c;但是干部子弟不乐…

【Spring教程20】Spring框架实战:AOP(面对切面编程)知识总结

欢迎大家回到《Java教程之Spring30天快速入门》&#xff0c;本教程所有示例均基于Maven实现&#xff0c;如果您对Maven还很陌生&#xff0c;请移步本人的博文《如何在windows11下安装Maven并配置以及 IDEA配置Maven环境》&#xff0c;本文的上一篇为《利用 AOP通知获取数据代码…

为 Compose MultiPlatform 添加 C/C++ 支持(3):实战 Desktop、Android、iOS 调用同一个 C/C++ 代码

theme: serene-rose 前言 在本系列的前两篇文章中我们已经学会了如何在 kotlin native 平台&#xff08;iOS&#xff09;使用 cinterop 调用 C/C 代码。以及在 jvm 平台&#xff08;Android、Desktop&#xff09;使用 jni 调用 C/C 代码&#xff0c;并且知道了如何自动编译 A…

Leetcode—389.找不同【简单】

2023每日刷题&#xff08;五十五&#xff09; Leetcode—389.找不同 实现代码 char findTheDifference(char* s, char* t) {int len strlen(s);int len2 len 1;int a[26] {0};int b[26] {0};if(len 0) {return t[0];}for(int i 0; i < len; i) {int idx s[i] - a;…

使用alpine镜像部署go应用时踩的坑

使用alpine镜像部署go应用时踩的坑 关于交叉编译 实际上我在ubuntu的交叉编译出来的exe并不能在alpine上运行&#xff0c;这边采取拉镜像编译复制出来的做法&#xff0c;部署再用干净的alpine 拉取golang:alpine踩坑 在Dockerhub上可以找到&#xff1a; 然而拉取的alpine中…

蓝桥杯-动态规划专题-子数组系列,双指针

目录 一、单词拆分 二、环绕字符串中唯一的子字符串 双指针-三数之和 ArrayList(Arrays.asList(array)) 四、四数之和&#xff08;思路和三数之和一样&#xff0c;只是多了一层循环&#xff09; 一、单词拆分 1.状态表示 dp[i]:到达i位置结尾&#xff0c;能否被dict拆分 …

JVM进程缓存

引言 缓存在日常开发中启动至关重要的作用&#xff0c;由于是存储在内存中&#xff0c;数据的读取速度是非常快的&#xff0c;能大量减少对数据库的访问&#xff0c;减少数据库的压力。我们把缓存分为两类&#xff1a; 分布式缓存&#xff0c;例如Redis&#xff1a; 优点&…

【MySQL】MySQL 在 Centos 7环境安装教程

文章目录 1.卸载不要的环境2.检查系统安装包3.获取mysql官方yum源4.安装mysql yum 源&#xff0c;对比前后yum源5.安装mysql服务6.查看配置文件和数据存储位置7.启动服务和查看启动服务8.登录9.配置my.cnf 1.卸载不要的环境 先检查是否有mariadb存在 ps ajx |grep mariadb如果…

虚拟机VMware安装centos以及配置网络

目录 1、CentOS7的下载2、CentOS7的配置3、CentOS7的安装4、CentOS7的网络配置 4.1、自动获取IP4.2、固定获取IP 5、XShell连接CentO 准备工作&#xff1a;提前下载和安装好VMware。VMware的安装可以参考这一篇文章&#xff1a;VMware15的下载及安装教程。 1、CentOS7的下载 …

sentinel整合nacos配置中心持久化

在网上找了很多的资料&#xff0c;发现sentinel整合nacos持久化的博文和视频大多数都只有改造限流部分的教程&#xff0c;并且都需要修改前端&#xff0c;略显麻烦&#xff0c;至于剩下的熔断、热点流控、授权的更是没有相关的改造教程&#xff0c;最后在知乎的看到一篇文章后让…

Sql server数据库数据查询

请查询学生信息表的所有记录。 答&#xff1a;查询所需的代码如下&#xff1a; USE 学生管理数据库 GO SELECT * FROM 学生信息表 执行结果如下&#xff1a; 查询学生的学号、姓名和性别。 答&#xff1a;查询所需的代码如下&#xff1a; USE 学生管理数据库 GO SELE…

文章解读与仿真程序复现思路——电力系统自动化EI\CSCD\北大核心《考虑移动式储能调度的配电网灾后多源协同孤岛运行策略》

这篇文章的标题表明研究的主题是在配电网发生灾害后&#xff0c;采用一种策略来实现多源协同孤岛运行&#xff0c;并在这个过程中特别考虑了移动式储能的调度。 让我们逐步解读标题的关键词&#xff1a; 考虑移动式储能调度&#xff1a; 文章关注的焦点之一是移动式储能系统的…

持续集成交付CICD:Jenkins流水线实现Nexus制品晋级策略

目录 一、理论 1.开发测试运维环境 二、实验 1.Nexus制品晋级策略 一、理论 1.开发测试运维环境 &#xff08;1&#xff09;环境 1&#xff09;持续集成开发环境&#xff08;DEV: Development Environment&#xff09; 直接通过源代码编译打包&#xff0c;其会跑单元测试…