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;	//3std::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;	//4std::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-beginstd::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++17size_t index = 0;while(index < std::size(a)){std::cout << a[index] << std::endl;index = index + 1;}//基于(c)begin/(c)endauto 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);//获取元素个数--3std::cout << x.size() <<std::endl;//判断元素是否为空,空返回1,不空返回0std::cout << x.empty() <<std::endl;//容量--3std::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;}//forfor (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;		//3std::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); // 改变字符串长度为10std::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 提供了范围检查的访问方式,避免了数组越界的问题

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

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

相关文章

【数据结构】数组循环队列的实现

队列&#xff08;Queue&#xff09;是一种特殊的线性数据结构&#xff0c;它遵循FIFO&#xff08;First In First Out&#xff0c;先入先出&#xff09;的原则。队列只允许在表的前端&#xff08;front&#xff09;进行删除操作&#xff0c;而在表的后端&#xff08;rear&#…

python下载及安装

1、python下载地址&#xff1a; Python Releases for Windows | Python.orgThe official home of the Python Programming Languagehttps://www.python.org/downloads/windows/ 2、python安装 &#xff08;1&#xff09; 直接点击下载后的可执行文件.exe &#xff08;2&…

Spring Boot项目怎么集成Gitee登录

一、背景 现在的越来越多的项目&#xff0c;需要集成第三方系统进行登录。今天我们以Spring Boot项目集成Gitee为例&#xff0c;演示一下怎么使用Oauth2协议&#xff0c;集成第三方系统登录。 不了解oauth2的&#xff0c;可以看我之前的文章。Ouath2是怎么实现在第三方应用认…

计算机毕业设计Python+Spark知识图谱课程推荐系统 课程预测系统 课程大数据 课程数据分析 课程大屏 mooc慕课推荐系统 大数据毕业设计

1 绪 论 1.1 课题研究背景 在线教育学习平台是学生用来进行校内或校外拓展课程学习的平台&#xff0c;平台需要具备在线视频观看&#xff0c;作业提交&#xff0c;形成性考核等功能。在学生学习的过程中&#xff0c;学校的管理者或负责教师需要了解学生的学习情况和学习状态&…

WWW服务器搭建(2)——Apache服务器配置与管理

一、Apache简介 1.1 关于Apache Apache HTTP Server&#xff08;简称Apache&#xff09;是Apache软件基金会的一个开放源码的Web服务器&#xff0c;可以在大多数计算机操作系统中运行&#xff0c;由于其跨平台和安全性被广泛使用&#xff0c;是最流行的Web服务器端软件之一。…

01-02-5

1、单链表中按位置查找 a.原理 通过传递的位置&#xff0c;返回该位置对应的地址&#xff0c;放到主函数定义的指针变量中。 我们认为位置从&#xff1a;有数据的节点开始计数 即如下结构&#xff1a; 查找位置&#xff0c;就是返回该位置对应的空间地址。 b.代码说明 Ⅰ…

H5嵌入原生----兼容安卓与ios

主要分UI展示&#xff0c;键盘&#xff0c;输入框等等。解决bug最苦恼的问题不是没有解决方案&#xff0c;而是你没有找到真正的原因。再就是现象难以重现&#xff0c;每次都要发布代码&#xff0c;然后到手机app中去测试&#xff0c;模拟。这些地方会耗费大量的精力。 一、UI…

【软设】常见易错题汇总

目录 计算机系统基础 程序语言基础 数据结构 算法设计与分析 计算机网络与信息安全 软件工程基础 开发方法&#xff08;结构化与面向对象&#xff09; 数据库 操作系统 知识产权相关的法律法规 &#x1f92f;&#x1f92f;&#x1f92f;&#x1f92f;&#x1f92f;&#x1f9…

《系统架构设计师教程(第2版)》第10章-软件架构的演化和维护-07-软件架构维护

