二级指针分配触发段错误:环形帧缓冲区实现求助
缓冲区实现问题排查与修正
我需要实现一个缓冲区管理逻辑:
- 有5个缓冲区,要写入20帧数据,每帧对应一个缓冲区
- 缓冲区满时,用最新帧覆盖最旧的缓冲区
- 还要能在随机时刻读取所有缓冲区中最旧的帧(包含帧ID和数据)
- 要求必须用二级指针实现缓冲区,但现在分配步骤就触发段错误,不知道原因,现有代码如下:
void fakeFrame(uint16_t *data) { for (auto i = 0; i < 1440; i++) for (auto j = 0; j < 1440; j++) data[(i * 1440) + j] = std::rand()%2; } int main() { uint16_t **p_frameBuffers; uint32_t *p_frameIdxs; uint16_t wrIdx = 0; uint16_t reIdx = 0; uint16_t currentFrameCounter = 0; uint16_t nbBuffers = 5; for(auto i =0; i< nbBuffers; i++) { p_frameBuffers[i] = (uint16_t*)malloc(1440*1440*2); } while(currentFrameCounter <= 20) { wrIdx++; wrIdx %= nbBuffers; if(wrIdx == reIdx) { std::cout<<"i passed the limit"; } currentFrameCounter++; p_frameIdxs[wrIdx] = currentFrameCounter; fakeFrame(p_frameBuffers[wrIdx]); } std::cout<<"\n"; return 0; }
段错误的核心原因
- 二级指针未初始化:
p_frameBuffers是uint16_t**类型,直接用p_frameBuffers[i]赋值等于访问野指针内存,必然触发段错误。必须先给p_frameBuffers分配能容纳nbBuffers个uint16_t*的空间。 - 帧ID数组未初始化:
p_frameIdxs是uint32_t*类型,同样没分配内存,直接赋值p_frameIdxs[wrIdx]会访问非法内存。 - 写入索引逻辑错误:初始
wrIdx=0,第一次循环wrIdx++变成1,会跳过索引0的缓冲区,浪费第一个缓冲区空间。
修正后的完整代码
#include <iostream> #include <cstdlib> #include <cstring> void fakeFrame(uint16_t *data) { for (auto i = 0; i < 1440; i++) for (auto j = 0; j < 1440; j++) data[(i * 1440) + j] = std::rand() % 2; } // 读取最旧帧的函数 void readOldestFrame(uint16_t** buffers, uint32_t* frameIds, uint16_t readIdx, uint16_t nbBuffers, uint16_t* outData, uint32_t* outId) { *outId = frameIds[readIdx]; memcpy(outData, buffers[readIdx], 1440*1440*sizeof(uint16_t)); } int main() { uint16_t **p_frameBuffers; uint32_t *p_frameIdxs; uint16_t wrIdx = 0; uint16_t reIdx = 0; uint16_t currentFrameCounter = 0; uint16_t nbBuffers = 5; uint16_t* oldestFrameData = (uint16_t*)malloc(1440*1440*sizeof(uint16_t)); uint32_t oldestFrameId; // 先给二级指针分配内存,容纳nbBuffers个指针 p_frameBuffers = (uint16_t**)malloc(nbBuffers * sizeof(uint16_t*)); // 给帧ID数组分配内存 p_frameIdxs = (uint32_t*)malloc(nbBuffers * sizeof(uint32_t)); // 逐个分配每个缓冲区的内存,并初始化帧ID for(auto i = 0; i < nbBuffers; i++) { p_frameBuffers[i] = (uint16_t*)malloc(1440*1440*sizeof(uint16_t)); p_frameIdxs[i] = 0; } while(currentFrameCounter < 20) // 确保写入正好20帧 { currentFrameCounter++; // 写入当前缓冲区 p_frameIdxs[wrIdx] = currentFrameCounter; fakeFrame(p_frameBuffers[wrIdx]); std::cout << "写入帧ID: " << currentFrameCounter << " 到缓冲区索引: " << wrIdx << std::endl; // 模拟随机时刻读取最旧帧(这里每3帧读一次,实际可替换为随机条件) if(currentFrameCounter % 3 == 0) { readOldestFrame(p_frameBuffers, p_frameIdxs, reIdx, nbBuffers, oldestFrameData, &oldestFrameId); std::cout << "读取到最旧帧ID: " << oldestFrameId << " 来自缓冲区索引: " << reIdx << std::endl; } // 更新写入索引 wrIdx++; wrIdx %= nbBuffers; // 写入索引追上读取索引时,说明要覆盖最旧帧,更新读取索引 if(wrIdx == reIdx) { std::cout << "缓冲区已满,即将覆盖最旧帧,更新读取索引" << std::endl; reIdx++; reIdx %= nbBuffers; } } // 最后读取一次最旧帧 readOldestFrame(p_frameBuffers, p_frameIdxs, reIdx, nbBuffers, oldestFrameData, &oldestFrameId); std::cout << "最终读取到最旧帧ID: " << oldestFrameId << std::endl; // 释放所有内存,避免泄漏 free(oldestFrameData); for(auto i = 0; i < nbBuffers; i++) { free(p_frameBuffers[i]); } free(p_frameBuffers); free(p_frameIdxs); return 0; }
关键修正点说明
- 先为
p_frameBuffers分配内存,再逐个分配每个缓冲区的内存 - 为
p_frameIdxs分配足够内存存储每个缓冲区对应的帧ID - 调整写入逻辑:先写入当前索引再更新,避免跳过第一个缓冲区
- 实现
readOldestFrame函数,通过reIdx定位最旧帧(reIdx始终指向当前最旧的缓冲区) - 加入内存释放逻辑,避免内存泄漏
- 修正循环条件,确保写入正好20帧
内容的提问来源于stack exchange,提问作者user3253067
相关产品推荐
相关产品推荐

