【笔记】C_静态数组

本文详细介绍了C语言中的静态数组,包括数组不可改变长度的特性,数组元素在内存中的连续存储方式。接着讨论了在静态数组中插入和删除元素的操作,这些操作通常涉及数据的拷贝和移动。最后,文章提到了数组越界和溢出的问题,指出编译器不会检查越界,并给出了越界和溢出可能导致程序中止的例子。

1.C语言中的数组静态数组

C语言中的数组不能改变长度,从出生起便固定了长度,数组数据在内存中是连续存放的。

2.数组的插入与删除

插入:因为数组是静态数组,所以插入相当于拷贝到新的数组中,将插入点的数据向后移动,插入数据。
如果在arr[5]={1,2,3,4,5}的2与3位置插入一个数字,代码如下:

#include <stdio.h>

#pragma warning(disable:4996)

int main() {
	int arr1[5] = { 1,2,3,4,5 };
	int arr2[6] = { 0 };
	int a;
	printf("enter your number:\n");
	scanf("%d", &a);
	scanf("%*[^\n]"); scanf("*c");
	for (int i = 0; i < 5; i++) {
		if (i < 2) {
			arr2[i] = arr1[i];
		}
		else if(i==2) {
			arr2[i] = a;
			arr2[i + 1] = arr1[i];
		}
		else {
			arr2[i + 1] = arr1[i];
		}
	}

	for (int j = 0; j < 6; j++) {
		printf("%d ", arr2[j]);
	}
	return 0;
}

删除:同理,也是将数组拷贝,将需要删除的数据后的数据向前移动。删除数组arr[5]={1,2,3,4,5}中的3。

#include <stdio.h>
#pragma warning(disable:4996)

int main() {
	int arr1[5] = { 1,2,3,4,5 };
	int arr2[4] = { 0 };
	printf("arr1={");
	for (int i = 0; i < 5; i++) {
		printf("%d ", arr1[i]);
	}
	printf("}\n");
	for (int j = 0; j < 5; j++) {
		if (j < 2) {
			arr2[j] = arr1[j];
		}
		else if (j > 2) {
			arr2[j - 1] = arr1[j];
		}
	}
	printf("arr2={");
	for (int c = 0; c < 4; c++) {
		printf("%d ", arr2[c]);
	}
	printf("}\n");
	return 0;
}

3.数组的越界与溢出

越界

#include <stdio.h>
#pragma warning(disable:4996)

int main() {
	int arr[4] = { 1,2,3,4 };
	for (int i = -2; i < 6; i++) {
		printf("%d\n", arr[i]);
	}
}

输出:

-858993460
-858993460
1
2
3
4
-858993460
12515688

编译器不会对越界做检查。倘若使用代码:

printf("%d",arr1[10000]);

程序中止。

溢出

#include <stdio.h>
#pragma warning(disable:4996)

