C++基础与深度解析 | 数组 | vector | string

文章目录

    • 一、数组
      • 1.一维数组
      • 2.多维数组
    • 二、vector
    • 三、string

一、数组

1.一维数组

  在C++中,数组用于存储具有相同类型和特定大小的元素集合。数组在内存中是连续存储的,并且支持通过索引快速访问元素。

数组的声明

  数组的声明指定了元素的类型和数组的长度。

// 声明一个整型数组,具有10个元素
int arr[10];

// 声明并初始化整型数组
int arr[] = {1, 2, 3, 4, 5};

注意:不要使用extern 指针来声明数组,应该extern int array[];即Unknown Bounded Array 声明

错误示例:

`file1.cpp`:
int array[3] = {1, 2, 3};

`file2.cpp`://正确写法
extern int array[];

`file2.cpp`://错误写法
extern int* array;

数组初始化

  数组的初始化可以是隐式的,也可以是显式的。

  • 缺省初始化

    在C++中,如果数组是非静态的局部数组,其元素将包含未定义的值,因为它们没有默认初始化。全局数组和静态数组将会被默认初始化为零。

    void function() {
        int localArray[10];  // 未定义的值
        static int staticArray[10];  // 初始化为0
    }
    
  • 聚合初始化( aggregate initialization )

    //使用大括号{}
    int arr[] = {1, 2, 3, 4, 5}; //根据初始化列表推导出int[5]
    

注意事项

  • 不能使用auto来声明数组类型

    auto b = {1,2,3};	//b推导出的类型为std::initializer_list<int>
    
    int c[3] = {1,2,3};
    auto d = c;		//d推导出的类型为int*,类型退化了
    
  • C++中,数组(内置数组)不能直接复制。因为它们没有像类或结构体那样的拷贝构造函数或赋值运算符

    • 赋值操作:对于数组,你不能使用简单的赋值操作(=)来复制数组。例如,以下代码是错误的:

      int arr1[10] = {1, 2, 3};
      int arr2[10];
      arr2 = arr1; // 错误:数组之间不能使用赋值操作符
      
    • 拷贝构造函数:传统数组没有拷贝构造函数,这意味着你不能通过构造函数来创建一个数组的深拷贝

    尽管传统数组不能直接通过赋值或拷贝构造函数来复制,你仍然可以通过其他方法来复制数组的内容。

    • 手动复制:使用循环手动逐个复制数组的每个元素

    • std::copy:使用C++标准库中的 <algorithm> 头文件提供的 std::copy 函数

    • 拷贝构造函数(对于数组类型的对象):如果你有一个包含数组的类或结构体,你可以定义一个拷贝构造函数来复制数组。

      struct MyStruct {
          int arr[10];
          MyStruct(const MyStruct& other) {
              std::copy(other.arr, other.arr + 10, arr);
          }
      };
      
    • C++11标准库容器:如 std::arraystd::vector 提供了拷贝构造函数和赋值运算符来复制其内容。

      std::array<int, 10> arr1 = {{1, 2, 3}};
      std::array<int, 10> arr2 = arr1; // 使用std::array的拷贝构造函数
          
      std::vector<int> vec1 = {1, 2, 3};
      std::vector<int> vec2 = vec1; // 使用std::vector的拷贝构造函数
      
  • 元素个数必须是常量表达式(编译期可计算的值)

  • 字符串数组的特殊性

    char str[] = "Hello";	//char[6]
    char str[] = {'H', 'e', 'l', 'l', 'o'}; //char[5]
    char str[] = {'H', 'e', 'l', 'l', 'o', '\0'}; //char[6]
    

    使用字符串字面量初始化字符数组

    char str[] = "Hello"; // char[6]
    

    在这行代码中,"Hello" 是一个字符串字面量,它包含了字符串 "Hello" 以及一个隐式的空字符 \0,用作字符串的终止符。因此,当你使用这个字符串字面量来初始化字符数组 str 时,数组的大小是6个字符,包括5个可见字符和一个空字符。

    使用字符字面量初始化字符数组

    char str[] = {'H', 'e', 'l', 'l', 'o'}; // char[5]
    

    在这个例子中,使用花括号 {} 包围的字符字面量列表来初始化字符数组 str。这种方式不会自动添加空字符 \0,因此初始化后的数组 str 将包含5个字符,即 'H', 'e', 'l', 'l', 和 'o'。数组的实际大小是5个字符。

    注意事项

    • 当使用字符串字面量初始化字符数组时,编译器会自动在末尾添加一个空字符 \0,所以数组需要有足够的空间来存储这个额外的字符。
    • 当使用字符字面量列表初始化字符数组时,需要确保数组有足够的空间来存储所有字符,且不会自动添加空字符 \0。如果你需要一个以空字符终止的字符串,必须手动添加 \0
    • 字符串字面量和字符字面量列表在初始化字符数组时的行为不同,这可能会影响程序中字符串的处理和字符串函数的使用。

