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

相关推荐
yivifu6 小时前
Excel中Lookup函数实现临界点归入下一个等级的方法
java·前端·excel
Jerry丶Li6 小时前
三十九、STM32的SPI(软件读写W25Q64)
stm32·单片机·嵌入式硬件
大佐不会说日语~6 小时前
Spring AI Alibaba 对话记忆丢失问题:Redis 缓存过期后如何恢复 AI 上下文
java·人工智能·spring boot·redis·spring·缓存
.普通人6 小时前
stm32之DS18B20温度传感器+OLED显示+RTOS多任务执行(cubemx配置,使用hal库)
stm32·单片机·嵌入式硬件
古城小栈7 小时前
Spring AI 1.1:快速接入主流 LLM,实现智能问答与文本生成
java·人工智能·spring boot·spring
计算机学姐7 小时前
基于SSM的宠物领养管理系统【2026最新】
java·vue.js·后端·java-ee·tomcat·mybatis·宠物
后端小张7 小时前
【JAVA进阶】鸿蒙开发与SpringBoot深度融合:从接口设计到服务部署全解析
java·spring boot·spring·spring cloud·华为·harmonyos·鸿蒙
Qiuner7 小时前
Spring Boot AOP(一) 入门与核心概念
java·spring boot·后端·spring·aop
Nan_Shu_6147 小时前
学习:Pinia(1)
javascript·vue.js·学习