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

相关推荐
一定要AK5 小时前
Spring 入门核心笔记
java·笔记·spring
A__tao5 小时前
Elasticsearch Mapping 一键生成 Java 实体类(支持嵌套 + 自动过滤注释)
java·python·elasticsearch
AI成长日志5 小时前
【Agentic RL】1.1 什么是Agentic RL:从传统RL到智能体学习
人工智能·学习·算法
KevinCyao5 小时前
java视频短信接口怎么调用?SpringBoot集成视频短信及回调处理Demo
java·spring boot·音视频
迷藏4945 小时前
**发散创新:基于Rust实现的开源合规权限管理框架设计与实践**在现代软件架构中,**权限控制(RBAC)** 已成为保障
java·开发语言·python·rust·开源
UTP协同自动化测试5 小时前
物联网模组测试难点 |APP指令下发+UART 响应+GPIO 电平变化,如何一次性验证?
功能测试·嵌入式硬件·物联网·模块测试
_李小白6 小时前
【OSG学习笔记】Day 38: TextureVisitor(纹理访问器)
android·笔记·学习
wuxinyan1236 小时前
Java面试题47:一文深入了解Nginx
java·nginx·面试题
新知图书6 小时前
搭建Spring Boot开发环境
java·spring boot·后端
冰河团队6 小时前
一个拉胯的分库分表方案有多绝望?整个部门都在救火!
java·高并发·分布式数据库·分库分表·高性能