嵌入式C语言:二维数组
目录
一、二维数组的定义
二、内存布局
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); // 输出: 7return 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); // 输出: 7return 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>
#include <assert.h>// 辅助函数,用于访问二维数组的元素,并进行边界检查
static inline int safe_access_element(int *array, int row, int column, int width, int height) {assert(row >= 0 && row < height && column >= 0 && column < width);return array[row * width + column];
}// 宏,用于方便地从二维数组名获取数组指针(因为数组名在大多数情况下会退化为指针)
#define ACCESS_ARRAY(array) (&(array)[0][0])int main() {int matrix[3][4] = {{1, 2, 3, 4},{5, 6, 7, 8},{9, 10, 11, 12}};int rows = 3;int cols = 4;// 使用函数安全地访问第二行第三列的元素int element = safe_access_element(ACCESS_ARRAY(matrix), 1, 2, cols, rows);printf("Element at row 1, column 2 (via function): %d\n", element); // 输出: 7// 尝试访问一个无效的索引(这将触发断言失败)// int invalidElement = safe_access_element(ACCESS_ARRAY(matrix), 3, 2, cols, rows); // 这行会触发断言错误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语言中,二维数组通常是按行存储的。了解二维数组的内存布局有助于更好地管理内存和优化程序性能。
相关文章:
嵌入式C语言:二维数组
目录 一、二维数组的定义 二、内存布局 2.1. 内存布局特点 2.2. 内存布局示例 2.2.1. 数组元素地址 2.2.2. 内存布局图(简化表示) 2.3. 初始化对内存布局的影响 三、访问二维数组元素 3.1. 常规下标访问方式 3.2. 通过指针访问 3.2.1. 指向数…...
【机器学习:四、多输入变量的回归问题】
多输入变量的回归问题 1. 多元线性回归概述 1.1 单变量线性回归与多变量线性回归的概念区分 单变量线性回归:用于预测一个因变量(输出变量)与单一自变量(输入变量)之间的线性关系。模型形式为: y θ 0 …...
JVM实战—OOM的定位和解决
1.如何对系统的OOM异常进行监控和报警 (1)最佳的解决方案 最佳的OOM监控方案就是:建立一套监控平台,比如搭建Zabbix、Open-Falcon之类的监控平台。如果有监控平台,就可以接入系统异常的监控和报警,可以设置当系统出现OOM异常&…...
iOS 本地新项目上传git仓库,并使用sourceTree管理
此文记录的场景描述: iOS前期开发时,在本地创建项目,直至开发一段时间,初期编码及框架已完善后,才拿到git仓库的地址。此时需要将本地代码上传到git仓库。 上传至git仓库,可以使用终端,键入命令…...
mysql之基本select语句 运算符 排序分页
1.SQL的分类 DDL:数据定义语言. CREATE ALTER DROP RENAME TRUNCATE DML: 数据操作语言. INSERT DELETE UPDATE SELECT 重中之重 DCL: 数据控制语言. COMMIT ROLLBACK SAVEPOINT GRANT REVOKE 2.SQL语言的规则与规范 1.基本规则 SQL可以在一行或多行,为了提高可…...
如何在 Ubuntu 22.04 上安装 Nagios 服务器教程
简介 在本教程中,我们将解释如何在 Ubuntu 22.04 上安装和配置 Nagios,使用 Apache 作为 Web 服务器,并通过 Let’s Encrypt Certbot 使用 SSL 证书进行保护。 Nagios 是一个强大的监控系统,它可以帮助组织在 IT 基础设施问题影…...
数据库事务:确保数据一致性的关键机制
1. 什么是数据库事务 定义:事务(Transaction)是数据库管理系统中的一个逻辑工作单元,用于确保一组相关操作要么全部成功执行,要么全部不执行,从而维护数据的一致性和完整性。重要性:在多用户环…...
词作词汇积累:错付、大而无当、语焉不详、愈演愈烈
错付 1、基本介绍 【错付】是错误地付出或投入,特别是在感情、信任或资源方面。 【错付】代表投入的东西没有得到应有的回报,或者投入的对象并不值得。 2、实例实操 1. 她将所有的爱与关怀都【错付】给了那个不懂珍惜的人。2. 多年的努力似乎【错付…...
selenium学习笔记
一.搭建环境 1.安装chrome #下载chrome wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb#安装chrome apt --fix-broken install ./google-chrome-stable_current_amd64.deb2.安装chromedriver 首先先查看版本:google-chrome --…...
asp.net core webapi 并发请求时 怎么保证实时获取的用户信息是此次请求的?
对于并发请求,每个请求会被分配到一个独立的线程或线程池工作线程上。通过 HttpContext 或 AsyncLocal,每个线程都能独立地获取到它自己的上下文数据。由于这些数据是与当前请求相关的,因此在并发请求时不会互相干扰。 在并发请求时…...
实时数仓:基于数据湖的实时数仓与数据治理架构
设计一个基于数据湖的实时数仓与数据治理架构,需要围绕以下几个核心方面展开:实时数据处理、数据存储与管理、数据质量治理、数据权限管理以及数据消费。以下是一个参考架构方案: 一、架构整体概览 核心组成部分 数据源层 数据来源ÿ…...
STM32 拓展 RTC案例1:使用闹钟唤醒待机模式 (HAL库)
需求描述 执行完毕正常代码之后,让MCU进入待机模式,设置闹钟,自动让MCU从待机模式中被唤醒。可以用led点亮熄灭显示是否唤醒。 应用场景:比如设计一个野外温度自动采集的设备,规定每小时采集一次温度,就可…...
ESP32S3使用串口0作为LOG输出
配置 配置串口,在内存保护这个选项里Memory protection 修改内存申请函数 测试代码 uint8_t buf1 heap_caps_malloc(320*240 * sizeof(lv_color_t), MALLOC_CAP_SPIRAM); ESP_LOGI("Test", "%d", buf1);sprintf(buffer, " Biggest / …...
Linux:深入了解fd文件描述符
目录 1. 文件分类 2. IO函数 2.1 fopen读写模式 2.2 重定向 2.3 标准文件流 3. 系统调用 3.1 open函数认识 3.2 open函数使用 3.3 close函数 3.4 write函数 3.5 read函数 4. fd文件描述符 4.1 标准输入输出 4.2 什么是文件描述符 4.3 语言级文件操作 1. 文件分类…...
springboot 集成 etcd
springboot 集成 etcd 往期内容 ETCD 简介docker部署ETCD 前言 好久不见各位小伙伴们,上两期内容中,我们对于分布式kv存储中间件有了简单的认识,完成了docker-compose 部署etcd集群以及可视化工具 etcd Keeper,既然有了认识&a…...
03_Redis基本操作
1.Redis查询命令 1.1 官网命查询命令 为了便于学习Redis,官方将其用于操作不同数据类型的命令进行了分类整理。你可以通过访问Redis官方网站上的命令参考页面https://redis.io/commands来查阅这些分组的命令,这有助于更系统地理解和使用Redis的各项功能。 1.2 HELP查询命令…...
pycharm-pyspark 环境安装
1、环境准备:java、scala、pyspark、python-anaconda、pycharm vi ~/.bash_profile export SCALA_HOME/Users/xunyongsun/Documents/scala-2.13.0 export PATH P A T H : PATH: PATH:SCALA_HOME/bin export SPARK_HOME/Users/xunyongsun/Documents/spark-3.5.4-bin…...
Unity + Firebase + GoogleSignIn 导入问题
我目前使用 Unity版本:2021.3.33f1 JDK版本为:1.8 Gradle 版本为:6.1.1 Firebase 版本: 9.6.0 Google Sign In 版本为: 1.0.1 问题1 :手机点击登录报错 apk转化成zip,解压,看到/lib/armeabi-v…...
web-app uniapp监测屏幕大小的变化对数组一行展示数据作相应处理
web-app uniapp监测屏幕大小的变化对数组一行展示数据作相应处理 1.uni.getSystemInfoSync().screenWidth; 获取屏幕宽度 2.uni.onWindowResize() 实时监测屏幕宽度变化 3.根据宽度的大小拿到每行要展示的数量itemsPerRow 4.为了确保样式能够根据 items…...
2025年VGC大众汽车科技社招入职测评综合能力英语口语SHL历年真题汇总、考情分析
早在1978年,大众汽车集团就开始了与中国的联系。1984年,集团在华的第一家合资企业—上汽大众汽车有限公司奠基成立;1991年,一汽-大众汽车有限公司成立;2017年,大众汽车(安徽)有限公司…...
Linux中配置Java环境变量
基本工作 1.官网下载java 1.8地址(需要注册一个oracle账户): Java Downloads | Oracle 点击上面的链接,滚动页面到最下面就可以看到下载界面,如下图 选择适合自己系统的版本。 本文选用 jdk-8u431-linux-x64.tar.g…...
完全自定义Qt翻译功能,不使用Qt Linguist的.ts 和 .qm类型翻译
这篇文章展示了集成Qt Linguist 的功能。 但是有时候Qt的翻译功能比较繁琐,我们简单项目只需要使用本地化功能,将中文字符串导入到项目中,避免编码格式问题导致的乱码。 只需要使用一个简单的json或者其他格式的本地文件作为映射的key/value.…...
551 灌溉
常规解法: #include<bits/stdc.h> using namespace std; int n,m,k,t; const int N105; bool a[N][N],b[N][N]; int cnt; //设置滚动数组来存贮当前和下一状态的条件 //处理传播扩散问题非常有效int main() {cin>>n>>m>>t;for(int i1;i&l…...
php函数性能优化中应注意哪些问题
PHP 函数性能优化中的注意事项 在 PHP 应用中优化函数性能对于提升整体运行效率至关重要。以下是一些需要注意的关键问题: 1. 避免内联变量 将变量内联到函数调用中会增加不必要的开销。例如: function sum($a, $b) {return $a $b; }// 不要这样做&…...
安科瑞 Acrel-1000DP 分布式光伏监控系统在工业厂房分布式光伏发电项目中的应用
吕梦怡 18706162527 摘 要:常规能源以煤、石油、天然气为主,不仅资源有限,而且会造成严重的大气污染,开发清洁的可再生能源已经成为当今发展的重要任务,“节能优先,效率为本”的分布式发电能源符合社会发…...
鼠标自动移动防止锁屏的办公神器 —— 定时执行专家
目录 ◆ 如何设置 ◇ 方法1:使用【执行Nircmd命令】任务 ◇ 方法2:使用【模拟键盘输入】任务 ◆ 定时执行专家介绍 ◆ 定时执行专家最新版下载 ◆ 如何设置 ◇ 方法1:使用【执行Nircmd命令】任务 1、点击工具栏第一个图标【新建任务】&…...
各种特种无人机快速发展,无人机反制技术面临挑战
随着科技的飞速发展,各种特种无人机在军事、民用等领域得到了广泛应用,其性能不断提升,应用场景也日益丰富。然而,无人机反制技术的发展确实面临一定的挑战,难以完全跟上无人机技术的快速发展步伐。以下是对这一问题的…...
深入学习RabbitMQ的Direct Exchange(直连交换机)
RabbitMQ作为一种高性能的消息中间件,在分布式系统中扮演着重要角色。它提供了多种消息传递模式,其中Direct Exchange(直连交换机)是最基础且常用的一种。本文将深入介绍Direct Exchange的原理、应用场景、配置方法以及实践案例&a…...
HTML实战课堂之启动动画弹窗
一:代码片段讲解 小提示:下面是一个包含启动页和弹窗的完整示例。这个示例包括一个简单的启动页和一个弹窗,当用户点击启动页上的按钮时,会显示弹窗。 1. **HTML结构**: - #startPage:启动页,包…...
将本地的 Git 仓库上传到 GitHub 上(github没有该仓库)
文章目录 步骤 1:在 GitHub 上创建新仓库步骤 2:配置本地仓库步骤 3:添加远程仓库地址步骤 4:推送本地代码到 GitHub验证上传 步骤 1:在 GitHub 上创建新仓库 登录 GitHub: 打开浏览器并访问 GitHub。使用自…...
实训网站建设的总结/推广策略包括哪些内容
冬天快到了。蚂蚁和蟋蟀在各自忙着准备过冬食物。蚂蚁从早忙到晚,忙忙碌碌地搬运着,而蟋蟀则悠哉游哉,仍然在不停地歌唱着。 蚂蚁问:“你怎么不抓紧准备冬天的粮食?” 蟋蟀说:“你没有听见我在唱歌吗&#…...
WordPress用AFC制作主题/广州网站优化价格
WindowBuilder是可视化Java GUI编程的eclipse插件。有了它的帮助,我们可以通过拖拽来编辑Java程序界面。在最新版的Eclipse中安装最新版插件WindowBuilder,可以有两种方式: 一、直接安装方式: 1.启动Eclipse4.21。选择“帮助”-…...
wordpress注册没有密码/760关键词排名查询
项目接口文档管理之swagger-ui 首先引入swagger-ui的包文件其次是wagger的配置类第三是自定义接口说明第四是启动测试swagger2的常用注解说明@Api@ApiOperation@ApiImplicitParams@ApiModel@ApiResponses@ApiParam首先引入swagger-ui的包文件 <dependency><groupId...
wordpress微信机器人破解版/网络推广合作协议范本
羽毛球比赛规则: 1、21分制,三局两胜为佳 2、每球得分制 3、每回合中取胜的一方的一分 4、双方均为20分时,领先对方2分一方获胜 5、双方均为29分时,先到达30分一方获胜 6、一局比赛中获胜方在下一局率先开球 代码如下:…...
电子商务网站租用服务器费用/站长之家 站长工具
2019独角兽企业重金招聘Python工程师标准>>> 最近在用intellij IDEA创建maven项目的形式写些代码,依赖了一些库,通过pom.xml添加依赖解决。最终需要打包使用的时候,使用java命令运行其中的Class会报错,因为找不到依赖。…...
网站怎么做才有效果/网络违法犯罪举报网站
QtCreator:没有CDB二进制档可用为二进制格式在x86-windows-msvc2008-pe-32bit" 最近安装QtCreator, 可以编译运行程序, 启动调试时提示: "没有CDB二进制档可用为二进制格式在x86-windows-msvc2008-pe-32bit" 这样的错误;解决方法: 网上搜索并安装dbg_x86_6.11.1…...