数组(数组到指针的隐式转换)

  数组名在大多数表达式中会被解释为指向数组首元素的指针。使用数组对象时,通常情况下会产生数组到指针的隐式转换,隐式转换会丢失一部分类型信息,可以通过声明引用来避免隐式转换

int arr[10];
int* ptr = arr;  // ptr是指向数组首元素的指针,数组到指针的隐式转换

auto& b = arr;	//声明引用来避免隐式转换

由于数组名可以作为指针使用,所以可以进行指针运算。

#include <iostream>

int main()
{
    int arr[10];
    for (int* ptr = arr; ptr < arr + 10; ++ptr)  {
        // 操作数组元素
        *ptr = *ptr + 1;	//1
    }
}

指针数组与数组指针

  • 指针数组

    指针数组是一个包含多个指针的数组,每个指针可以指向不同的对象。

    语法:指针数组在声明时,指针符号 * 放在数组名的前面。

    int* arr[3];
    
  • 数组指针

    数组指针是指向数组的指针。这种指针指向整个数组,而不是数组中的单个元素。

    语法:数组指针在声明时,指针符号 * 放在数组类型后面,使用括号括起来

    // 创建一个整型数组
    int arr[] = {10, 20, 30};
    
    // 创建一个指向数组的指针
    int (*ptrToArr)[3] = &arr;
    

    ptrToArr 是一个指向数组的指针,它指向一个包含3个 int 的数组。ptrToArr 不是一个指向 int 的指针,而是指向整个数组。

注意

  • 当传递数组作为函数参数时,实际上传递的是指向数组首元素的指针,而不是整个数组。
  • 数组的生命周期和存储空间必须在数组指针使用期间保持有效。
  • 指针数组和数组指针在内存布局和访问方式上有所不同,需要根据具体需求选择合适的类型。

声明数组的引用:(C++中没有引用数组的概念)

  声明数组的引用意味着创建一个引用,它指向整个数组。数组引用在函数参数传递、大型数据结构的传递等方面非常有用,因为它们允许函数直接操作传入的数组,而不是数组的副本。

int (&arr)[5] = data; // 假设 'data' 是一个已定义的数组

数组作为函数参数时,由于数组不能直接拷贝,通常会退化为指针。为了避免这种情况,可以使用数组引用作为函数参数

void printArray(int (&arr)[5]) {
    for (int i = 0; i < 5; ++i) {
        std::cout << arr[i] << " ";
    }
    std::cout << std::endl;
}

int data[5] = {1, 2, 3, 4, 5};
printArray(data);

printArray 函数接受一个数组的引用作为参数。这意味着函数可以直接访问和修改数组 data 中的元素。如果想限制数组中的元素不能修改,则void printArray(const int (&arr)[5])

注意

  • 数组引用必须在声明时被初始化。
  • 数组引用的大小(数组的长度)必须是已知的,因此它们不能指向未指定大小的数组。
  • 数组引用通常用于函数参数,以便安全地传递数组并避免数组退化为指针

