C++ 基础:指针和引用浅谈

news2024/11/8 0:50:43

指针

基本概念

C++中,指针是存储其他变量的内存地址的变量。

我们在程序中声明的每个变量在内存中都有一个关联的位置,我们称之为变量的内存地址。
如果我们的程序中有一个变量 var,那么&var 返回它的内存地址。

int main()
{

   int var1 = 3;
   int var2 = 90;
   int var3 = 520;

   cout<<"Address of var1: "<<&var1<<endl;
   cout<<"Address of var2: " <<&var2<<endl;
   cout<<"Address of var3: "<<&var3 <<endl;

   
   return 0;
}

image-20240625094624250

  • 开头的0x代表十六进制形式的地址。
  • 注意,第一个地址与第二个地址相差 4 个字节,第二个地址与第三个地址相差 4 个字节。
  • 区别是因为在64位系统中int的大小是4个字节
  • 运行该程序时,您可能不会得到相同的结果。这是因为地址取决于程序运行的环境。

如何定义指针:

int* pointer;

以下是我们如何为指针分配地址:

int var = 5;
int* ptr = &var;

在这里,变量 var 被赋值为 5。然后,通过代码 ptr = &var,将变量 var 的地址分配给 ptr指针。

声明指针之后立即对其进行赋值操作是一个不错的编码习惯;

  • 通过指针获取值

需要获取指针指向的变量地址中的值,可以使用*来进行;

int main()
{

   int var1 = 5;
   int* ptr = &var1;

   cout<<"Address of var1: "<<&var1<<endl;
   cout<<"ptr value: "<< *ptr<<endl;


   return 0;

}

我们使用 *point_var 来获取存储在该地址中的值。当将 * 与指针一起使用时,称之为解引用运算符。它作用于指针并给出指针中存储的地址指向的值。也就是说,*point_var = var

再看一个例子,强化对指针和解引用概念的理解:

#include <iostream>
using namespace std;
int main() {
    int var = 5;

    // store address of var
    int* point_var = &var;

    // print value of var
    cout << "var = " << var << endl;

    // print address of var
    cout << "Address of var (&var) = " << &var << endl
         << endl;

    // print pointer point_var
    cout << "point_var = " << point_var << endl;

    // print the content of the address point_var points to
    cout << "Content of the address pointed to by point_var (*point_var) = " << *point_var << endl;
    
    return 0;
}

Working of C++ Pointers


  • 改变指针指向的值

如果point_var指向var的地址,我们可以使用*point_var来改变var的值。

int main()
{

   int var1 = 3;
   int* ptr = &var1;

   *ptr = 1;
   cout<<"Address of var1: "<<&var1<<endl;
   cout<<"ptr value: "<< *ptr<<endl;


   return 0;

}

这里,point_var&var具有相同的地址;当*point_var改变时,var 的值也会改变。

  • 使用指针时候的常见错误用法:
int var = 5;

// Wrong! 
// point_var is an address but var is not
int* point_var = var;

// Wrong!
// &var is an address
// *point_var is the value stored in &var
*point_var = &var;

// Correct! 
// point_var is an address and so is &var
point_var = &var;

 // Correct!
// both *point_var and var are values
*point_var = var;

指针和数组

C++ 中,指针是保存其他变量地址的变量。指针不仅可以存储单个变量的地址,还可以存储数组单元的地址。

int *ptr;
int arr[5];

// store the address of the first
// element of arr in ptr
ptr = arr;
  • 这里,ptr是一个指针变量,而arr是一个int数组。
  • 代码ptr = arr; 将数组的第一个元素的地址存储在变量ptr中。
  • 注意,我们使用的是arr而不是&arr[0]。这是因为它们是相同的。因此,下面的代码与上面的代码相同。
int *ptr;
int arr[5];
ptr = &arr[0];

其余数组元素的地址由 &arr[1]、&arr[2]、&arr[3] &arr[4] 给出。


  • 使用指针获取指定元素

假设我们需要使用相同的指针 ptr 指向数组的第四个元素。
这里,如果 ptr 指向上例中的第一个元素,那么 ptr + 3 将指向第四个元素地址。例如:

int *ptr;
int arr[5];
ptr = arr;

ptr + 1 is equivalent to &arr[1];
ptr + 2 is equivalent to &arr[2];
ptr + 3 is equivalent to &arr[3];
ptr + 4 is equivalent to &arr[4];

类似地,我们可以使用单个指针访问元素。例如:

