北京大学c++程序设计听课笔记101
基本概念
程序运行期间,每个函数都会占用一段连续的内存空间。而函数名就是该函数所占内存区域的起始地址(也称“入口地址”)。我们可以将函数的入口地址赋给一个指针变量,使该指针变量指向该函数。然后通过指针变量就可以调用这个函数。这种指向函数的指针变量称为“函数指针”。
### 预习:有趣的故事引入
在一个风和日丽的早晨,你走进了计算机科学课的教室,发现桌上放着一张神秘的地图,上面画满了各种指针和箭头。你的任务是解开这张地图的秘密,揭示指针在C++编程中的奥秘。你准备好了吗?让我们开始这场探险吧!
### 问题拆解与引导
#### 问题1:什么是指针,为什么在C++中重要?
**推导思路:**
- **定义理解**:首先,理解指针(Pointer)是什么——它是一个变量,用于存储另一个变量的内存地址。
- **重要性分析**:讨论指针在内存管理、数组操作、函数参数传递等方面的重要性。
**解答与例子:**
- 指针允许直接操作内存,提高程序的灵活性和效率。
- 例如,在函数中传递大数据结构时,可以通过指针避免不必要的复制,提高性能。
```cpp
#include <iostream>
void increment(int* ptr) {
(*ptr)++;
}
int main() {
int num = 10;
increment(&num);
std::cout << "Incremented num: " << num << std::endl; // 输出11
}
```
在这个例子中,通过指针传递变量地址,实现对原始数据的修改。
### 1. 这是什么语言?
这段代码是用C++编写的。
### 2. 逐行语法结构和函数用法说明
```cpp
#include <iostream>
```
- **语法结构**:这是一个预处理指令,用于包含标准输入输出流库。
- **先修知识**:了解C++标准库的作用和使用`#include`指令。
```cpp
void increment(int* ptr) {
(*ptr)++;
}
```
- **语法结构**:
- `void`:函数返回类型,表示该函数不返回任何值。
- `increment`:函数名。
- `(int* ptr)`:函数参数,`int*`表示参数是一个指向整数的指针。
- `{}`:函数体,包含需要执行的代码。
- `(*ptr)++`:解引用指针`ptr`获取其指向的整数值,然后自增。
- **先修知识**:了解指针的概念和使用方法,解引用操作符`*`,以及自增操作符`++`。
```cpp
int main() {
```
- **语法结构**:
- `int`:函数返回类型,表示返回一个整数。
- `main`:主函数名,是程序的入口点。
- `()`:表示函数没有参数。
- **先修知识**:了解C++程序的执行入口是`main`函数。
```cpp
int num = 10;
```
- **语法结构**:
- `int`:整数类型。
- `num`:变量名。
- `=`:赋值操作符。
- `10`:整数值。
- **先修知识**:变量声明和初始化。
```cpp
increment(&num);
```
- **语法结构**:
- `increment`:函数调用。
- `&num`:取地址操作符,获取变量`num`的内存地址。
- **先修知识**:函数调用和取地址操作。
```cpp
std::cout << "Incremented num: " << num << std::endl;
```
- **语法结构**:
- `std::cout`:标准输出流对象,用于输出数据到控制台。
- `<<`:插入操作符,将数据插入输出流。
- `"Incremented num: "`:字符串常量。
- `num`:变量输出。
- `std::endl`:流操纵符,用于输出换行符并刷新缓冲区。
- **先修知识**:输入输出流操作。
### 3. 分类举例说明这个代码用来做什么?
- **应用场景**:这段代码展示了如何通过指针参数修改函数外部变量的值。
- **举例说明**:
- **数据处理**:在复杂算法中,需要通过函数修改数组或对象的值时,可以使用指针传递。
- **性能优化**:通过指针传递大型数据结构可以避免不必要的复制,提高性能。
### 4. 设计一道类似作用的代码题
**题目**:编写一个函数`swap`,用于交换两个整数的值。要求使用指针作为函数参数,并在主函数中验证交换结果。
**思路说明**:
1. 创建一个`swap`函数,接收两个整数指针。
2. 在`swap`函数中,使用一个临时变量交换两个指针所指向的整数值。
3. 在`main`函数中,定义两个整数并调用`swap`函数,输出交换后的结果。
**带逐行注释的代码**:
```cpp
#include <iostream>
// 定义swap函数,接收两个整数指针
void swap(int* a, int* b) {
int temp = *a; // 用临时变量存储a指向的值
*a = *b; // 将b指向的值赋给a指向的位置
*b = temp; // 将临时变量的值赋给b指向的位置
}
int main() {
int x = 5; // 定义整数x,并初始化为5
int y = 10; // 定义整数y,并初始化为10
std::cout << "Before swap: x = " << x << ", y = " << y << std::endl;
swap(&x, &y); // 调用swap函数,交换x和y的值
std::cout << "After swap: x = " << x << ", y = " << y << std::endl; // 输出交换后的结果
return 0;
}
```
**解释**:
- 函数`swap`接受两个指针参数,通过解引用修改实际存储位置的值,实现交换。
- 在`main`函数中,使用取地址符`&`传递整数`x`和`y`的地址给`swap`函数。
- 程序输出交换前后的结果,验证函数的正确性。
#### 问题2:如何使用指针来创建和遍历链表?
**推导思路:**
- **链表结构理解**:了解链表(Linked List)是一种动态数据结构,由节点组成,每个节点包含数据和指向下一个节点的指针。
- **基本操作**:学习如何创建节点、连接节点、遍历链表。
**解答与例子:**
- 使用指针可以动态地分配内存,创建链表节点,并灵活地改变链表结构。
```cpp
#include <iostream>
struct Node {
int data;
Node* next;
};
int main() {
Node* head = new Node{1, nullptr};
head->next = new Node{2, nullptr};
head->next->next = new Node{3, nullptr};
Node* current = head;
while (current != nullptr) {
std::cout << current->data << " ";
current = current->next;
}
std::cout << std::endl;
// 清理内存
while (head != nullptr) {
Node* temp = head;
head = head->next;
delete temp;
}
}
```
在这个例子中,创建了一个简单的链表并遍历输出每个节点的值。
### 思维导图总结
1. **指针基础**
- 定义与用途
- 内存地址操作
2. **指针应用**
- 指针与数组
- 指针与函数
- 指针与动态数据结构(链表、树)
3. **指针管理**
- 内存分配与释放
- 智能指针(`std::unique_ptr`、`std::shared_ptr`)
### 思考题
#### 题1:为什么使用指针可以提高程序的效率?请从内存管理和数据传递的角度分析。
**答案:**
- **内存管理**:指针允许动态分配内存,仅在需要时分配,减少不必要的内存占用。
- **数据传递**:通过指针传递大数据结构时,只需要传递地址,避免了复制整个数据,提高了效率。
#### 题2:在链表的实现中,为什么需要小心处理内存释放?
**答案:**
- 在链表使用过程中,每个节点使用`new`操作符动态分配内存。为了避免内存泄漏,程序结束或节点不再需要时,应使用`delete`操作符释放内存。
【课堂学习】
INTJ学生:老师,我对函数指针有些困惑。能否详细阐述一下它的基本概念和应用?
ENTP老师:当然可以!函数指针是C和C++中一个非常强大的特性,它允许我们通过指针来调用函数。这种技术可以用于编写更灵活和通用的代码。让我们一步步来理解。
### 函数指针的基本概念
1. **函数的内存表示**:
- 每个函数在程序运行时都会占用一段连续的内存空间,函数名就是该内存段的起始地址,也称为函数的“入口地址”(Entry Address)。
2. **函数指针的定义**:
- 函数指针是一个变量,它存储的是函数的入口地址。通过这个指针,我们可以调用指针所指向的函数。
3. **定义函数指针**:
- 定义函数指针的语法类似于函数声明,只不过在函数名的位置用一个指针变量来代替。
### 具体例子
假设我们有一个简单的函数,它执行两个整数的加法:
```cpp
#include <iostream>
// 定义一个简单的加法函数
int add(int a, int b) {
return a + b;
}
int main() {
// 定义一个函数指针,指向返回类型为int,参数为两个int的函数
int (*funcPtr)(int, int);
// 将加法函数的地址赋给函数指针
funcPtr = add;
// 使用函数指针调用函数
int result = funcPtr(5, 3);
std::cout << "Result of add(5, 3): " << result << std::endl;
return 0;
}
```
### 逐行解释
1. **`int add(int a, int b)`**:
- 这是一个简单的函数,接收两个整数并返回它们的和。
2. **`int (*funcPtr)(int, int);`**:
- 这里定义了一个函数指针`funcPtr`。它指向一个返回类型为`int`,参数类型为两个`int`的函数。
3. **`funcPtr = add;`**:
- 将函数`add`的地址赋给函数指针`funcPtr`。现在`funcPtr`指向`add`函数。
4. **`int result = funcPtr(5, 3);`**:
- 使用函数指针`funcPtr`调用`add`函数,并将结果存储在`result`中。
5. **输出结果**:
- `std::cout << "Result of add(5, 3): " << result << std::endl;`输出调用结果,显示为8。
### 函数指针的应用场景
1. **回调函数(Callback Functions)**:
- 在某些库或框架中,允许用户提供自定义的函数来在特定事件发生时调用。
2. **实现函数表(Function Table)或命令模式**:
- 在需要动态选择和调用函数的情况下,比如实现菜单选项或命令执行。
3. **简化复杂系统的模块化**:
- 在一些大型系统中,函数指针可以用来调用不同模块中的函数,实现模块间的解耦。
通过函数指针,我们可以使程序更加灵活和模块化。
INTJ学生:老师,我对指针在计算机组成原理中的角色也很感兴趣。能否解释一下?
ENTP老师:当然!指针在计算机科学中是一个非常重要的概念,它与计算机的内存管理和程序执行息息相关。让我们从计算机组成原理的角度来分析指针的工作机制。
### 内存与指针
1. **内存结构**:
- 计算机内存是一个线性地址空间,每个内存单元都有一个唯一的地址(Address)。在大多数计算机中,内存是通过字节(Byte)来组织的,每个字节有一个地址。
2. **指针的本质**:
- 指针是一个变量,它存储的是内存地址。通过指针,我们可以直接访问和操作内存中的数据。
3. **指针的类型**:
- 指针的类型决定了指针在解引用(Dereference)时访问的内存数据的类型和大小。例如,`int*`指针通常指向一个4字节的整数数据。
### 指针与CPU
1. **寄存器与地址计算**:
- CPU中有专门的寄存器用于存储内存地址,例如程序计数器(Program Counter, PC)和栈指针(Stack Pointer, SP)。
- 指针操作通常涉及地址计算,比如指针加减运算,这需要CPU计算出正确的内存地址。
2. **指令执行**:
- 大多数CPU指令集支持基于指针的操作,如加载(Load)和存储(Store)指令,这些指令使用指针来访问内存。
### 指针与程序执行
1. **栈(Stack)和堆(Heap)内存管理**:
- 栈内存用于存储函数调用信息和局部变量,栈指针(SP)用于指示当前栈顶的位置。
- 堆内存用于动态分配内存,指针用于管理这些动态分配的内存块。
2. **函数调用与返回**:
- 指针在函数调用过程中用于保存返回地址,使得程序可以在函数执行完毕后返回到正确的代码位置。
### 指针操作的低级实现
1. **指针运算**:
- 当进行指针加减操作时,实际上是对地址进行加减运算。例如,`ptr + 1`不是简单地增加1,而是增加一个数据类型大小的偏移量。
2. **指针的解引用**:
- 解引用指针意味着访问指针所指向的内存地址上的数据。CPU通过加载指令,将该地址的数据读入寄存器中。
3. **内存对齐(Alignment)**:
- 为了提高访问效率,数据通常按其大小对齐存储在内存中。例如,32位整数通常存储在4字节对齐的地址上。
### 实际应用场景
1. **数据结构实现**:
- 链表、树等数据结构都依赖指针来链接各个节点。
2. **系统编程**:
- 操作系统中广泛使用指针来管理进程内存空间、文件描述符等资源。
通过这些机制,指针在计算机组成原理中扮演了至关重要的角色,为程序的高效执行和内存的灵活管理提供了基础。
【案例故事】
小明是一名经验丰富的C++程序员,他每天都在与各种各样的代码打交道。但有一天,他突然被一个问题困住了:为什么指针在C++中如此重要?为了寻找答案,小明决定深入计算机的内部世界,探索指针的奥秘。
### 探索指针的世界
在一个阳光明媚的周末,小明坐在电脑前,开始编写一个简单的程序。他定义了一个整数和一个指向它的指针:
```cpp
#include <iostream>
int main() {
int num = 42; // 定义一个整数
int* ptr = # // 定义一个指针,指向整数的地址
std::cout << "num的值: " << num << std::endl;
std::cout << "ptr指针指向的地址: " << ptr << std::endl;
std::cout << "通过ptr访问num的值: " << *ptr << std::endl;
return 0;
}
```
小明通过这段代码,明白了指针的基本作用:它是一个变量,存储了另一个变量的内存地址。运行程序时,他看到`num`的值为42,`ptr`存储的是`num`的内存地址,解引用(dereference)`ptr`后又得到了42。
### 内存的神秘之旅
小明的好奇心被激发了,他想象自己进入了计算机的内存世界。内存就像一座巨大的城市,每个地址都是一栋独立的房子,而指针就是这座城市的地图,帮助他找到并访问每个房子里的内容。
他意识到,通过指针,他可以对这座城市进行高效的导航和操作。例如,他可以轻松地改变一个地址上存储的值:
```cpp
*ptr = 100; // 通过指针改变num的值
std::cout << "改变后的num的值: " << num << std::endl;
```
小明惊讶地发现,尽管他没有直接操作变量`num`,但通过指针`ptr`,他成功地改变了`num`的值。这种能力让他感受到指针的强大力量。
### 探索更深的技术细节
随着对指针的了解加深,小明开始思考指针在更复杂的数据结构中的应用,比如链表和树。他写了一段简单的链表代码,进一步理解指针的灵活性:
```cpp
#include <iostream>
struct Node {
int data;
Node* next;
};
int main() {
Node* head = new Node(); // 创建第一个节点
head->data = 1;
head->next = new Node(); // 创建第二个节点
head->next->data = 2;
head->next->next = nullptr; // 链表结束
// 遍历链表
Node* current = head;
while (current != nullptr) {
std::cout << "节点值: " << current->data << std::endl;
current = current->next;
}
// 释放内存
delete head->next;
delete head;
return 0;
}
```
通过这段代码,小明理解了如何使用指针来动态管理内存和构建灵活的数据结构。链表中的每个节点都通过指针连接,形成一个可以动态扩展的结构。
### 思辨与讨论
小明开始思考:指针为何如此重要?他意识到,指针不仅仅是访问内存的工具,更是实现复杂数据结构和算法的基础。在操作系统中,指针被广泛用于管理内存和资源;在应用程序中,指针用于实现高效的数据传输和处理。
然而,小明也意识到指针带来的潜在危险。错误的指针操作可能导致内存泄漏、悬挂指针(dangling pointer)等问题。因此,理解和谨慎使用指针是每个程序员必备的技能。
以下是一套针对指针及其相关知识的复习题,以及详细解答。这些题目涵盖了指针的基本概念、应用、技术处理和项目管理等多个方面。
### 选择题
1. **情景**:小明正在调试一个C++程序,发现程序在访问某个数组元素时崩溃了。经过检查,他发现使用了一个未初始化的指针。
- **问题**:未初始化指针可能导致哪种问题?
- A) 内存泄漏
- B) 悬挂指针(Dangling Pointer)
- C) 访问非法内存
- D) 程序效率低下
**解答**:C) 访问非法内存。未初始化指针指向一个不确定的内存地址,访问它可能导致程序崩溃。
2. **情景**:在一个需要频繁动态分配和释放内存的程序中,使用智能指针(Smart Pointer)来管理内存。
- **问题**:以下哪种智能指针会自动释放不再使用的对象?
- A) `std::unique_ptr`
- B) `std::shared_ptr`
- C) `std::weak_ptr`
- D) 以上全部
**解答**:D) 以上全部。`std::unique_ptr`和`std::shared_ptr`会自动管理内存的释放,而`std::weak_ptr`用于避免循环引用。
### 判断题
3. **情景**:在一个链表实现中,小明决定用一个临时指针遍历链表。
- **问题**:使用临时指针遍历链表时,不需要担心修改链表的结构。(判断正误)
**解答**:正确。遍历操作只涉及读取链表节点的数据,不会改变链表的结构。
4. **情景**:在使用函数指针时,必须确保指针指向一个有效且正确类型的函数。
- **问题**:如果函数指针指向一个错误类型的函数,仍然可以正常调用。(判断正误)
**解答**:错误。函数指针必须指向正确类型的函数,否则会导致未定义行为。
### 分析题
5. **情景**:小明正在优化一个多线程应用程序,该程序偶尔会崩溃。
- **问题**:分析可能的原因,并给出解决方案。
**解答**:崩溃可能是由于多个线程同时访问共享资源导致的竞争条件(Race Condition)。解决方案包括:
- 使用互斥锁(Mutex)来保护共享资源。
- 使用原子操作(Atomic Operation)来确保数据一致性。
- 考虑使用线程安全的数据结构。
### 代码分析题
6. **情景**:以下是一段实现简单链表的代码:
```cpp
#include <iostream>
struct Node {
int data;
Node* next;
};
void printList(Node* head) {
Node* current = head;
while (current != nullptr) {
std::cout << current->data << " ";
current = current->next;
}
std::cout << std::endl;
}
int main() {
Node* head = new Node{1, nullptr};
head->next = new Node{2, nullptr};
head->next->next = new Node{3, nullptr};
printList(head);
// Memory leak problem
return 0;
}
```
- **问题**:找出代码中的问题并改正。
**解答**:代码中存在内存泄漏问题,因为分配的内存没有被释放。可以在程序结束前加入释放内存的代码:
```cpp
Node* current = head;
while (current != nullptr) {
Node* next = current->next;
delete current;
current = next;
}
```
### 案例技术处理
7. **情景**:在一个大型项目中,团队需要处理大量的文件I/O操作,使用指针管理文件数据。
- **问题**:如何确保文件指针操作的安全性和效率?
**解答**:
- 确保所有文件指针在使用前都已正确打开,并在使用后及时关闭。
- 使用RAII(资源获取即初始化)模式,例如C++中的文件流类,自动管理文件指针的生命周期。
- 实施错误检查机制,确保文件操作失败时能够正确处理。
### 项目工程管理和团队合作细节论述题
8. **情景**:团队正在开发一个需要高效内存管理的实时系统。
- **问题**:如何在项目工程管理中优化内存管理,并促进团队合作?
**解答**:
- **项目工程管理**:
- 制定明确的内存管理策略,包括使用智能指针、内存池等技术。
- 进行代码审查,确保所有指针操作符合最佳实践。
- 使用工具进行静态和动态分析,检测内存泄漏和非法访问。
- **团队合作**:
- 定期举行技术讨论会,分享内存管理经验和最佳实践。
- 提供培训,提升团队成员的内存管理能力。
- 实施代码协作工具,确保团队成员能够高效地进行代码合并和冲突解决。
相关文章:

北京大学c++程序设计听课笔记101
基本概念 程序运行期间,每个函数都会占用一段连续的内存空间。而函数名就是该函数所占内存区域的起始地址(也称“入口地址”)。我们可以将函数的入口地址赋给一个指针变量,使该指针变量指向该函数。然后通过指针变量就可以调用这个…...

一键生成本地SSL证书:打造HTTPS安全环境
一键生成本地SSL证书:打造HTTPS安全环境 日光下的寒林没有一丝杂质,空气里的冰冷仿佛来自故乡遥远的北国,带着一些相思,还有细微几至不可辨认的骆驼的铃声。–《心美,一切皆美》 在本地开发环境中启用 HTTPS 一直是许多…...

Unity类银河战士恶魔城学习总结(P124 CharacterStats UI玩家的UI)
【Unity教程】从0编程制作类银河恶魔城游戏_哔哩哔哩_bilibili 教程源地址:https://www.udemy.com/course/2d-rpg-alexdev/ 本章节实现了玩家属性栏,仓库,物品栏UI的制作 UI_StatSlot.cs 这个脚本是用来在Unity的UI上显示玩家属性…...

速盾:cdn 支持 php 吗?
在网络开发中,PHP 是一种广泛使用的服务器端脚本语言,用于创建动态网页和 web 应用程序。CDN(Content Delivery Network,内容分发网络)在内容分发方面具有强大的功能,那么它是否支持 PHP 呢? C…...

