【问题标题】:C Segfaults when trying to free memory that no longer needs to be used尝试释放不再需要使用的内存时出现 C 段错误
【发布时间】:2013-05-15 21:53:52
【问题描述】:

我正在使用 C 语言编写一个循环缓冲区程序。缓冲区必须能够根据每次使用新报价更新缓冲区时检查的某些条件进行扩展和缩小(缓冲区包含股票报价)。但是,当我尝试扩展缓冲区并释放旧的(较小的)缓冲区时,我从 gilbc 收到“invalid next size”错误。

我的展开功能如下:

cbuf* expandBuffer(cbuf *cb_ptr){


    int newSize;
    newSize = (cb_ptr->maxSize * 2) -1;
    cbuf *tempBuffer = malloc(sizeof(cbuf) + newSize * sizeof(quote));
    tempBuffer ->maxSize = cb_ptr->maxSize * 2;
    tempBuffer ->start = cb_ptr->start;
    tempBuffer ->end = cb_ptr->end;
    tempBuffer ->freeSlots = tempBuffer->maxSize - cb_ptr->maxSize;

    int x;
    int counter;
    counter = 0;

    for(x = cb_ptr->end; x < cb_ptr->maxSize; x ++){

        tempBuffer->quoteBuffer[counter].time = cb_ptr->quoteBuffer[x].time;
        tempBuffer->quoteBuffer[counter].rate = cb_ptr->quoteBuffer[x].rate;
        counter ++;
    }
    int y;
    for(y = 0; y < cb_ptr->start; y ++){

        tempBuffer->quoteBuffer[counter].time = cb_ptr->quoteBuffer[y].time;
        tempBuffer->quoteBuffer[counter].rate = cb_ptr->quoteBuffer[y].rate;
        counter++;
    }

    tempBuffer->start = cb_ptr->maxSize;
    tempBuffer->end = 0;
    free(cb_ptr);
    return tempBuffer;

}

而我的更新函数如下:

void cbuf_update(cbuf *cb_ptr, unsigned int time, double rate){

    *Code*

    if(cb_ptr->freeSlots == 0){
        printf("\n\nEXPANDING CIRCULAR BUFFER!\n\n");
        *cb_ptr = *(expandBuffer(cb_ptr));


    }   

    *More code here edited out since it doesnt pertain to question.
}

最后是我的主要内容:

int main(){

    cbuf *cb1 ;
    cb1 = cbuf_init() ;
    cbuf_update(cb1, 60, 1.291) ;
    cbuf_update(cb1, 63, 1.287) ;
    cbuf_update(cb1, 63, 1.231) ;
    cbuf_update(cb1, 69, 1.229) ;
    cbuf_update(cb1, 72, 1.247) ;
    cbuf_update(cb1,361,1.291);
    cbuf_update(cb1, 411, 1.291) ;
    cbuf_update(cb1, 412, 1.281) ;
    cbuf_update(cb1, 413, 1.292) ;
    cbuf_update(cb1, 414, 1.284) ;
    cbuf_update(cb1, 414, 1.290) ;
    cbuf_update(cb1, 511, 1.241) ;
    cbuf_update(cb1, 512, 1.251) ;
    cbuf_update(cb1, 513, 1.232) ;
    cbuf_update(cb1, 514, 1.202) ;
    cbuf_update(cb1, 517, 1.119) ;
    cbuf_update(cb1, 551, 1.080) ;
    cbuf_update(cb1, 552, 1.081) ;
    cbuf_update(cb1, 553, 1.079) ;
    cbuf_update(cb1, 554, 1.088) ;
    cbuf_update(cb1, 561, 1.072) ;
    cbuf_update(cb1, 562, 1.113) ;
    cbuf_update(cb1, 563, 1.091) ;
    cbuf_update(cb1, 564, 1.092) ;
    cbuf_update(cb1, 571, 1.089) ;
    cbuf_update(cb1, 572, 1.073) ;
    cbuf_update(cb1, 573, 1.061) ;
    cbuf_update(cb1, 574, 1.111) ;
    cbuf_update(cb1, 581, 1.119) ;
    cbuf_update(cb1, 582, 1.123) ;
    cbuf_update(cb1, 583, 1.151) ;
    return 0;
}

这行的段错误:

cbuf *tempBuffer = malloc(sizeof(cbuf) + newSize * sizeof(quote));

在 expandBuffer 之后,它已经成功扩展了一次。如果我需要多次扩展缓冲区,我会在该行得到一个段错误。

但是,如果我注释掉:

    free(cb_ptr);

我不再遇到段错误。但是,cb_ptr(“旧”缓冲区被新的、更大的缓冲区替换)必须被释放,因为它不再使用。我很困惑为什么释放它并在 cbuf_update 中向 cb_ptr 返回一个新的、更大的缓冲区会导致段错误。

【问题讨论】:

  • 这似乎是一个典型的案例,其中为您的问题制作一个小型完整的可编译示例非常有益。我们可能不需要一百行“cbuf_update”来理解问题。 (我敢打赌,你正在覆盖你不打算覆盖的东西)
  • 用realloc不是更方便吗?

标签: c memory segmentation-fault


【解决方案1】:

问题是这样的:

*cb_ptr = *(expandBuffer(cb_ptr));

expandBuffer 中,您释放了指针,但随后在分配中取消引用现在已释放的指针。这会导致未定义的行为,这可能(在您的情况下肯定会)导致崩溃。


我建议您改为通过引用(即指向指针的指针)将指针传递给cbuf_update 函数:

void cbuf_update(cbuf **cb_ptr, unsigned int time, double rate)
{
    /* ... */

    if((*cb_ptr)->freeSlots == 0)
    {
        printf("\n\nEXPANDING CIRCULAR BUFFER!\n\n");
        *cb_ptr = expandBuffer(*cb_ptr);
    }

    /* ... */
}

使用指针的地址运算符调用新函数:

cbuf_update(&cb1, 60, 1.291) ;

【讨论】:

  • 由于expandBuffer返回指向新分配区域的指针,cb_ptr = expandBuffer(cb_ptr);似乎是更好的方法。
  • 当我尝试 cb_ptr = expandBuffer(cb_ptr) 时,没有崩溃,但缓冲区中的数据不正确。如果我不释放 cb_ptr 并保留 *cb_ptr = *expandbuffer(cb_ptr),则数据是正确的,但它会出现段错误(我可以在 valgrind 中查看数据,尽管 valgrind 不能帮助我查明这个问题)。还有@joachim Pileborg,我无法更改函数原型
  • @DanielFischer 不可能,因为似乎即使在函数之外也需要更新指针。
  • @user1806716 当您调用expandbuffer 时,您释放了传递的cb_ptr 指针。但是随后您使用*cb_ptr 访问(现在是空闲的)内存。那是行不通的。
  • 嗯。好吧,在我用从 expandBuffer 返回的新缓冲区替换旧 cb_ptr 之后,我必须以某种方式释放它。但是,我无法在任何地方释放它而不会导致段错误。不释放它,valgrind 吐出“18 allocs, 0 frees”
猜你喜欢
  • 2016-05-08
  • 1970-01-01
  • 2015-07-13
  • 2014-04-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多