*ptr == arr[0];
*(ptr + 1) is equivalent to arr[1];
*(ptr + 2) is equivalent to arr[2];
*(ptr + 3) is equivalent to arr[3];
*(ptr + 4) is equivalent to arr[4];

假设我们已经初始化了 ptr = &arr[2];

ptr - 2 is equivalent to &arr[0];
ptr - 1 is equivalent to &arr[1]; 
ptr + 1 is equivalent to &arr[3];
ptr + 2 is equivalent to &arr[4];

Working of C++ Pointers with Arrays

int main()
{

   float arr[3];

   float *ptr;

   for(int i=0;i<3;i++)
   {
      cout<<"&arr["<<i<<"]=" <<&arr[i] <<endl;
   }

   ptr = arr;

   cout<<endl;

   for(int i=0;i<3;i++)
   {
      cout <<"ptr + " << i <<"  = " << ptr+i<<endl;
   }

   return 0;

}

在上面的程序中,我们分别使用普通方式和指针的方式打印了数组元素的地址信息;

在大多数情况下,数组名称会退化为指针。简单来说,数组名称被转换为指针。这就是为什么我们可以使用指针来访问数组元素的原因。但是,我们应该记住,指针和数组并不相同。在某些情况下,数组名称不会衰减为指针。具体情况可以查阅:https://stackoverflow.com/questions/17752978/exceptions-to-array-decaying-into-a-pointer

// C++ Program to insert and display data entered by using pointer notation.

#include <iostream>
using namespace std;

int main() {
    float arr[5];
    
   // Insert data using pointer notation
    cout << "Enter 5 numbers: ";
    for (int i = 0; i < 5; ++i) {

        // store input number in arr[i]
        cin >> *(arr + i) ;

    }

    // Display data using pointer notation
    cout << "Displaying data: " << endl;
    for (int i = 0; i < 5; ++i) {

        // display value of arr[i]
        cout << *(arr + i) << endl ;

    }

    return 0;
}

其中的cin >> *(arr + i) ;等同于cin >> arr[i];;

请注意,我们没有声明单独的指针变量,而是使用数组名称 arr 作为指针表示法。
我们已经知道,数组名 arr 指向数组的第一个元素。因此,我们可以将 arr 视为一个指针。


引用

基本概念

我们使用&符号来创建引用。例如:

string& ref_city = city;
#include <iostream>

using namespace std;

int main() {

    string city = "Paris";

    // create a reference to the variable
    string& ref_city = city;
    
    // display the variable
    cout << "Variable Value: " << city << endl;
    cout << "Reference Value: " << ref_city << endl;

    return 0;
}

上面的代码中我们使用引用变量 ref_city 来显示变量 city 的值。


  • 通过引用修改变量

我们可以通过简单地为引用变量分配一个新值来修改变量。

int main()
{
   string city = "Shanghai";

   string& ref_city = city;

   ref_city = "Hk";
   cout <<"var:" << city <<endl;
   cout<<"ref: "<< ref_city<<endl;

   return 0;

}

我们可以在创建引用时将 & 符号与数据类型或变量一起放置。但是,标准做法是将符号与数据类型一起使用。例如:

// create a variable
string city = "Paris";

// valid but not a standard practice
string &ref_city = city;

// valid and a standard practice
sring& ref_city = city;

一旦我们创建了对变量的引用,就无法将其更改为引用另一个变量。例如:

int main() {

    string city1 = "Paris";

    // create a reference to the variable
    string& ref_city = city1;
    
    // display the variable
    cout << "city1 = " << city1 << endl;
    cout << "ref_city = " << ref_city << endl;
    
    string city2 = "New York";
    
    // trying to modify the ref_city reference variable to refer to city2
    // but it assigns the value of city2 to the variable city1
    ref_city = city2;

    // display the variables
    cout << endl << "city1 = " << city1 << endl;
    cout << "city2 = " << city2 << endl;
    cout << "ref_city = " << ref_city << endl;

    return 0;
}

注意,虽然这里最后引用ref_city输出的是新的值New York,但他指向的始终还是开始的那个city1,只是引用的值变为了新的New York

引用传递

在 C++ 函数教程中,我们学习了如何将参数传递给函数。使用的这种方法称为按值传递,因为传递的是实际值。
但是,还有另一种传递参数的方法,称为引用传递
引用传递是一种在函数中传递参数的方法,其中将实际参数的引用而不是它们的值传递给函数。

// function that takes value as parameter

void func1(int num_val) {
    // code
}

