C语言FreeRTOS队列与动态分配结构体使用异常问题求助
代码错误点及修复方案
核心致命错误
- 队列元素类型和入队数据完全不匹配:你修改队列创建参数为
sizeof(struct COMMAND)后,入队时仍然传入struct COMMAND*类型的latest_command指针,相当于把32位机下4字节的指针值直接覆盖到struct COMMAND结构体的内存空间,所有成员取值全部错位,这是你程序卡死、数据错乱的核心原因。 - 多处低级语法笔误:
play函数中memcpy(play_data.command, command, strlen(command)+1)写法错误,play_data是结构体指针,访问成员必须用->,此处越界访问内存直接破坏堆结构。- 你测试直接赋值指针时的代码
play_data->player_type = command; play_data->player_type = direction完全错误,把char*指针强制赋值给1字节的uint8_t成员,指针被截断且覆盖了同偏移位置的CONNECT结构体的username/password字段,就是你看到username = move这类异常输出的直接原因。
- 内存重复释放:
send_connect_struct/send_play_struct中已经会释放传入的CONNECT/PLAY结构体本身,旧版消费任务中还额外执行free(rec_command->connect_data)指向的内存,同一块内存被释放两次直接破坏堆管理结构,后续malloc调用直接卡死。
次要风险错误
- 任务栈空间不足:你给
prvLIBTask分配的栈是configMINIMAL_STACK_SIZE,该值通常仅为128~256字节,仅能运行空任务,包含串口发送、字符串拼接、打印逻辑时必然栈溢出,导致程序跑飞。 - 无动态内存分配检查:单片机堆空间普遍很小(通常几KB级别),
malloc调用失败返回NULL时,后续访问NULL指针会直接触发硬件异常,你当前卡在play函数大概率是堆结构被破坏后malloc失败导致的。 - 字符串常量赋值的认知错误:你调用
connect、play时传入的是字符串常量,存储在只读数据段/FLASH中,不会随函数返回失效,所以直接赋值指针前几次能正常读取,第三次出错是因为前面的内存越界操作修改了指针值或对应地址的数据,和栈内存无关。
完整修复步骤
- 队列逻辑二选一即可:
- 方案1(存指针,推荐,开销小):队列创建改回
xCommandQueue = xQueueCreate(32, sizeof(struct COMMAND*));,入队传&latest_command,消费任务接收struct COMMAND* rec_command,处理完成后仅需要free(rec_command)即可,send_xxx_struct中去掉free(CONNECT/PLAY结构体本身)的逻辑,避免重复释放。 - 方案2(存结构体):入队时改为传
*latest_command,接收后手动拷贝内部指针指向的内容,处理完成后释放所有动态分配的内存。
- 方案1(存指针,推荐,开销小):队列创建改回
- 修正所有语法笔误,结构体指针访问成员统一用
->。 - 任务栈大小调整为至少
1024字节(根据你实际串口操作逻辑调整)。 - 所有
malloc调用后增加返回值判断,分配失败时返回错误或做异常处理,禁止访问空指针。 - 统一内存释放逻辑:谁分配谁释放,避免同一块内存被多次释放。
内容的提问来源于stack exchange,提问作者Future Fisherman
相关产品推荐
相关产品推荐