数组的元素访问

  • 数组对象是一个左值(如果作为右值使用,类型会发生隐式转换:int[3] --> int*

    C++中左值与右值

    在C++中,表达式可以根据它们是否可以取得内存地址被分为两类:l-value(左值)和r-value(右值)。

    • l-value:l-value是指具有内存地址的表达式,这个内存地址可以被读取和写入。l-value通常用在赋值表达式的左边

      l-value的例子:

      • 变量:int a;
      • 数组元素:int arr[10]; arr[0];
      • 函数参数:当函数参数是一个引用类型时,它是一个l-value。
      • 位域:当位域是一个对象成员时。
    • r-value:r-value是指那些没有内存地址或者有临时内存地址的表达式,它们不能被赋值,因为它们的存在时间很短暂。r-value通常用在赋值表达式的右边,比如字面量、临时对象、表达式的结果等。

      以下是一些r-value的例子:

      • 字面量:10
      • 表达式:a + b
      • 函数返回值:除非函数返回一个引用,否则返回的是一个r-value。
      int b = 20; // b是一个l-value
      int c = a + b; // a + b是一个r-value
      
  • 数组访问

    使用时数组名通常会转换成相应的指针类型(指向数组首元素的指针),本质上:arr[index] = *(arr + index),实际上是利用指针运算来访问数组元素

    int arr[5] = {1, 2, 3, 4, 5};
    int firstElement = arr[0];  // 获取第一个元素,值为1
    int thirdElement = arr[2]; // 获取第三个元素,值为3
    
  • 范围检查

    C++不提供自动的数组范围检查,所以访问数组元素时应该确保索引不会超出数组的界限。

    int arr[5];
    for (int i = 0; i < 5; ++i) {
        // 安全的访问 arr[i]
    }
    
  • 越界访问

    如果尝试访问超出数组实际大小的索引,将导致未定义行为,这可能引发程序错误,如数组越界错误、野指针引用等

获得指向数组开头与结尾的指针 :

int a[3] = {1,2,3};

获得指向数组开头的指针:a     &(a[0])  std::begin(a)  std::cbegin(a)
获得指向数组结尾的下一个元素的指针:a+3   &(a[3])  std::end(a)    std::cend(a)

std::begin(a)与std::end(a)获得的类型为int*
std::cbegin(a)与std::cend(a)获得的类型为const int*

指针算术运算

  • 增加、减少

    指向数组下一位置元素的指针

  • 比较

    如果参数比较运算的指针是指向一个数组中的两个位置 ,是可以进行比较运算的;如果指向的是不同数组,不建议这样做,可能产生未定义的行为

  • 求距离

    #include <iostream>
    
    int main()
    {
        int a[3] = {1, 2, 3};
        auto ptr = a;
        auto ptr2 = a +3;
        std::cout << ptr2 - ptr << std::endl;	//3
        std::cout << ptr - ptr2 << std::endl;	//-3
    }
    
  • 解引用

  • 指针索引

    指针索引使用方括号 [] 来指定偏移量,从而访问指针指向的内存位置之后的某个位置。

数组的其他操作

  • 求元素个数

    以下三种方法都是对数组进行操作(获取数组的定义),而不是指针

    • sizeof方法: C语言方式,有危险,不推荐
    • std::size方法(C++17及以后):推荐的方式
    • std::end() - std::begin()方法:在运行期进行指针运算,但其实数组信息在编译器就可以看到,增加了运行期负担,不推荐
    #include <iostream>
    
    int main()
    {
        int a[3];
        
        std::cout << sizeof(int) << std::endl;	//4
        std::cout << sizeof(a) << std::endl;	//12
        //sizeof()方法求元素个数
        std::cout << sizeof(a)/sizeof(int) << std::endl; //3
    
        //std::size()   C++17
        // std::cout << std::size(a) << std::endl;
        //end-begin
        std::cout << std::end(a) - std::begin(a) << std::endl;    //3
    }
    
  • 元素遍历

    • 基于元素个数
    • 基于©begin/©end
    • 基于range-based for循环:语法糖
    #include <iostream>
    
    int main()
    {
        int a[3] = {2, 3, 5};
        
        //基于元素个数--C++17
        size_t index = 0;
        while(index < std::size(a))
        {
            std::cout << a[index] << std::endl;
            index = index + 1;
        }
        
        //基于(c)begin/(c)end
        auto ptr = std::cbegin(a);
        while(ptr != std::cend(a))
        {
            std::cout << *ptr << std::endl;
            ptr = ptr + 1;
        }
        
        //基于`range-based ` for循环
        for (int x : a)
        {
            std::cout << x << std::endl;
        }
    }
    

数组–C字符串

  • C 字符串本质上是字符数组
  • C 语言提供了额外的函数来支持 C 字符串相关的操作 : strlen, strcmp…,这些操作都需要’\0’,知道C字符串到哪里结束
    • strlen():统计长度直到找到’\0’

2.多维数组

  多维数组本质上是数组的数组。其内存布局仍是连续存储。

int x[3][4];  //x是一个数组,包含3个元素,x的每个元素是一个int[4]数组。
x[0];	//类型是int(&)[4]

声明多维数组

  多维数组的声明涉及指定每个维度的大小。在C++中,通常使用方括号来声明多维数组。

// 声明一个3x3的二维整型数组
int multiArray[3][3];

// 声明一个5x10的二维整型数组
int anotherArray[5][10];

初始化多维数组

  初始化时,每个维度的元素应该用花括号 {} 包围,维度之间的元素应该用逗号 , 分隔。

  • 缺省初始化

  • 聚合初始化

    一层大括号与多层大括号

//其余元素默认初始化为0
int x2[3][4] = {1, 2, 3, 4, 5, 6};

//其余元素默认初始化为0
int x3[3][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}};

