嵌入式C语言:二维数组

news2025/1/11 6:30:24

目录

一、二维数组的定义

二、内存布局

2.1. 内存布局特点

2.2. 内存布局示例

2.2.1. 数组元素地址

2.2.2. 内存布局图(简化表示)

2.3. 初始化对内存布局的影响

三、访问二维数组元素

3.1. 常规下标访问方式

3.2. 通过指针访问

3.2.1. 指向数组首元素的指针

3.2.2. 指向单行元素的指针

3.2.3. 指针数组访问方案(一种特殊的间接方式)

3.2.4. 动态二维数组与指针

3.3. 使用宏定义来简化访问

四、应用场景

4.1. 图像处理

4.2. 矩阵运算

4.3. 传感器数据采集与处理(矩阵形式的传感器阵列)

4.4. 游戏开发(简单的嵌入式游戏)

五、注意事项

5.1. 数组大小与内存限制

5.2. 数组越界访问

5.3. 作为函数参数传递

5.4. 初始化与赋值操作

5.5. 其它


在嵌入式 C 语言中,二维数组是一种非常有用的数据结构,用于存储和处理按行和列组织的数据。

一、二维数组的定义

在C语言中,二维数组的定义遵循以下语法结构:

数据类型 数组名[行数][列数];
int array[3][4];  // 声明一个3行4列的二维数组

定义了一个整数类型的二维数组array,包含3行4列,总共能存储12个整数。这些整数在内存中是线性排列的,即先填满第一行,再接着填充第二行,以此类推。

二、内存布局

二维数组在内存中的布局是按一维线性方式排列的,但逻辑上它呈现二维结构,即有行和列的概念。

2.1. 内存布局特点

  • 连续存储:二维数组的所有元素在内存中都是连续存储的,没有间隔或空隙。

  • 按行存储:二维数组通常是按行优先(row-major order)存储的。意味着数组的第一行完全存储在内存中,紧接着是第二行,依此类推。

  • 元素地址计算:给定一个二维数组array[rows][cols]和一个元素array[i][j],其内存地址可以通过以下方式计算(假设数组的起始地址为base_address,且每个元素的大小为element_size):

address_of_element = base_address + (i * cols + j) * element_size

2.2. 内存布局示例

int array[3][4]为例,假设每个整数元素占4个字节,且数组的起始地址为2000(仅为示例,实际地址由操作系统分配)。

2.2.1. 数组元素地址

  • array[0][0]的地址为2000。
  • array[0][1]的地址为2004(因为每个元素占4个字节)。
  • array[0][2]的地址为2008。
  • array[0][3]的地址为2012。
  • array[1][0]的地址为2016(跳过了第一行的4个元素)。
  • 以此类推,array[2][3]的地址为2044。

2.2.2. 内存布局图(简化表示)

地址	元素
2000	array[0][0]
2004	array[0][1]
2008	array[0][2]
2012	array[0][3]
2016	array[1][0]
2020	array[1][1]
2024	array[1][2]
2028	array[1][3]
2032	array[2][0]
2036	array[2][1]
2040	array[2][2]
2044	array[2][3]

用代码来验证这种布局,可以通过指针运算:

#include <stdio.h>

int main() {
    int arr[3][4];
    int *p = (int *)arr;

    for (int i = 0; i < 3 * 4; i++) {
        p[i] = i;
    }

    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 4; j++) {
            printf("arr[%d][%d] = %d, address: %p\n", i, j, arr[i][j], &arr[i][j]);
        }
    }
    return 0;
}

先把二维数组当成一维数组,用指针给所有元素赋值,之后再用二维数组的常规访问方式输出每个元素及其地址。可以清晰看到,随着循环变量的推进,元素地址是连续递增的,充分证明了按行优先的存储特性。

这种内存布局的优势在于,访问同一行元素时,由于内存连续性,缓存命中率更高,能够加快数据访问速度。而且在进行一些底层算法,例如矩阵遍历、图像像素点扫描时,了解这种布局可以简化指针运算,高效处理数组元素 。 

2.3. 初始化对内存布局的影响

二维数组的初始化不会影响其内存布局方式,但会决定数组元素的初始值。

  • 完全初始化:如果提供了足够的初始值来填充整个数组,那么这些值将按行顺序存放在内存中。