// function that takes reference as parameter
// notice the & before the parameter
void func2(int& num_ref) {
    // code
}

int main() {
    int num = 5;

    // pass by value
    func1(num);

    // pass by reference
    func2(num);

    return 0;
}

注意 void func2(int& num_ref) 中的 &。这表示我们使用变量的引用作为参数。
因此,当我们通过传递变量 num 作为参数来调用 main() 中的func2()函数时,我们实际上传递的是 num 变量的引用而不是值 5

void swap(int &n1,int &n2)
    {
        int temp;
        temp = n1;
        n1 = n2;
        n2 = temp;
    }
int main() {

    int a {1},b {2};
    cout<<"Before swaping" << endl;
    cout<<"a = "<< a <<endl;
    cout<<"b = "<< b << endl;

    swap(a,b);

    cout<<"\nAfter swaping" << endl;
    cout<<"a = "<< a <<endl;
    cout<<"b = "<< b << endl;

    return 0;
}

在这个程序中,我们将变量 a 和 b 传递给 swap() 函数。请注意函数的定义、其中的参数我们使用的是引用类型;

因此,编译器可以识别出传递给函数参数的不是实际值,而是变量的引用。
swap() 函数中,函数参数 n1 n2 分别指向与变量 a b 相同的值。因此,交换是在实际值上进行的。


常量引用

当变量的值不需要更改时,我们可以将它们作为常量引用传递。
我们来看一个例子:

#include <iostream>
using namespace std;

// function to add two numbers 
// using const references
int add(const int& num1, const int& num2) {
    return num1 + num2;
}

int main() {
    int number1, number2;

    // take input
    cout << "Enter the first number: ";
    cin >> number1;

    cout << "Enter the second number: ";
    cin >> number2;

    // call add function
    int sum = add(number1, number2);

    // displaying the result
    cout << "The sum of " << number1 << " and " << number2 << " is " << sum << endl;

    return 0;
}

在这里,我们使用 const 关键字通过 const 引用传递值。
使用 const 引用可防止函数内的值发生更改。例如,让我们尝试使用 const 引用来交换两个数字。

#include <iostream>
using namespace std;

// function definition to swap values
// using const references
void swap(const int& n1,const int& n2) {
    int temp;
    temp = n1;
    n1 = n2;
    n2 = temp;
}

int main() {

    // initialize variables
    int a = 1, b = 2;

    cout << "Before swapping" << endl;
    cout << "a = " << a << endl;
    cout << "b = " << b << endl;

    // call function to swap numbers
    swap(a, b);

    cout << "\nAfter swapping" << endl;
    cout << "a = " << a << endl;
    cout << "b = " << b << endl;

    return 0;
}

这个程序运行是会报错的,因为对于参数,我们使用了const进行修饰

image-20240625172322268

对于这个交换函数,我们使用指针传递参数也是可以实现的,但是不建议使用这种方式:

#include <iostream>
using namespace std;

// function prototype with pointers as parameters
void swap(int*, int*);

int main() {

    // initialize variables
    int a = 1, b = 2;

    cout << "Before swapping" << endl;
    cout << "a = " << a << endl;
    cout << "b = " << b << endl;

    // call function by passing variable addresses
    swap(&a, &b);

    cout << "\nAfter swapping" << endl;
    cout << "a = " << a << endl;
    cout << "b = " << b << endl;
    return 0;
}

// function definition to swap numbers
void swap(int* n1, int* n2) {
    int temp;
    temp = *n1;
    *n1 = *n2;
    *n2 = temp;
}
  • *n1*n2 分别给出存储在地址 n1 和 n2 处的值。*
  • 由于n1n2包含a和b的地址,因此对*n1*n2进行任何操作都会改变ab的实际值。因此,当我们在 main() 函数中打印 a b 的值时,这些值会发生变化,也就完成了交换;

使用引用而不是指针通常更容易且不易出错,因为它不涉及直接的指针操作。
指针只能用于在特别需要指针的上下文中或与 C 库交互时传递参数。


内存管理

  • C++ 允许我们在运行时动态分配内存。这就是所谓的动态内存分配。
  • 在 Java 和 Python 等其他编程语言中,编译器会自动管理分配给变量的内存。但 C++ 并非如此。
  • 在 C++ 中,当我们不再使用变量时,需要手动取消分配动态分配的内存。
  • 我们可以使用 new 和 delete 操作符分别动态分配和取消分配内存。

new关键字

我们可以使用新表达式在运行时分配内存。例如

int* point_var;
point_var = new int;
*point_var = 45;