//其余元素默认初始化为0
int x3[3][4] = {{1, 2, 3, 4}, {5, 6, 7}};

// 初始化一个3x3的二维数组
int multiArray[3][3] = {
    {1, 2, 3},
    {4, 5, 6},
    {7, 8, 9}
};


// 使用缺省初始化
int defaultArray[3][3] = {};

多维数组只能省略最高位的维度如:int x[][3],但是不建议这么干

多维数组索引与遍历

  • 使用多个中括号来索引,访问多维数组元素

    int value = multiArray[1][2]; // 获取第二行第三列的元素,值为6
    
  • 使用多重循环来遍历多维数组

    #include <iostream>
    
    int main()
    {
        int multiArray[3][3] = {
            {1, 2, 3},
            {4, 5, 6},
            {7, 8, 9}
        };
    
        //基于`range-based` for循环
        for (auto& p : multiArray)   //auto& 非常重要
        {
            for (auto q : p)
            {        
                std::cout << q << std::endl;
            }
        }
    }
    

    下面分析for (auto& p : multiArray)for (auto p : multiArray)的区别

    image-20240505002541618

    image-20240505002635403

指针与多维数组

  在C++中,多维数组的数组名可以被看作一个指向数组首元素的指针。可以使用指针运算来操作多维数组。

int arr[2][3] = {{1, 2, 3}, {4, 5, 6}};
int (*ptrToRow)[3] = arr; // ptrToRow是一个指向具有3个整数的数组的指针

// 访问第一行的第二个元素
int value = (*ptrToRow)[1]; // 等于 arr[0][1],值为2
  • 多维数组可以隐式转换为指针,但只有最高维会进行转换,其它维度的信息会被保留。

    image-20240505003740863

  • 使用类型别名来简化多维数组指针的声明

    #include <iostream>
    
    using A = int[4];
    int main()
    {
        int x[3][4];
        A* ptr = x;
    }
    
  • 使用指针来遍历多维数组

    #include <iostream>
    
    
    int main()
    {
        int x2[3][4] = {};
        auto ptr = std::begin(x2);
        while(ptr != std::end(x2))
        {
            auto ptr2 = std::begin(*ptr);
            while(ptr2 != std::end(*ptr))
            {
                ptr2 = ptr2 + 1;
            }
            ptr = ptr + 1;
        }
    }
     
    

二、vector

  C++标准库中的 std::vector 是一个序列容器,是 C++ 标准库中定义的一个类模板。与内建数组相比,std::vector 提供了更多的功能,例如自动调整大小、范围检查和一些有用的成员函数(更侧重易用性)。std::vector 可复制、可在运行期动态改变元素个数(内建数组不可以)。

构造与初始化

  • 缺省初始化

  • 聚合初始化

  • 其他初始化方式–构造函数

    std::vector<T,Allocator>::vector,根据参数调用不同的构造函数

std::vector<int> vec; // 默认构造
std::vector<int> vec(10, 1); // 10个整数初始化为1
std::vector<int> vec = {1, 2, 3}; // 列表初始化

其他方法

  • 获取元素个数、判断元素是否为空、容量

    #include <iostream>
    #include <vector>
    
    int main()
    {
        std::vector<int> x(3, 1);
        //获取元素个数--3
        std::cout << x.size() <<std::endl;
        //判断元素是否为空,空返回1,不空返回0
        std::cout << x.empty() <<std::endl;
        //容量--3
        std::cout << x.capacity() <<std::endl;
    
    }
    
  • 插入元素

    vec.push_back(4); // 在末尾添加一个元素
    vec.push_back({5, 6, 7}); // 从初始列表添加多个元素
    
  • 删除元素

    vec.pop_back(); // 删除最后一个元素
    vec.erase(vec.begin() + 1); // 删除第二个元素
    
  • vector比较

    逐个比较两个vector的元素,如果元素相同,则比较下一个元素;如果第一个元素不同,则由第一个元素的大小决定;

  • 清空

    vec.clear(); // 删除所有元素,保留容量
    
  • 修改容器大小

    vec.resize(5); // 改变vec的大小为5,如果缩小则可能删除元素
    vec.resize(7, 1); // 如果需要,用1填充额外的空间以改变大小为7
    
  • 元素操作

    vec.front(); // 返回第一个元素
    vec.back(); // 返回最后一个元素
    

