嵌入式面试问题:STM32中指针和数组的本质区别是什么,常用数组存储什么数据?

STM32中指针和数组的本质区别

核心本质区别

1. 定义与内存分配

cs 复制代码
// 数组 - 静态分配,大小固定
uint8_t array[100];  // 编译器分配100字节连续内存
// array本身是内存地址的标识符,不是变量

// 指针 - 动态或静态,大小可变
uint8_t *ptr;        // 只分配4/8字节存储地址
ptr = array;         // 指向已存在内存
ptr = (uint8_t*)malloc(100);  // 动态分配

2. 类型特性

cs 复制代码
// sizeof行为不同
sizeof(array);    // 返回整个数组大小 (100*sizeof(type))
sizeof(ptr);      // 返回指针本身大小 (4或8字节)

// 地址操作不同
&array;           // 得到数组首地址,类型是uint8_t(*)[100]
&ptr;             // 得到指针变量的地址

// 自增操作不同
ptr++;            // 指针移动sizeof(uint8_t)字节
array++;          // 错误!数组名不是左值

3. 内存布局差异

复制代码
数组:
┌─────────────────┐
│ 数据直接存储    │ ← array标识符直接引用此内存
│ (连续100字节)   │
└─────────────────┘

指针:
┌─────────┐   ┌─────────────────┐
│ 地址值  │ → │ 实际数据        │
│ (4字节) │   │ (动态分配内存)   │
└─────────┘   └─────────────────┘

STM32中常用数组存储的数据类型

1. 外设数据缓冲区

cs 复制代码
// DMA传输缓冲区
uint8_t uart_rx_buffer[256];  // UART接收缓冲区
uint32_t adc_buffer[128];     // ADC采样数据

// 通信协议数据
uint8_t can_frame[8];        // CAN报文数据场
uint8_t spi_tx_data[64];     // SPI发送数据

2. 信号处理数据

cs 复制代码
// 传感器数据缓存
int16_t imu_raw[6];          // 六轴IMU原始数据
float temperature_history[60]; // 温度历史记录

// 数字信号处理
float fft_input[1024];       // FFT输入数据
int32_t fir_filter_buffer[32]; // FIR滤波器缓存

3. 系统状态与配置

cs 复制代码
// 系统状态数组
uint32_t task_stack[128];    // 任务堆栈空间
system_state_t states[10];   // 状态机状态

// 配置参数表
const uint32_t pwm_lookup[256] = { /* PWM占空比表 */ };
const float calibration_table[20]; // 校准系数

4. 显示与界面数据

cs 复制代码
// 显示缓冲区
uint16_t lcd_frame_buffer[320*240];  // LCD显存
uint8_t led_matrix[8][8];            // LED点阵数据

// 字符与图形
const char menu_items[5][20];        // 菜单项文本
uint8_t bitmap_data[1024];           // 位图数据

5. 实时控制系统数据

cs 复制代码
// 控制算法数据
float pid_error[3];          // PID误差记录
motor_position_t trajectory[100];  // 运动轨迹

// 采样与滤波
uint32_t encoder_counts[4];  // 编码器计数值
float current_samples[100];   // 电流采样

STM32中的特殊考虑

1. 内存分段放置

cs 复制代码
// 指定数组存放位置 (链接脚本中定义)
uint8_t __attribute__((section(".ccmram"))) fast_buffer[512];  // CCM RAM
const uint8_t __attribute__((section(".rodata"))) lookup_table[256]; // 只读段

2. 对齐要求

cs 复制代码
// DMA通常需要字对齐
uint32_t __attribute__((aligned(4))) dma_buffer[128];

// 缓存行对齐优化性能
uint8_t __attribute__((aligned(32))) cache_aligned_data[1024];

3. 静态分配优势

无动态内存管理开销 - 适合实时系统

编译时确定大小 - 可预测的内存使用

更少的运行时错误 - 无内存泄漏/碎片化

选择建议

使用数组的场景:

  • 数据大小在编译时已知且固定

  • 需要频繁访问的缓冲区

  • 实时性要求高的中断服务程序

  • 避免动态内存管理的系统

使用指针的场景:

  • 数据大小在运行时确定

  • 需要灵活的内存管理

  • 传递数据到不同函数(避免大数组拷贝)

  • 动态数据结构(链表、树等)

STM32最佳实践:

cs 复制代码
// 优先使用静态数组
#define BUFFER_SIZE 256
static uint8_t local_buffer[BUFFER_SIZE];  // 文件内使用

// 需要传递时使用指针参数
void process_data(uint8_t *data, uint32_t length);

// 大数组放置在合适的内存区域
__attribute__((section(".dtcm"))) uint32_t critical_buffer[1024];  // TCM内存

性能影响

  • 数组访问:编译时可计算偏移,通常更快

  • 指针访问:需要间接寻址,可能有额外开销

  • 缓存友好性:数组的连续内存更利于缓存预取

在STM32嵌入式开发中,由于内存有限且实时性要求高,大多数情况下推荐使用静态数组,除非确实需要动态内存分配。

相关推荐
曹牧2 小时前
Spring Boot:如何测试Java Controller中的POST请求?
java·开发语言
执笔论英雄2 小时前
【大模型学习cuda】入们第一个例子-向量和
学习
wdfk_prog3 小时前
[Linux]学习笔记系列 -- [drivers][input]input
linux·笔记·学习
ouliten3 小时前
cuda编程笔记(36)-- 应用Tensor Core加速矩阵乘法
笔记·cuda
爬山算法3 小时前
Hibernate(90)如何在故障注入测试中使用Hibernate?
java·后端·hibernate
kfyty7253 小时前
集成 spring-ai 2.x 实践中遇到的一些问题及解决方案
java·人工智能·spring-ai
猫头虎3 小时前
如何排查并解决项目启动时报错Error encountered while processing: java.io.IOException: closed 的问题
java·开发语言·jvm·spring boot·python·开源·maven
李少兄3 小时前
在 IntelliJ IDEA 中修改 Git 远程仓库地址
java·git·intellij-idea
忆~遂愿3 小时前
ops-cv 算子库深度解析:面向视觉任务的硬件优化与数据布局(NCHW/NHWC)策略
java·大数据·linux·人工智能
小韩学长yyds4 小时前
Java序列化避坑指南:明确这4种场景,再也不盲目实现Serializable
java·序列化