int array[3][4] = {
    {1, 2, 3, 4},
    {5, 6, 7, 8},
    {9, 10, 11, 12}
};
  • 部分初始化:如果只提供了部分初始值,那么未初始化的元素将被自动初始化为0(对于静态存储类型的数组)。这些0值也将按顺序存放在内存中。

int array[3][4] = {
    {1, 2},
    {3}
};
// 相当于:
// int array[3][4] = {
//     {1, 2, 0, 0},
//     {3, 0, 0, 0},
//     {0, 0, 0, 0}
// };

三、访问二维数组元素

3.1. 常规下标访问方式

使用下标访问二维数组元素是最直接且常见的方法:

array[i][j];  // i表示行索引,j表示列索引

索引都是从 0 开始计数。例如,对于前面定义的 array数组,要访问第二行第三列的元素,就用 matrix[1][2],它的值是 6。 

代码示例

#include <stdio.h>
 
int main() {
    int matrix[3][4] = {
        {1, 2, 3, 4},
        {5, 6, 7, 8},
        {9, 10, 11, 12}
    };
 
    // 访问第二行第三列的元素
    int element = matrix[1][2];
    printf("Element at row 1, column 2: %d\n", element); // 输出: 7
 
    return 0;
}

在嵌入式系统中,这种精准访问常用于读取传感器矩阵数据、操控显示屏像素点等场景,每个元素对应一个物理量或者像素信息。

3.2. 通过指针访问

3.2.1. 指向数组首元素的指针

当我们有一个二维数组时,如int array[3][4];,可以定义一个指向其首元素的指针,即指向第一行第一个元素的指针:

int (*ptr)[4] = array; // ptr 是一个指向包含4个int元素的数组的指针

此时,ptr 可以被用来访问二维数组的元素。例如,ptr[i][j] 相当于 array[i][j]。这里,ptr[i] 是一个指向第 i 行第一个元素的指针(类型也是 int (*)[4]),然后 [j] 用于访问该行的第 j 个元素。

例如:

#include <stdio.h>
int main() {
    int arr[3][4] = {
        {1, 2, 3, 4},
        {5, 6, 7, 8},
        {9, 10, 11, 12}
    };

    int (*q)[4];
    q = arr;
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 4; j++) {
            // 通过指向行的指针访问元素并打印
            printf("%d ", (*(q + i))[j]);
        }
        printf("\n");
    }
    return 0;
}

3.2.2. 指向单行元素的指针

另一种方法是定义一个指向 int 的指针,并让它指向二维数组的第一个元素。这种方法需要更复杂的索引计算来访问特定的元素:

int *ptr = &array[0][0]; // ptr 是一个指向 int 的指针

要访问 array[i][j],我们需要计算正确的偏移量:

int value = *(ptr + i * 4 + j); // 假设每行有4个元素

这里的 i * 4 + j 计算了从数组开始到 array[i][j] 的元素偏移量(假设数组是按行存储的,且每行有4个元素)。

例如:

#include <stdio.h>

int main() {
    int matrix[3][4] = {
        {1, 2, 3, 4},
        {5, 6, 7, 8},
        {9, 10, 11, 12}
    };

    int *p = &matrix[0][0]; // 指向二维数组的第一个元素

    // 访问第二行第三列的元素
    int element = *(p + 1*4 + 2); // 1*4 + 2 是根据二维数组的内存布局计算出的偏移量
    printf("Element at row 1, column 2 (via pointer): %d\n", element); // 输出: 7

    return 0;
}

3.2.3. 指针数组访问方案(一种特殊的间接方式)

指针数组的构建:可以创建一个指针数组,其中每个指针指向二维数组的每一行。例如,对于int arr[3][4];,可以定义

int *row_pointers[3];

然后通过循环初始化每个指针,如

for (int i = 0; i < 3; i++) {row_pointers[i] = arr[i];}

这样,row_pointers数组中的每个元素就分别指向了arr的每一行。

元素访问方式:要访问二维数组中的元素arr[i][j],可以使用

*(row_pointers[i] + j)

这里row_pointers[i]获取到指向第i行的指针,然后+ j进行列偏移,最后通过解引用*获取元素的值。

#include <stdio.h>
int main() {
    int arr[3][4] = {
        {1, 2, 3, 4},
        {5, 6, 7, 8},
        {9, 10, 11, 12}
    };

    int *row_pointers[3];
    for (int i = 0; i < 3; i++) {
        row_pointers[i] = arr[i];
    }
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 4; j++) {
            // 通过指针数组访问元素并打印
            printf("%d ", *(row_pointers[i] + j));
        }
        printf("\n");
    }
    return 0;
}