vector 中元素的索引与遍历

  • []at实现vector 中元素的索引

    std::vector<int> vec(10, 1); // 10个整数初始化为1
    int firstElement = vec[0]; // 获取第一个元素
    vec[1] = 20; // 设置第二个元素的值
    
    //at方法
    vec.at(2) = 30;
    
  • ©begin / ©end 函数 V.S. ©begin / ©end 方法

    #include <iostream>
    #include <vector>
    
    
    int main()
    {
        std::vector<int> x1 = {1, 2, 3};
        //begin、end函数
        auto p = std::begin(x1);
        while(p != std::end(x1))
        {
            std::cout << *p << std::endl;
            p = p + 1;
        }
    
        //begin、end方法
        auto q = x1.begin();    //返回指向第一个元素的迭代器,迭代器解引用也可以获取元素的值
        while(q != x1.end())
        {
            std::cout << *q << std::endl;
            q = q + 1;
        }
    
        //for
        for (auto x : x1)
        {
            std::cout << x << std::endl;
        }
    }
    

    vector中©begin / ©end 方法返回的是随机访问迭代器

    迭代器

    • 模拟指针行为

    • 包含多种类别,每种类别支持的操作不同

    • vector 对应随机访问迭代器

      • 解引用与下标访问

      • 移动

      • 两个迭代器相减求距离

      • 两个迭代器比较

        这两个迭代器必须指向相同的vector

vector相关的其他内容

  • 添加元素可能使迭代器失效

    image-20240505131607321

  • 多维 vector

    如:std::vector<std::vector<int>>

  • .-> 操作符

    #include <iostream>
    #include <vector>
    
    
    int main()
    {
        std::vector<int>  x = {1, 2, 3};
        std::vector<int>* ptr = &x;
    
        std::cout << x.size() << std::endl;		//3
        std::cout << ptr->size() << std::endl;  //3
    }
    
  • vector 内部定义的类型

    • size_type

      image-20240505132432117

    • iterator / const_iterator

      image-20240505132511431

注意事项

  • std::vector 会根据需要自动调整大小,但可能会引起性能开销,因为它可能需要重新分配内存和复制元素。
  • 访问 std::vector 中的元素时,要注意范围检查,避免越界访问。
  • 与原始数组相比,std::vector 更安全且易于使用,但可能会占用更多的内存,并且访问速度可能稍慢。

三、string

  std::string 是标准库中的一个类模板实例化,它提供了一个可变长度的字符序列,用于内建字符串的代替品。与内建字符串相比,更侧重于易用性。string可复制、可在运行期动态改变字符个数

TypeDefinition
std::stringstd::basic_string

参考:std::basic_string

构造与初始化

#include <string>

std::string str; // 默认构造,创建一个空字符串
std::string str("Hello, World!"); // 直接初始化
std::string str(10, 'A'); // 初始化为10个字符'A'

string其他方法

  • 访问元素

    char ch = str[0]; // 获取第一个字符,与C风格字符串不同,这是安全的
    
  • 添加和修改字符串

    str += "追加的字符串"; // 追加字符串
    str.append("追加的字符串"); // 另一种追加方式
    str.insert(1, "插入的字符串"); // 在指定位置插入字符串
    str.replace(1, 2, "新字符串"); // 替换部分字符串
    str.erase(1, 4); // 删除从索引1开始的4个字符
    str.back() = '!'; // 修改最后一个字符
    
  • 尺寸相关方法(size/length)

    #include <iostream>
    #include <vector>
    
    
    int main()
    {
        std::string str= "Hello World!";
    
        size_t size = str.size();
        size_t len = str.length(); // 获取字符串长度
    
        std::cout << size << std::endl;
        std::cout << len << std::endl;
        str.resize(10); // 改变字符串长度为10
        std::cout << str.size() << std::endl;
        std::cout << str.length() << std::endl;
    }
    
  • 查找和比较

    size_t pos = str.find("sub"); // 查找子串"sub"的位置
    bool isEqual = str.compare("anotherString"); // 比较字符串
    
  • 子字符串

    std::string sub = str.substr(1, 4); // 获取从索引1开始的4个字符的子字符串
    
  • 清空

    str.clear(); // 删除所有字符,保留容量
    
  • 交换

    str.swap(anotherStr); // 交换两个字符串的内容
    
  • 转换为C字符串,返回一个指向’\0’结束字符数组的指针

    const char* cstr = str.c_str(); // 获取C风格的字符数组
    