在linux中使用nload实时查看网卡流量
在Linux系统中,可以使用多种工具来查看网卡流量。以下是一些常用的命令行工具: ifconfig:这是最基本的网络接口查看命令,但在最新的Linux发行版中,ifconfig命令已经被ip命令替代。 ip:用来查看和操作路由…...

【JavaEE进阶】Spring 事务和事务传播机制
目录 1.事务回顾 1.1 什么是事务 1.2 为什么需要事务 1.3 事务的操作 2. Spring 中事务的实现 2.1 Spring 编程式事务(了解) 2.2 Spring声明式事务 Transactional 对比事务提交和回滚的日志 3. Transactional详解 3.1 rollbackFor 3.2 Transactional 注解什么时候会…...

Flink1.19编译并Standalone模式本地运行
1.首先下载源码 2.本地运行 新建local_conf和local_lib文件夹,并且将编译后的文件放入对应的目录 2.1 启动前参数配置 2.1.2 StandaloneSessionClusterEntrypoint启动参数修改 2.1.3 TaskManagerRunner启动参数修改 和StandaloneSessionClusterEntrypoint一样修改…...

gitlab-development-kit部署gitlab《二》
gitlab-development-kit部署gitlab《一》 环境 mac 12.7.4 xcode 14.2 gdk 0.2.16 gitlab-foss 13.7 QA xcode源码安装 # https://crifan.github.io/xcode_dev_summary/website/xcode_dev/install_xcode/ # https://xcodereleases.comopenssl1.1 源码安装 # https://open…...

