You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

二级指针分配触发段错误:环形帧缓冲区实现求助

缓冲区实现问题排查与修正

我需要实现一个缓冲区管理逻辑:

  • 有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;
 }

段错误的核心原因

  1. 二级指针未初始化:p_frameBuffers是uint16_t**类型,直接用p_frameBuffers[i]赋值等于访问野指针内存,必然触发段错误。必须先给p_frameBuffers分配能容纳nbBuffers个uint16_t*的空间。
  2. 帧ID数组未初始化:p_frameIdxs是uint32_t*类型,同样没分配内存,直接赋值p_frameIdxs[wrIdx]会访问非法内存。
  3. 写入索引逻辑错误:初始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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 09:35:21