注意事项

  • std::string 是一个类模板的实例化,所以它不是像原始数组那样的低级类型。
  • 字符串字面量(如 "Hello")是 const char 类型的数组,它们在C++中被定义为 const,因此不能被修改。
  • 当需要C风格的字符串时,可以使用 c_str() 成员函数来获取,但要注意,这个操作可能涉及内存分配,因此不应该频繁调用。
  • std::string 提供了范围检查的访问方式,避免了数组越界的问题

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【基础技能】Windows常用快捷键

最近做知识管理&#xff0c;梳理了下个人技能&#xff0c;存在好多基础技能都是一知半解&#xff0c;用的时候都是现搜现查&#xff0c;没有形成一个完整的知识体系&#xff0c;导致一些基础不牢靠&#xff0c;需要再次筑基&#xff01; 于是就翻阅了微软的官网&#xff0c;撸…

5.13网络编程

只要在一个电脑中的两个进程之间可以通过网络进行通信那么拥有公网ip的两个计算机的通信是一样的。但是一个局域网中的两台电脑上的虚拟机是不能进行通信的&#xff0c;因为这两个虚拟机在电脑中又有各自的局域网所以通信很难实现。 socket套接字是一种用于网络间进行通信的方…

Linux进程间几种通信机制

一. 简介 经过前一篇文章的学习&#xff0c; 我们知道Linux下有两种标准&#xff1a;system V标准和 Posix标准。 System V 和 POSIX 标准是操作系统提供的接口标准&#xff0c;它们规定了操作系统应该如何实现一些基本功能&#xff0c;比如线程、进程间通信、文件处理等。 …

【APM】在Kubernetes中搭建OpenTelemetry+Loki+Tempo+Grafana链路追踪(一)

文章目录 1、最终效果2、前提准备2、环境信息3、服务集成&#xff08;Opentelemetry ->Tempo&#xff09;3.1 上报链路数据3.1.1 下载opentelemetry-agent3.1.2 启动配置业务app3.1.3 配置opentelemetry输入输出3.1.4 配置grafana datasource3.1.4.1 配置tempo3.1.4.2 配置l…

基于RK3568的鸿蒙通行一体机方案项目

鸿蒙通行一体机方案以鸿蒙版AIoT-3568X人工智能主板为核心平台&#xff0c;搭载OpenHarmony操作系统&#xff0c;使用自研算法和国产芯片&#xff0c;可管可控&#xff0c;并提供身份识别以及其他外设配件生态链支持。 01 项目概述 项目使用场景 鸿蒙版通行一体机方案凭借自主…

【云计算小知识】云管理的作用是什么?

云计算已经成为推动企业数字化转型&#xff0c;提升运营效率的重要力量。而在这个过程中&#xff0c;云管理作为确保云计算环境稳定、高效运行的关键环节&#xff0c;其作用愈发凸显。今天我们小编就给大家详细介绍一下云管理的作用是什么&#xff1f; 云管理的作用是什么&…

探索渲染农场的高性能奥秘

在当今数字化的时代&#xff0c;渲染农场正逐渐成为许多行业不可或缺的强大工具。那么&#xff0c;为什么我们说渲染农场是高性能的计算机系统呢&#xff1f;让我们深入剖析其中关键要点。 “渲染农场”拥有大规模的计算资源。它由众多高性能的计算机节点组成&#xff0c;这些…

Maven、JavaWeb基础开发

1 Maven介绍 1、标准化的项目结构 2、标准化的构建流程 3、依赖管理 4、依赖范围 2 JavaWeb基础开发 2.1 Http协议 1 Http请求数据格式 2 Http响应数据格式 2.2 Web服务器&#xff08;Tomcat&#xff09; VTS、FileServer使用Tomcat部署&#xff1b; 其他服务单元TESLA S…

vue3.0(七) 计算属性(computed)