在这里,我们使用 new 表达式为一个 int 变量动态分配了内存。
请注意,我们使用了指针 point_var 来动态分配内存。这是因为 new 表达式返回的是内存位置的地址。
我们还可以在相同的步骤中分配内存并初始化值:

int* point_var = new int{45};

使用此语法可以避免未初始化的指针。取消引用时,未初始化的指针可能会导致未定义的行为。所以这是首选语法。
使用新表达式的语法是:

data_type* pointer_variable = new data_type{value};

delete关键字

一旦我们不再需要使用动态声明的变量,就可以取消分配该变量占用的内存。
为此,我们可以使用delete关键字。它将内存归还给操作系统。这就是所谓的内存去分配。
删除表达式的语法如下:

int* point_var = new int{45};

// print the value stored in memory
cout << *point_var; 

// deallocate the memory
delete point_var;

// set pointer to nullptr
point_var = nullptr;

在这里,我们使用指针 point_var 为一个 int 变量动态分配了内存。
打印完 point_var 的内容后,我们使用 delete 删除了内存。
一个好的做法是,在取消分配内存后将指针设置为 nullptr,以避免在指针被取消引用时出现未定义的行为。

不正确地删除内存会造成内存泄漏,进而导致程序消耗大量内存。正确使用删除表达式对于防止内存泄漏和确保高效内存管理至关重要。

下面再看两个例子,加深理解:

  • ex1
#include <iostream>
using namespace std;

int main() {

    // dynamically allocate memory
    int* point_int = new int{45};
    float* point_float = new float{45.45f};

    cout << *point_int << endl;
    cout << *point_float << endl;

    // deallocate the memory
    // set pointers to nullptr
    delete point_int;

    delete point_float;
    
    return 0;
}

在这个程序中,我们为两个 int 和 float 类型的变量动态分配了内存。在为它们赋值并打印后,我们最后使用删除表达式去分配内存。

动态内存分配可以提高内存管理的效率,尤其是对于数组而言,很多时候我们可能要到运行时才能知道数组的大小。

  • ex2
#include <iostream>
using namespace std;

int main() {

    int num;
    cout << "Enter total number of students: ";
    cin >> num;
    float* ptr;
    
    // memory allocation of num number of floats
    ptr = new float[num];
    
    cout << "Enter GPA of students." << endl;
    for (int i = 0; i < num; ++i) {
    cout << "Student" << i + 1 << ": ";
    cin >> *(ptr + i);
    }
    
    cout << "\nDisplaying GPA of students." << endl;
    for (int i = 0; i < num; ++i) {
    cout << "Student" << i + 1 << ": " << *(ptr + i) << endl;
    }
    
    // ptr memory is released
    delete[] ptr;
    ptr = nullptr;
    
    return 0;
}

在这个程序中,我们要求用户输入学生人数,并将其存储在 num 变量中。然后,我们使用 new 为浮点数组动态分配了内存。
我们使用指针符号将数据输入数组(随后打印数据)。在不再需要数组后,我们使用代码去分配数组内存:

注意删除后的[]。我们使用方括号 [] 来表示内存的删除是删除一个数组。

  • ex3
#include <iostream>
using namespace std;

class Student {
    private:
    int age;
    
    public:
    
    // constructor initializes age to 12
    Student() : age(12) {}
    
    void get_age() {
      cout << "Age = " << age << endl;
    }
};

int main() {

    // dynamically declare student object
    Student* ptr = new Student();
    
    // call get_age() function
    ptr->get_age();
    
    // ptr memory is released
    delete ptr;
    
    return 0;
}

在这个程序中,我们创建了一个 Student 类,该类有一个私有变量 age
我们在默认构造函数 Student() 中将 age 初始化为 12,并使用函数 get_age() 打印了它的值。
main() 中,我们使用 new 表达式创建了一个 Student 对象,并使用指针 ptr 指向其地址。
对象创建后,Student() 构造函数将年龄初始化为 12 岁。


为什么要使用动态内存分配?

动态内存分配有几个优点,例如:

  • 灵活性: 动态内存分配允许我们在运行时根据需要分配内存。当编译时不知道数据结构的大小,或在程序执行过程中数据结构的大小发生变化时,这种灵活性就非常有用。
  • 数据结构: 数据结构(如链表、树、图和可调整大小的数组(C++ 中的向量))通常需要动态分配内存,以容纳不同数量的数据。
  • 资源管理: 我们可以在需要时分配内存,并在不再需要时取消分配。这样可以提高资源利用率。
  • 动态数组: 在 C++ 等语言中,静态数组的大小是在编译时确定的。动态内存分配允许我们创建数组,其大小可在运行时确定。

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

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