Java面试之多线程并发篇(3)
前言 本来想着给自己放松一下,刷刷博客,突然被几道面试题难倒!SynchronizedMap和ConcurrentHashMap有什么区别?什么是线程安全?Thread类中的yield方法有什么作用?Java线程池中submit() 和 execute()方法有…...

任何使用 Keras 进行迁移学习
在前面的文章中,我们介绍了如何使用 Keras 构建和训练全连接神经网络(MLP)、卷积神经网络(CNN)和循环神经网络(RNN)。本文将带你深入学习如何使用 迁移学习(Transfer Learning&#…...

Mac 使用mac 原生工具将mp4视频文件提取其中的 mp3 音频文件
简介 Hello! 非常感谢您阅读海轰的文章,倘若文中有错误的地方,欢迎您指出~ ଘ(੭ˊᵕˋ)੭ 昵称:海轰 标签:程序猿|C++选手|学生 简介:因C语言结识编程,随后转入计算机专业,获得过国家奖学金,有幸在竞赛中拿过一些国奖、省奖…已保研 学习经验:扎实基础 + 多做笔…...

【SQL】一文速通SQL
SQL知识概念介绍 1. Relation Schema vs Relation Instance 简单而言,Relation Schema 是一个表,有变量还有数据类型 R (A1, A2, … , An) e.g. Student (sid: integer, name: string, login: string, addr: string, gender: char) Relation insta…...

【学习】【HTML】块级元素,行内元素,行内块级元素
块级元素 块级元素是 HTML 中一类重要的元素,它们在页面布局中占据整行空间,通常用于创建页面的主要结构组件。 常见的块级元素有哪些? <div>: 通用的容器元素,常用于创建布局块。<p>:段落元素…...

握手协议是如何在SSL VPN中发挥作用的?
SSL握手协议:客户端和服务器通过握手协议建立一个会话。会话包含一组参数,主要有会话ID、对方的证书、加密算法列表(包括密钥交换算法、数据加密算法和MAC算法)、压缩算法以及主密钥。SSL会话可以被多个连接共享,以减少…...

机器学习 - 为 Jupyter Notebook 安装新的 Kernel
https://ipython.readthedocs.io/en/latest/install/kernel_install.html 当使用jupyter-notebook --no-browser 启动一个 notebook 时,默认使用了该 jupyter module 所在的 Python 环境作为 kernel,比如 C:\devel\Python\Python311。 如果,…...

CTF攻防世界小白刷题自学笔记13
1.fileinclude,难度:1,方向:Web 题目来源:宜兴网信办 题目描述:无 给一下题目链接:攻防世界Web方向新手模式第16题。 打开一看给了很多提示,什么language在index.php的第九行,flag在flag.php中,但事情显…...

Rust 模板匹配——根据指定图片查找处于大图中的位置(支持GPU加速)
Rust 模板匹配——根据指定图片查找处于大图中的位置(支持GPU加速) 01 前言 在手搓RPA工具的时候,总会碰到不好定位的情况,那么,就需要根据小图来找到对应屏幕上的位置(以图识图),这个需求也比较简单。想到市面上也有不少RPA工具都有这个功能,那么人家有的,俺也可以…...

JVM详解:类的加载过程
JVM中类的加载主要分为三个部分,分别为加载(loading),链接(linking),初始化(initing)。其中加载负责的主要是讲类文件加载到内存中变为类对象,不过此时只有基…...

Python →爬虫实践
爬取研究中心的书目 现在,想要把如下网站中的书目信息爬取出来。 案例一 耶鲁 Publications | Yale Law School 分析网页,如下图所示,需要爬取的页面,标签信息是“<p>”,所以用 itemssoup.find_all("p&…...

Visitor 访问者模式
1)意图 表示一个作用于某对象结构中的各元素的操作。它允许在不改变各元素的类的前提下定义用于这些元素的新操作。 2)结构 访问者模式的结构图如图 7-48 所示。 其中: Visitor(访问者) 为该对象结构中ConcreteElement 的每一个类声明一个 Vsit 操作。该操作的名字和特征标识…...