文章目录 1 计算属性&#xff08;computed &#xff09;1.1 computed使用1.2 computed使用场景1.4 computed的注意点1.4 computed的原理1.5 computed的示例 computed 和 Methods 的区别 1 计算属性&#xff08;computed &#xff09; 在 Vue 3 中&#xff0c;computed 是一个用…

【AI大模型】自动生成红队攻击提示--GPTFUZZER

本篇参考论文为&#xff1a; Yu J, Lin X, Xing X. Gptfuzzer: Red teaming large language models with auto-generated jailbreak prompts[J]. arXiv preprint arXiv:2309.10253, 2023. https://arxiv.org/pdf/2309.10253 一 背景 虽然LLM在今天的各个领域得到了广泛的运用…

Nginx安全扫描借助lua-nginx-module模块增加授权

一、问题描述 某次安全扫描通过Dirsearch工具发现&#xff0c;nginx代理访问某后端业务时&#xff0c;发现&#xff1a;Springboot未授权漏洞&#xff0c;存在信息泄露风险&#xff0c;危险等级&#xff1a;中危&#xff1b; 相关资源&#xff1a;openresty官网、/lua-nginx-m…

结构体补充-位段

文章目录 位段介绍位段内存分配位段的使用注意事项结束 位段介绍 为什么会有位段呢? 我们直到一个int是4个字节表示32个bit位,但是比如2,3这样的整数,我们只需要2个bit位就可以了,那30个比特位不就是浪费掉了吗,所以位段就产生了 位段通过结构体来实现&#xff0c;位段表示方法…

Hive表数据优化

Hive表数据优化 1.文件格式 为Hive表中的数据选择一个合适的文件格式&#xff0c;对提高查询性能的提高是十分有益的。 &#xff08;1&#xff09;Text File 文本文件是Hive默认使用的文件格式&#xff0c;文本文件中的一行内容&#xff0c;就对应Hive表中的一行记录。 可…

C++之Eigen库基本使用(下)

1、常见变换 Eigen::Matrix3d //旋转矩阵&#xff08;3*3&#xff09; Eigen::AngleAxisd //旋转向量&#xff08;3*1&#xff09; Eigen::Vector3d //欧拉角&#xff08;3*1&#xff09; Eigen::Quaterniond //四元数&#xff08;4*1&#xff09; Eigen::Isom…

K8s:二进制安装k8s(单台master)

目录 一、安装k8s 1、拓扑图 2、系统初始化配置 2.1关闭防火墙selinx以及swap 2.2设置主机名 2.3在每台主机中添加hosts&#xff0c;做映射 2.4调整内核参数&#xff0c;将桥接的ipv4流量传递到iptables&#xff0c;关闭ipv6 2.4时间同步 3、部署docker引擎&#xff0…

【Kali Linux工具篇】wpscan的基本介绍与使用

介绍 WPScan是Kali Linux默认自带的一款漏洞扫描工具&#xff0c;它采用Ruby编写&#xff0c;能够扫描WordPress网站中的多种安全漏洞&#xff0c;其中包括主题漏洞、插件漏洞和WordPress本身的漏洞。最新版本WPScan的数据库中包含超过18000种插件漏洞和2600种主题漏洞&#x…

力扣【旋转函数】python

如果直接用暴力的话&#xff0c;只能过4个样例好像&#xff0c;超时 因此得用递推公式 F1F0前n-1个数-(n-1)*第n个数 F0sum(nums)-n*第n个数 nlen(nums) ans[]#定义一个存最大值值的列表 ss sum(nums) dm 0 for j in range(n):dm j * nums[j] ans.append(dm) print(dm) n…

MinIO学习笔记

MINIO干什么用的&#xff1a; AI数据基础设施的对象存储 为人工智能系统提供数据支持&#xff0c;数据存储&#xff1b;对象存储&#xff08;Object Storage&#xff09;是一种数据存储架构&#xff0c;它以对象为单位来处理、存储和检索数据&#xff0c;每个对象都包含了数据本…

GitHub和huggingface镜像网站

GitHub镜像网站 gitclone 如果网络原因打不开GitHub的话&#xff0c;可以用这个网站进行克隆项目&#xff0c;将克隆代码修改一下 git clone https://github.com/comfyanonymous/ComfyUI.git 修改 git clone https://gitclone.com/github.com/comfyanonymous/ComfyUI.git 这个…

JSON在线解析及格式化验证 - JSON.cn网站

JSON在线解析及格式化验证 - JSON.cn https://www.json.cn/