3.2.4. 动态二维数组与指针

如果二维数组的大小是动态的,我们通常使用动态内存分配(如 malloc)来创建它,并使用指针来访问它。例如:

int rows = 3, cols = 4;
int **array = malloc(rows * sizeof(int*));
for (int i = 0; i < rows; i++) {
    array[i] = malloc(cols * sizeof(int));
}

// 访问元素
array[i][j] = some_value;

// 释放内存
for (int i = 0; i < rows; i++) {
    free(array[i]);
}
free(array);

在这种情况下,array 是一个指向指针的指针(即 int **),每个 array[i] 都是一个指向第 i 行第一个元素的指针(即 int *)。

使用指针访问的优势: 在嵌入式系统中,尤其是在资源有限的情况下,通过指针访问二维数组可以更灵活地操作内存。例如,在一些实时数据处理场景中,通过指针可以快速地遍历数组元素,减少不必要的下标计算开销。同时,在与硬件寄存器或者内存映射 I/O 设备交互时,指针访问方式可以更好地适应底层硬件的地址访问要求。 

3.3. 使用宏定义来简化访问

为了方便和安全地访问二维数组元素,可以使用宏定义来封装访问逻辑。

宏定义与代码示例

#include <stdio.h>

#define ACCESS_ELEMENT(array, row, column, width) ((array)[(row)*(width)+(column)])

int main() {
    int matrix[3][4] = {
        {1, 2, 3, 4},
        {5, 6, 7, 8},
        {9, 10, 11, 12}
    };

    // 使用宏访问第二行第三列的元素
    int element = ACCESS_ELEMENT(matrix, 1, 2, 4); // 传入数组、行索引、列索引和列宽
    printf("Element at row 1, column 2 (via macro): %d\n", element); // 输出: 7

    return 0;
}

使用宏定义ACCESS_ELEMENT可以简化二维数组元素的访问,同时提高代码的可读性和可维护性。在需要频繁访问二维数组元素的嵌入式应用程序中,这种方法特别有用。

四、应用场景

在嵌入式C语言中,二维数组作为一种重要的数据结构,具有广泛的应用场景。

4.1. 图像处理

  • 图像存储:在嵌入式图像采集与处理系统中,二维数组是存储图像像素数据的理想选择。例如,一个简单的灰度图像可以用一个二维数组unsigned char image[height][width];来存储,其中height表示图像的高度(行数),width表示图像的宽度(列数),而unsigned char类型的元素可以存储每个像素的灰度值(通常范围是 0 - 255)。
  • 图像滤波:二维数组可用于实现图像滤波算法。例如,在一个简单的均值滤波算法中,对于图像中的每个像素,需要访问其周围像素的值来计算平均值。可以通过二维数组来遍历图像,如下所示:
void mean_filter(unsigned char image[height][width]) {
    unsigned char filtered_image[height][width];
    for (int i = 1; i < height - 1; i++) {
        for (int j = 1; j < width - 1; j++) {
            int sum = 0;
            for (int m = -1; m <= 1; m++) {
                for (int n = -1; n <= 1; n++) {
                    sum += image[i + m][j + n];
                }
            }
            filtered_image[i][j] = sum / 9;
        }
    }
    // 将滤波后的图像数据复制回原始数组或进行其他操作
    for (int i = 1; i < height - 1; i++) {
        for (int j = 1; j < width - 1; j++) {
            image[i][j] = filtered_image[i][j];
        }
    }
}
  • 图像边缘检测:在边缘检测算法(如 Sobel 算子)中,也需要使用二维数组来存储图像数据并进行卷积运算。通过对图像的水平和垂直方向分别进行卷积,可以计算出每个像素的梯度值,从而确定图像的边缘位置。

4.2. 矩阵运算

  • 科学计算与工程应用:在嵌入式系统的科学计算和工程应用中,经常会遇到矩阵运算。例如,在机器人运动学和动力学计算中,需要使用二维数组来表示变换矩阵。假设一个机器人手臂的正向运动学计算,需要将各个关节的旋转矩阵相乘得到末端执行器相对于基座的位姿矩阵。可以定义二维数组来存储这些矩阵,如下所示:
float joint1_matrix[4][4];
float joint2_matrix[4][4];
// 初始化关节矩阵
//...
float end_effector_matrix[4][4];
matrix_multiply(end_effector_matrix, joint1_matrix, joint2_matrix);

其中matrix_multiply函数用于实现矩阵乘法运算,通过嵌套循环来访问二维数组中的元素进行计算。

  • 数字信号处理中的矩阵运算:在数字信号处理领域,如快速傅里叶变换(FFT)的矩阵形式实现,也会用到二维数组。FFT 算法可以通过矩阵乘法来高效地计算信号的频谱,二维数组用于存储变换矩阵和信号数据,方便进行运算和中间结果的存储。

4.3. 传感器数据采集与处理(矩阵形式的传感器阵列)

  • 温度传感器阵列:在环境监测系统中,可能会使用一个二维的温度传感器阵列来获取空间温度分布。可以用二维数组来存储传感器数据,如下所示:
int temperature_array[num_rows][num_cols];
// 读取每个传感器的数据并存储到二维数组中
for (int i = 0; i < num_rows; i++) {
    for (int j = 0; j < num_cols; j++) {
        temperature_array[i][j] = read_temperature_sensor(i, j);
    }
}

之后,可以对这些数据进行分析,如查找温度异常点、计算平均温度等操作。

  • 压力传感器阵列:在一些触觉传感器系统或汽车轮胎压力监测系统中,使用压力传感器阵列来获取压力分布信息。二维数组可以很好地存储这些数据,并用于计算压力中心、压力变化趋势等参数,为后续的控制或监测提供数据支持。

4.4. 游戏开发(简单的嵌入式游戏)

  • 游戏地图存储与遍历:在简单的嵌入式游戏(如基于小型嵌入式设备的迷宫游戏或棋类游戏)中,二维数组可以用于存储游戏地图。例如,一个迷宫游戏可以用二维数组char maze[height][width];来存储,其中maze[i][j]的值可以表示该位置是墙壁(例如用'#'表示)、通道(用'.'表示)还是其他特殊元素(如宝藏、怪物等)。在游戏中,角色在迷宫中的移动可以通过遍历二维数组来实现,根据当前位置和移动方向来更新角色的位置,并检查是否遇到墙壁或其他特殊元素。
  • 游戏状态存储与更新:对于一些棋类游戏,如简单的井字棋游戏,可以用二维数组来存储棋盘状态。例如,int tic - tac - toe_board[3][3];,数组元素的值可以表示该位置是空白(0)、玩家 1 的棋子(1)还是玩家 2 的棋子(2)。在游戏过程中,通过更新二维数组中的元素来记录游戏状态,并根据游戏规则检查是否有玩家获胜或游戏是否平局。

五、注意事项

在嵌入式C语言编程中,二维数组是一种强大的数据结构,但使用时需要注意以下几点,以确保程序的稳定性和安全性。

5.1. 数组大小与内存限制

  • 内存占用:二维数组占用连续的内存空间,其大小由元素类型、行数和列数共同决定。在内存资源有限的嵌入式系统中,定义大型二维数组可能会导致内存不足,因此需要仔细考虑数组大小是否符合系统的内存预算。
  • 栈空间限制:在函数内部定义的二维数组通常占用栈空间。栈空间大小在嵌入式系统中也是有限的,过大的二维数组可能会导致栈溢出。因此,可以考虑将二维数组定义为全局变量或使用动态内存分配来解决。

5.2. 数组越界访问

  • 问题描述:C语言不会对数组下标进行边界检查,很容易出现数组越界的情况。越界访问可能会导致数据损坏、程序崩溃或产生错误的计算结果。
  • 预防措施:在编写代码时要格外小心,通过添加适当的条件判断来确保下标在合法范围内。良好的代码注释和代码风格也有助于减少越界访问的错误。

5.3. 作为函数参数传递

  • 参数声明要求:当二维数组作为函数参数传递时,除了第一维(行数)可以不指定大小外,其他维度(列数)必须指定大小。因为编译器需要知道列数才能正确地计算元素的偏移量。
  • 传递方式的理解:二维数组在函数中实际上被看作是一个指向数组首元素的指针。在编写函数时,需要清楚这种传递方式,以正确地访问和操作二维数组元素。