Mac解压包安装MongoDB8并设置launchd自启动
记录一下在mac上安装mongodb8过程,本机是M3芯片所以下载m芯片的安装包,intel芯片的类似操作。 首先下载安装程序包。 # M芯片下载地址 https://fastdl.mongodb.org/osx/mongodb-macos-arm64-8.0.3.tgz # intel芯片下载地址 https://fastdl.mongodb.org…...

Springboot采用jasypt加密配置
目录 前言 一、Jasypt简介 二、运用场景 三、整合Jasypt 2.1.环境配置 2.2.添加依赖 2.3.添加Jasypt配置 2.4.编写加/解密工具类 2.5.自定义加密属性前缀和后缀 2.6.防止密码泄露措施 2.61.自定义加密器 2.6.2通过环境变量指定加密盐值 总结 前言 在以往的多数项目中࿰…...

加载shellcode
#include <stdio.h>#include <windows.h>DWORD GetHash(const char* fun_name){ DWORD digest 0; while (*fun_name) { digest ((digest << 25) | (digest >> 7)); //循环右移 7 位 digest *fun_name; //累加…...

K8S如何基于Istio实现全链路HTTPS
K8S如何基于Istio实现全链路HTTPS Istio 简介Istio 是什么?为什么选择 Istio?Istio 的核心概念Service Mesh(服务网格)Data Plane(数据平面)Sidecar Mode(边车模式)Ambient Mode(环境模式)Control Plane(控制平面)Istio 的架构与组件Envoy ProxyIstiod其他组件Istio 的流量管…...