相关文章

Stable Diffusion 3 正式开源,超强文生图模型 SD3-M 上线,赶紧来试试吧!

前言 我们都知道 Stable Diffusion 3 是一款强大的文生图模型&#xff0c;拥有20亿参数&#xff0c;因其高效的推理速度和卓越的生成效果而备受瞩目。 近日&#xff0c;Stability AI在推特上宣布正式开源了 Stable Diffusion 3 Medium&#xff08;SD3-M&#xff09; 权重&…

住宅IP代理服务终极指南:增强安全性和可访问性

在当今的数字安装程序中&#xff0c;隐私和可访问性对于企业和个人都至关重要。满足这些需求的一个强大工具是住宅 IP 代理服务。这些服务为用户提供住宅 IP 地址&#xff0c;这些地址是互联网产品 (ISP) 计算房主的真实 IP。在本综合指南中&#xff0c;我们将探讨住宅 IP 代理…

Chrome插件:​Vue.js Devtools 高效地开发和调试

在现代前端开发中&#xff0c;Vue.js因其灵活性和性能优势&#xff0c;受到越来越多开发者的青睐。然而&#xff0c;随着项目规模的扩大&#xff0c;调试和优化变得愈发复杂。幸运的是&#xff0c;Vue.js Devtools的出现&#xff0c;为开发者提供了一套强大的工具集&#xff0c…

【道合顺展会预告】2024国际传感器仪器仪表物联网长沙展览会!

传感器技术作为万物互联的基石&#xff0c;正以前所未有的速度驱动着全球各行各业的转型升级。在此背景下&#xff0c;2024国际传感器&仪器仪表&物联网展览会将于6月28日至30日在长沙盛大启幕&#xff0c;道合顺传感将携公司最新技术及科研成果参加展览会&#xff0c;并…

运维.Linux下执行定时任务(上:Cron简介与用法解析)

运维专题 Linux下执行定时任务&#xff08;上&#xff1a;Cron简介与用法解析&#xff09; - 文章信息 - Author: 李俊才 (jcLee95) Visit me at CSDN: https://jclee95.blog.csdn.netMy WebSite&#xff1a;http://thispage.tech/Email: 291148484163.com. Shenzhen ChinaAd…

Hadoop3:MapReduce中的Reduce Join和Map Join

一、概念说明 学过MySQL的都知道&#xff0c;join和left join 这里的join含义和MySQL的join含义一样 就是对两张表的数据&#xff0c;进行关联查询 Hadoop的MapReduce阶段&#xff0c;分为2个阶段 一个Map&#xff0c;一个Reduce 那么&#xff0c;join逻辑&#xff0c;就可以…

Vlog视频如何剪辑 Vlog视频剪辑逻辑 视频剪辑制作教程

剪出感觉、剪出情绪&#xff0c;给Vlog视频注入高级氛围感。不用购买昂贵的前期设备&#xff0c;正确地剪辑思维搭配一款好用的视频剪辑软件&#xff0c;你也能剪出令人惊艳的Vlog作品。请收藏本文并反复练习&#xff0c;相信在不久的将来&#xff0c;您的作品必会让人眼前一亮…

宣告 adsb.exposed - 基于 ClickHouse 的 ADS-B 航班数据交互式可视化和分析

本文字数&#xff1a;10340&#xff1b;估计阅读时间&#xff1a;26 分钟 审校&#xff1a;庄晓东&#xff08;魏庄&#xff09; 本文在公众号【ClickHouseInc】首发 Meetup活动 ClickHouse 上海首届 Meetup 讲师招募中&#xff0c;欢迎讲师在文末扫码报名&#xff01; 也许你已…

开发RpcProvider的网络服务

首先更改src的CMakeLists.txt的内容为&#xff1a; #当前目录的所有源文件放入SRC_LIST aux_source_directory(. SRC_LIST)#生成SHARED动态库 #add_library(mprpc SHARED ${SRC_LIST})#由于muduo是静态库&#xff0c;为了使用muduo&#xff0c;将mprpc也生成为静态库 add_libr…

【Docker】镜像