5.4. 初始化与赋值操作

  • 初始化方式:二维数组可以在定义时进行初始化,初始化方式有多种,包括按行初始化和不按行初始化。在初始化时要注意确保提供的初始值数量和数组大小相匹配,避免出现未初始化的元素。
  • 赋值操作:对二维数组元素进行赋值时,需要逐个元素赋值,不能像对普通变量那样整体赋值。可以通过循环或逐个指定元素的方式进行赋值。

5.5. 其它

  • 访问效率:由于二维数组是按行存储的,因此访问同一行的元素时通常比访问不同行的元素更高效。在编写代码时,可以尽量利用这一特性来提高程序的性能。
  • 指针操作:指针操作是常见的。了解二维数组的内存布局有助于正确地进行指针运算和数组访问。

综上所述,二维数组在内存中的布局是按一维线性方式排列的,但逻辑上呈现二维结构。在C语言中,二维数组通常是按行存储的。了解二维数组的内存布局有助于更好地管理内存和优化程序性能。

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

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

相关文章

Java SPI机制介绍及原理分析

概念介绍 SPI 即 Service Provider Interface &#xff0c;字面意思就是&#xff1a;“服务提供者的接口”&#xff0c;我的理解是专门给服务提供者使用的接口&#xff0c;也就是定义接口的人&#xff0c;和实现接口的人并不是同一个人 SPI 将服务接口和具体的服务实现分离开来…

数据分析-55-时间序列分析之获取时间序列的自然周期时间区间

文章目录 1 获取某年的总天数1.1 get_year_days()1.2 应用函数2 获取某年的总周数2.1 get_year_weeks()2.2 应用函数3 获取某日期属于某年的周数3.1 get_time_yearweek()3.2 应用函数4 获取某年某周的开始时间和结束时间4.1 get_week_start_end()4.2 应用函数5 获取往前num周期…

基于Spring Boot的房屋租赁系统源码(java+vue+mysql+文档)

项目简介 房屋租赁系统实现了以下功能&#xff1a; 基于Spring Boot的房屋租赁系统的主要使用者管理员可登录系统后台&#xff0c;登录后可对系统进行全面管理&#xff0c;包括个人中心、公告信息管理、租客管理、户主管理、房屋信息管理、看房申请管理、租赁合同管理、收租信…

MySQL--2.1MySQL的六种日志文件

大家好&#xff0c;我们来说一下MySQL的6中日志文件。 1.查询日志 查询日志主要记录mysql的select查询的&#xff0c;改配置是默认关闭的。不推荐开启&#xff0c;因为会导致大量查询日志文件储存占用你的空间。 举例查询一下 select * from class&#xff1b; 开启查询日志的命…

汽车供应链关键节点:物流采购成本管理全解析

在汽车行业&#xff0c;供应链管理是一项至关重要的任务。汽车制造从零部件的生产到整车的交付&#xff0c;涉及多个环节&#xff0c;其中物流、采购与成本管理是核心节点。本文将深入分析这些关键环节&#xff0c;探讨如何通过供应商管理系统及相关工具优化供应链管理。 一、…

Phidata源码分析

https://www.phidata.app/是一家agent saas公司&#xff0c;他们开源了phidata框架&#xff0c;从github介绍上看(https://github.com/phidatahq/phidata)&#xff0c;功能很齐全&#xff0c;我们来学习一下。 首先&#xff0c;明确目的&#xff0c;我想了解下面的实现方式&…

TypeScript Jest 单元测试 搭建

