嵌入式面试问题: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嵌入式开发中,由于内存有限且实时性要求高,大多数情况下推荐使用静态数组,除非确实需要动态内存分配。

相关推荐
逆境不可逃15 分钟前
Pi Agent 学习笔记:不同模型如何接入同一套工具循环
笔记·学习
敲代码的嘎仔18 分钟前
用 Redis 合并写 + DelayQueue 延迟检测,把视频播放进度写库频率降到 1/60
java·开发语言·数据库·redis·缓存·音视频·高并发
词却30 分钟前
OpenCV学习:dlib 人脸检测
人工智能·opencv·学习
爱吃苹果的日记本35 分钟前
数据结构第三课补充(空间复杂度)
数据结构·学习
♪飙♪42 分钟前
电气笔记——表的认识
笔记
..Dauntless..1 小时前
【stm32】GPIO(下篇)——统一编址、源码理解和输入模式
stm32·单片机·嵌入式硬件
PC2005-cloud1 小时前
Rust学习笔记:所有权、借用与生命周期——Rust的核心机制
笔记·学习·rust
youyou-06061 小时前
AUTOSAR‑COM 常见问题 QA (1)
java·linux·服务器·单片机·汽车
谢亮_vipxieliang1 小时前
ValidX时间段验证详解:ISO 8601标准与简化格式
java·spring boot·后端·spring·spring cloud·hibernate
Lsetea1 小时前
Java 请求 HTTPS 报 PKIX path building failed:从证书链到 truststore 的完整排查
java·https·ssl证书·keytool·truststore