目录 1. 镜像拉取 2. 镜像查询 3. 镜像导出 4. 镜像上传 5. 镜像打标签 6. 镜像上推 7. 镜像删除 8. 镜像运行及修改 8.1 在registry 节点运行 mariadb 镜像&#xff0c;将宿主机 13306 端口作为容器3306 端口映射 8.2 查看容器ID 8.3 进入容器 8.4 创建数据库xd_d…

第三方软件测评中心▏软件系统测试详情介绍

软件系统测试是指对软件系统的功能、性能、安全等方面进行全面测试和评估的过程。在软件开发生命周期的不同阶段&#xff0c;通过各种测试手段和工具&#xff0c;对软件系统进行验证和确认&#xff0c;以确保软件系统的质量和可靠性。 软件系统测试的内容包括以下几个方面&…

基于4G工业路由器的连锁品牌店铺组网监测

基于4G工业路由器的连锁品牌店铺组网监测是智慧城市建设中至关重要的任务&#xff0c;它涉及到营运管理等多方面&#xff0c;应用物联网技术可确保店铺运营的高效、安全和可靠。 连锁品牌店铺遍布城市各领域&#xff0c;甚至跨城市部署&#xff0c;分布广泛。这对集团总部的管…

用定时器T1中断控制两个LED以不同周期闪烁

#include<reg51.h> // 包含51单片机寄存器定义的头文件 sbit D1P2^0; //将D1位定义为P2.0引脚 sbit D2P2^1; //将D2位定义为P2.1引脚 unsigned char Countor1; //设置全局变量&#xff0c;储存定时器T1中断次数 unsigned char Countor2; //设置全局变量&#xff0c;储…

Python中的并发编程(5)PyQt 多线程

PyQt 多线程 1 卡住的计时器 我们定义了一个计时器&#xff0c;每秒钟更新一次显示的数字。此外我们定义了一个耗时5秒的任务oh_no&#xff0c;和按钮“危险”绑定。 当我们点击“危险”按钮时&#xff0c;程序去执行oh_no&#xff0c;导致显示停止更新了。 import sys im…

AI早班车2024.6.25

全球AI新闻速递 1.高通&#xff1a;开放 AI 模型&#xff0c;帮助开发者打造骁龙 X Elite 平台智能应用。 2.OpenAI&#xff1a;收购数据库分析公司Rockset。 3.大众海外版车型支持 ChatGPT。 4.乐聚夸父人形机器人&#xff0c;搭载华为云盘古具身智能大模型。 5.微软正努力…

【吊打面试官系列-Mysql面试题】你可以用什么来确保表格里的字段只接受特定范围里的值?

大家好&#xff0c;我是锋哥。今天分享关于 【你可以用什么来确保表格里的字段只接受特定范围里的值?】面试题&#xff0c;希望对大家有帮助&#xff1b; 你可以用什么来确保表格里的字段只接受特定范围里的值? 答&#xff1a;Check 限制&#xff0c;它在数据库表格里被定义&…

策略模式-通过枚举newInstance替代工厂

策略模式-使用枚举newInstance 前言一、枚举类&#xff1a;MarkCheckDataTypeEnum二、抽象类&#xff1a;AbstractMarkChecker三、检查类&#xff1a;MarkPeopleChecker四、demo演示总结 前言 很久没写文章了~~ 吐槽下&#xff1a;入职新公司后&#xff0c;基本在搬砖&#xf…

好的精益管理咨询公司是什么样

在竞争激烈的商业环境中&#xff0c;企业的成功不仅取决于其产品或服务的质量&#xff0c;更在于其内部管理的精细化和高效性。精益管理作为一种追求最大价值、消除浪费的管理哲学&#xff0c;已经越来越受到企业的重视。那么&#xff0c;一家好的精益管理咨询公司究竟是什么样…

【SQL Server点滴积累】Setup SQL Server 2008 Database Mirror (二)

【SQL Server点滴积累】Setup SQL Server 2008 Database Mirror (一)-CSDN博客今天分享SQL Server 2008 R2搭建数据库镜像(Database Mirror)https://blog.csdn.net/ncutyb123/article/details/139749117?spm1001.2014.3001.5501本篇Blog基于以上Blog步骤进行SQL Server 2008 R…

excel表格加密:电脑文件加密的5个方法介绍【新手篇】

为了防止数据泄露&#xff0c;编辑好表格文件后一般都会加上密码。敏感数据的泄露会导致严重的商业损失和声誉损害。Excel表格加密方法有很多&#xff0c;包括金舟文件夹加密大师、金舟ZIP解压缩、工作簿密码设置等方法。 下面分享5个excel表格加密方法&#xff0c;希望能够帮到…