NPM TypeScript 项目搭建 创建目录 mkdir mockprojectcd mockproject初始化NPM项目 npm init -y安装TypeScript npm i -D typescript使用VSCode 打开项目 创建TS配置文件tsconfig.json {"compilerOptions": {"target": "es5","module&…

FPGA技术的深度理解

目录 引言 FPGA的基本原理 结构组成 工作原理 FPGA的设计流程 设计阶段 编程阶段 实现阶段 FPGA的应用领域 FPGA编程技巧和示例代码 编程技巧 示例代码 结论 引言 FPGA&#xff08;现场可编程门阵列&#xff09;是一种可编程的集成电路&#xff0c;它允许用户根据…

Mysql进阶篇

一&#xff1a;存储引擎 二&#xff1a;索引 2.1 索引概述 索引&#xff08;index&#xff09;帮助mysql高效获取数据的数据结构&#xff08;有序&#xff09;。在数据之外&#xff0c;数据库系统还维护着满足特定查找算法的数据结构&#xff0c;这些数据结构以某种方式引用&…

《Spring Framework实战》15:4.1.4.6.方法注入

欢迎观看《Spring Framework实战》视频教程 方法注入 在大多数应用场景中&#xff0c;容器中的大多数bean都是单例&#xff08;singletons&#xff09;的。当单例bean需要与另一个单例bean协作或非单例bean需与另一非单例bean协作时&#xff0c;通常通过将一个bean定义为另一个…

Flutter:使用FVM安装多个Flutter SDK 版本和使用教程

一、FVM简介 FVM全称&#xff1a;Flutter Version Management FVM通过引用每个项目使用的Flutter SDK版本来帮助实现一致的应用程序构建。它还允许您安装多个Flutter版本&#xff0c;以快速验证和测试您的应用程序即将发布的Flutter版本&#xff0c;而无需每次等待Flutter安装。…

目标客户营销(ABM)结合开源AI智能名片2+1链动模式S2B2C商城小程序的策略与实践

摘要&#xff1a;在数字化营销日益盛行的今天&#xff0c;目标客户营销&#xff08;Account Based Marketing, ABM&#xff09;作为一种高度定制化的营销策略&#xff0c;正逐步成为企业获取高质量客户、提升市场竞争力的重要手段。与此同时&#xff0c;开源AI智能名片21链动模…

docker(目录挂载、卷映射)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、目录挂载1.命令2.案例3.补充 二、卷映射1.命令2.案例 总结 前言 在使用docker部署时&#xff0c;我们如果要改变一些配置项目&#xff0c;不可能每次都进入…

opencv warpAffine仿射变换C++源码分析

基于opencv 3.1.0源代码 sources\modules\imgproc\src\imgwarp.cpp void cv::warpAffine( InputArray _src, OutputArray _dst,InputArray _M0, Size dsize,int flags, int borderType, const Scalar& borderValue ) {...if( !(flags & WARP_INVERSE_MAP) ){//变换矩阵…

使用 IntelliJ IDEA 创建简单的 Java Web 项目

以下是使用 IntelliJ IDEA 创建几个简单的 Java Web 项目的步骤&#xff0c;每个项目实现基本的登录、注册和查看列表功能&#xff0c;依赖 Servlet/JSP 和基本的 Java Web 开发。 前置准备 确保安装了 IntelliJ IDEA Ultimate&#xff08;社区版不支持 Web 应用&#xff09;。…

R语言在森林生态研究中的魔法:结构、功能与稳定性分析——发现数据背后的生态故事!

森林生态系统结构、功能与稳定性分析与可视化研究具有多方面的重要意义&#xff0c;具体如下&#xff1a; 一、理论意义 ●深化生态学理论 通过研究森林生态系统的结构、功能与稳定性&#xff0c;可以深化对生态系统基本理论的理解。例如&#xff0c;生物多样性与生态系统稳定性…

QML states和transitions的使用

一、介绍 1、states Qml states是指在Qml中定义的一组状态&#xff08;States&#xff09;&#xff0c;用于管理UI元素的状态转换和属性变化。每个状态都包含一组属性值的集合&#xff0c;并且可以在不同的状态间进行切换。 通过定义不同的状态&#xff0c;可以在不同的应用场…

Git:Cherry-Pick 的使用场景及使用流程

前面我们说了 Git合并、解决冲突、强行回退等解决方案 >> 点击查看 这里再说一下 Cherry-Pick功能&#xff0c;Cherry-Pick不是merge&#xff0c;只是把部分功能代码Cherry-Pick到远程的目标分支 git cherry-pick功能简介&#xff1a; git cherry-pick 是用来从一个分…

【SpringAOP】Spring AOP 底层逻辑:切点表达式与原理简明阐述

前言 &#x1f31f;&#x1f31f;本期讲解关于spring aop的切面表达式和自身实现原理介绍~~~ &#x1f308;感兴趣的小伙伴看一看小编主页&#xff1a;GGBondlctrl-CSDN博客 &#x1f525; 你的点赞就是小编不断更新的最大动力 &am…

python基础和redis

1. Map函数 2. filter函数 numbers generate_numbers() filtered_numbers filter(lambda x: x % 2 0, numbers) for _ in range(5):print(next(filtered_numbers)) # 输出: 0 2 4 6 83. filter map 和 reduce 4. picking and unpicking 5. python 没有函数的重载&#xff0…