int main(){
	char str[4]={"hello world");
	puts(str);
	return 0;
}
<think>首先,用户的问题是基于他们之前的查询,似乎是关于在STM32L471上使用HAL库的HAL_SPI_Transmit_DMA函数来传输一个u8格式的多维数组到SPI2_tx。 从引用中: - 引用[1]提到了在SPI DMA回调函数中使用HAL_Delay会导致问题,但不是直接相关。 - 引用[2]讨论了STM32 DMA内存到内存传输,这与SPI DMA相关。 - 引用[3]是关于SPI模式下SD卡的应用笔记,与SPI传输相关。 - 引用[4]是关于移植u8g2库使用硬件SPI,显示如何设置SPI传输。 用户的具体问题是: “我想询问使用HAL库中的HAL_SPI_Transmit_DMA函数能否完成STM32L471中从RAM将u8格式多维数组(每个成员也是相同容量u8格式数组)传输到SPI2_tx” 关键点是: - 使用函数:HAL_SPI_Transmit_DMA - MCU:STM32L471 - 数据传输:从RAM中的源到SPI2_tx - 数据类型:u8格式多维数组;每个成员是相同容量的u8数组。意思是它是一个二维数组,例如二维数组 `uint8_t array[ROWS][COLS]` 在C语言中,多维数组在内存中是连续存储的。例如,一个二维数组 `uint8_t data[5][10]` 在内存中是大小为 `5*10=50` 个u8字节的连续块。 所以,为了使用DMA传输这样的数据,我需要确保: 1. DMA可以从源地址传输连续的数据。 2. HAL_SPI_Transmit_DMA函数支持连续数据传输。 函数原型: ```c HAL_StatusTypeDef HAL_SPI_Transmit_DMA(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size); ``` 这里,`pData` 是数据指针,指向源数据,`Size` 是以字节为单位的传输大小。 对于连续多维数组,由于它在内存中是连续的,我们可以直接使用: - `pData = &data[0][0]` 或简单的 `&data`,因为多维数组的基地址指向第一个元素。 - `Size = sizeof(data)` 或 `ROWS * COLS` bytes. 在HAL库中,DMA传输设置成SPI外设时,它会处理将数据从内存传输到SPI数据寄存器。 所以,回答应该是一个响亮的“是的,它应该工作得很好”。 但是,用户提到了“多维数组每个成员也是相同容量u8格式数组”。这听起来像是描述一个二维数组,在内存中是连续的。 潜在问题: - 如果数组在内存中不连续(例如使用指针的动态分配),那就不行,但用户说“u8格式多维数组”,假设是静态或自动存储。 - DMA配置:DMA需要设置地址增加模式,但SPI传输时,源地址通常是递增的。 - 在STM32中,SPI传输使用DMA时,DMA应该设置成源地址递增(因为我们是从内存传输),目标地址(SPI数据寄存器)是固定的。 在HAL库中,DMA流配置是由底层处理好的,但当调用HAL_SPI_Transmit_DMA时,函数内部会设置DMA传输: - Source address: provided pData - Destination address: fixed to SPI data register - Data size in bytes - Increment source address after each transfer, destination address not incremented. 所以对于连续数据块,它应该可以完美工作。 如果多维数组有指针,比如 `uint8_t **data_ptr`,那么我们需要复制到连续缓冲区,但对于静态数组或 `uint8_t data[i][j]`,它是连续的。 用户指定“每个成员也是相同容量u8格式数组”,所以它可能是一个二维数组或结构体数组,但数组定义应该是连续的。 在STM32L471中,DMA处理内存区域: - RAM区域是可访问的,只要地址在有效范围内。 参考引用[2],它讨论了HAL库中DMA初始化的逻辑。 现在,构建我的回答: - 结构清晰。 - 使用中文。 - 格式正确:数学表达式用LaTeX,例如涉及大小或地址,但问题中没有太多的数学,所以可能不需要。 - 生成相关问题。 - 添加引用,但我只有用户提供的引用,实际上不需要引用研究论文或任何内容。请确保自然地添加引用标识。 引用标识:用户提供了[1],[2],[3],[4],但它们是作为引用内容提供的,所以我应该提及它们。系统指令说:“回答中引用的段落末尾自然地添加引用标识,例如:[^1]” 但在这个语境中,我没有在我的回答中真正引用任何具体的来源;我是在解决用户的查询。我应该从这些引用中选择可能相关的部分。 例如: - 引用[1]:警告不要在回调函数中使用HAL_Delay;无关。 - 引用[2]:关于DMA传输;相关。 - 引用[3]:SPI初始化;相关背景。 - 引用[4]:使用硬件SPI;相关。 但我不直接引用它们。可能,在推理中,我可以提一点。 最终回答: - 回答用户问题。 - 解释为什么可行。 - 给出代码示例或概述。 - 确保安全:在DMA传输期间不要有延迟等。 生成相关问题: - 类似于示例,在最后添加“相关问题”部分。 使用中文。 </think> ### STM32L471 中使用 `HAL_SPI_Transmit_DMA` 传输多维数组的可行性分析 是的,使用 STM32L471 的 HAL 库函数 `HAL_SPI_Transmit_DMA` 可以完成从 RAM 中传输 u8 格式多维数组(例如 `uint8_t array[M][N]` ,其中每个成员是大小相同的 u8 数组)到 SPI2_TX 数据寄存器。这里的关键是确保数据在内存中是连续存储的,以及正确配置 DMA 传输参数。 #### 原因分析 1. **多维数组在内存中的存储方式**: - 在 C 语言中,静态或自动声明的多维数组(如 `uint8_t array[M][N]`)在 RAM 中占用连续的内存块。例如,对于一个 `M × N` 的数组: - 总字节大小:$ \text{size} = M \times N $ 字节。 - 数组首地址:`&array[0][0]`。 - 由于内存连续,DMA 可以一次性读取整块数据,无需额外处理。 2. **`HAL_SPI_Transmit_DMA` 函数的工作机制**: - 函数原型:`HAL_StatusTypeDef HAL_SPI_Transmit_DMA(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size)` - `pData`: 指向数据源的指针,例如 `&array[0][0]`。 - `Size`: 传输字节数,例如 $ M \times N $。 - DMA 配置(由 HAL 库自动处理): - 源地址递增:从 RAM 读取时地址递增。 - 目标地址固定:指向 SPI2 的数据寄存器。 - 引用[2]提到,HAL 库抽象了 DMA 配置的底层细节,确保内存到外设的传输逻辑正确[^2]。 3. **STM32L471 的 SPI2 和 DMA 支持**: - STM32L471 的 DMA 控制器支持内存到外设(如 SPI 外设)的传输模式。 - SPI2 作为目标外设,其 TX 数据寄存器可以通过 DMA 访问。 - 多维数组在 RAM 中的地址必须位于 DMA 可访问区域(例如 SRAM1/SRAM2),STM32L471 的 RAM 范围是 `0x20000000` 到 `0x20048000`,标准变量自动分配在此范围。 #### 实现步骤 1. **初始化**:确保 SPI2 和对应的 DMA 通道已配置。 - 使用 CubeMX 或手动初始化代码设置 SPI2 参数(如时钟、模式)、DMA 通道(源地址递增,目标地址固定,传输大小等)。 - 引用[3]中提到的 SPI 初始化逻辑可作为参考(调整时钟速度和片选等)[^3]。 2. **DMA 传输函数调用**: - 准备多维数组数据: ```c uint8_t myArray[5][10]; // 示例:5行10列的 u8 数组,在 RAM 中连续 uint16_t size = sizeof(myArray); // 计算总字节数:5*10=50 字节 ``` - 启动传输: ```c HAL_StatusTypeDef status = HAL_SPI_Transmit_DMA(&hspi2, (uint8_t *)&myArray[0][0], size); ``` - 检查返回状态:如果 `status == HAL_OK`,表示启动成功;DMA 在后台完成传输,可避免 CPU 忙等。 3. **注意事项**: - **内存连续性问题**:如果“多维数组”通过双重指针动态分配,则不是连续的(如 `uint8_t **ptr`)。此时必须复制到连续缓冲区,或使用静态/全局数组。 - **中断和回调**: - 传输结束后会触发 HAL 回调(如 `HAL_SPI_TxCpltCallback`),但避免在回调中使用 `HAL_Delay` 等阻塞函数(见引用[1],这会导致卡死)[^1]。 - 引用[4]展示的 GPIO 延迟函数可用于替代阻塞延迟[^4]。 - **硬件限制**:确保 DMA 和 SPI 时钟源已启用(例如在 RCC 配置中)。 #### 示例代码片段 ```c // 假设已定义和初始化 SPI2 句柄 SPI_HandleTypeDef hspi2; void transmitMultidimensionalArray() { #define ROWS 5 #define COLS 10 uint8_t dataArray[ROWS][COLS]; // u8 多维数组,内存连续 // 填充数据(示例) for (int i = 0; i < ROWS; i++) { for (int j = 0; j < COLS; j++) { dataArray[i][j] = i * j; // 示例数据 } } // 计算总字节大小,启动 DMA 传输 uint16_t bufferSize = sizeof(dataArray); // 或直接使用 ROWS * COLS HAL_StatusTypeDef result = HAL_SPI_Transmit_DMA(&hspi2, (uint8_t *)dataArray, bufferSize); if (result != HAL_OK) { // 错误处理 } } ``` #### 结论 使用 `HAL_SPI_Transmit_DMA` 传输连续多维数组是可靠的。如果数组在定义时是静态连续的,传输效率高且不占用 CPU。避免在 DMA 回调函数中添加延迟或其他阻塞操作以确保程序流畅运行。 如果传输动态指针数据结构,需先转化为连续块。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值