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

相关推荐
AI视觉网奇1 分钟前
ue5.7 配置 audio2face
笔记·ue5
wszy18095 分钟前
外部链接跳转:从 App 打开浏览器的正确姿势
java·javascript·react native·react.js·harmonyos
期待のcode10 分钟前
认识Java虚拟机
java·开发语言·jvm
微露清风14 分钟前
系统性学习C++-第二十讲-哈希表实现
c++·学习·散列表
raining_peidx14 分钟前
xxljob源码
java·开发语言
肥猪猪爸15 分钟前
双重检查锁(DCL)与 volatile 的关键作用
java·开发语言·单例模式
国科安芯19 分钟前
卫星通讯导航FPGA供电单元DCDC芯片ASP4644S2B可靠性分析
单片机·嵌入式硬件·fpga开发·架构·安全性测试
yaoxin52112323 分钟前
289. Java Stream API - 从字符串的字符创建 Stream
java·开发语言
浮游本尊30 分钟前
Java学习第35天 - 分布式系统深入与大数据处理
java
2301_7806698641 分钟前
Set集合、HashSet集合的底层原理
java