文章目录 1. 软件架构知识管理1.1 概念1.2 架构知识的获取1.3 作用1.4 架构知识管理的现状 2 软件架构修改管理3 软件架构版本管理4. 示例4.1 背景4.2 数据获取4.3 数据计算4.4 结果分析4.4.1 圈复杂度 (CCN)4.4.2 扇入扇出度 (FFC)4.4.3 模块间耦合度 (CBO)4.4.4 模块的响应 (…

mysql group by 细节介绍

mysql中group by的用法是配合聚合函数&#xff0c;利用分组信息进行统计&#xff0c;语句如“select name,sum(id) from test group by name,number”。 先来看下表1&#xff0c;表名为test&#xff1a; 执行如下SQL语句&#xff1a; SELECT name FROM test GROUP BY name 你…

OFDM802.11a的FPGA实现(十四)data域的设计优化,挤掉axi协议传输中的气泡

原文链接&#xff08;相关文章合集&#xff09;&#xff1a;OFDM 802.11a的xilinx FPGA实现 目录 1.前言 2.data域的时序要求 3.Debug 1.前言 前面12篇文章详细讲述了&#xff0c;OFDM 802.11a发射部分data域的FPGA实现和验证&#xff0c;今天对data域的设计做一个总结。在…

springboot306基于Java的民宿管理系统(源码+包运行+配套LW+技术指导)

项目描述 临近学期结束&#xff0c;开始毕业设计制作&#xff0c;你还在做java程序网络编程&#xff0c;期末作业&#xff0c;老师的作业要求觉的困难吗?不知道毕业设计该怎么办?网页功能的数量是否太多?没有合适的类型或系统?等等。今天给大家介绍一篇基于Java的民宿管理…

CoSeg: Cognitively Inspired Unsupervised Generic Event Segmentation

名词解释 1.特征重建 特征重建是一种机器学习中常用的技术&#xff0c;通常用于自监督学习或无监督学习任务。在特征重建中&#xff0c;模型被要求将输入数据经过编码器&#xff08;encoder&#xff09;转换成某种表示&#xff0c;然后再经过解码器&#xff08;decoder&#x…

升级Microsoft 365后,SAP GUI中无法打开Excel的解决方案

最近&#xff0c;我们遇到了一个棘手的问题&#xff0c;一位客户在升级到Microsoft 365后&#xff0c;无法在SAP GUI中打开Excel。这个问题不仅影响了工作效率&#xff0c;也给用户的日常操作带来了不便。在本文中&#xff0c;我们将探讨问题的成因&#xff0c;并提供一种解决方…

泛微E9开发 添加多个多选框,实现单选框的效果

利用多个多选框实现单选框的效果 1、功能背景2、展示效果3、实现效果 1、功能背景 如下图所示&#xff0c;在表单中新增四个“选择框-复选框”类型的字段&#xff0c;并且设置其中的选项&#xff0c;每个多选框都只有一个选项&#xff0c;通过代码块实现单选框的效果 1.显示模…

邓闲小——生存、生活、生命|真北写作

人生有三个层次∶生存、生活、生命。 生存就是做必须做的事。生存的模式是邓&#xff0c;是交易&#xff0c;是买卖。别人需要的东西&#xff0c;你生产出来&#xff0c;卖给他。哪怕这个东西没啥用&#xff0c;也可以卖&#xff0c;情绪也可以卖。你需要的东西&#xff0c;你花…

分布式与一致性协议之POW算法

POW算法 概述 谈起比特币&#xff0c;你应该并不陌生。比特币是基于区块链实现的&#xff0c;而区块链运行在因特网上&#xff0c;这就存在有人试图作恶的情况。有些读者可能已经发现了&#xff0c;口信消息型拜占庭问题之解、PBFT算法虽然能防止坏人作恶&#xff0c;但只能防…

八、e2studio VS STM32CubeIDE之内存使用情况窗口

目录 一、概述/目的 二、STM32CubeIDE Build Analyzer 三、e2studio Memory Usage 八、e2studio VS STM32CubeIDE之内存使用情况窗口 一、概述/目的 1、嵌入开发最大特点之一就是资源受限&#xff0c;关注芯片资源使用详情是优秀工程师的技能之一 2、Keil和IAR都不支持内存…

CTFshow 信息搜集

第一题1 进入靶场 直接看源码发现flag 第二题 1 按右键没办法看源码 按ctrlu可以查看源码 第三题 0 查看源码 发现还是什么都没有 用bp抓包发现flag 第四题1 直接进robots.txt 访问flagishere.txt获得flag 第五题 0 提示了phps源码泄露 用目录扫描工具没扫出来 看wp 发现有…

网络编程套接字详解

目录 1. 预备介绍 2.网络字节序 3.udp网络程序 4.地址转换函数 5.udp网络编程 1.预备介绍 1.1源IP地址和目标IP地址 举个例子: 从北京出发到上海旅游, 那么源IP地址就是北京, 目标IP地址就是上海. 1.2 端口号 作用: 标识一个进程, 告诉OS这个数据交给那个进程来处理; (1)…