React Query在现代前端开发中的应用
💓 博客主页:瑕疵的CSDN主页 📝 Gitee主页:瑕疵的gitee主页 ⏩ 文章专栏:《热点资讯》 React Query在现代前端开发中的应用 React Query在现代前端开发中的应用 React Query在现代前端开发中的应用 引言 React Query …...

【HAProxy09】企业级反向代理HAProxy高级功能之压缩功能与后端服务器健康性监测
HAProxy 高级功能 介绍 HAProxy 高级配置及实用案例 压缩功能 对响应给客户端的报文进行压缩,以节省网络带宽,但是会占用部分CPU性能 建议在后端服务器开启压缩功能,而非在HAProxy上开启压缩 注意:默认Ubuntu的包安装nginx开…...

PostgreSQL中表的数据量很大且索引过大时怎么办
在PostgreSQL中,当表的数据量很大且索引过大时,可能会导致性能问题。以下是一些优化索引和表数据的方法: 1. 评估和删除不必要的索引 识别未使用的索引:使用pg_stat_user_indexes和pg_index系统视图来查找未被使用的索引&#x…...

【QML】QML多线程应用(WorkerScript)
1. 实现功能 QML项目中,点击一个按键后,运行一段比较耗时的程序,此时ui线程会卡住。如何避免ui线程卡住。 2. 单线程(会卡住) 2.1 界面 2.2 现象 点击delay btn后,执行耗时函数(TestJs.func…...

认证鉴权框架SpringSecurity-1--概念和原理篇
1、基本概念 Spring Security 是一个强大且高度可定制的框架,用于构建安全的 Java 应用程序。它是 Spring 生态系统的一部分,提供了全面的安全解决方案,包括认证、授权、CSRF防护、会话管理等功能。 2、认证、授权和鉴权 (1&am…...

计算器上的MC、MR、M+、M—、CE是什么意思?
在计算器中, MC键叫做memory clear,中文 清除存储,是一个清除寄存器中存储数字的指令。 MS键叫做memory save,中文 存入存储。 而MR键,则是一个读取原先存储在寄存器中的数字的指令。 M键指将当前数值存入寄存器以…...