是什么导致堆栈溢出?而我该如何解决呢?

时间:2019-03-30 13:59:23

标签: c graphics

我正在做计算机图形学的作业。 我们需要使用floodfill来绘制区域,但是无论我如何更改Visual Studio的reserve stack,它总是会跳出stackoverflow

void Polygon_FloodFill(HDC hdc, int x0, int y0, int fillColor, int borderColor) {
int interiorColor;
interiorColor = GetPixel(hdc, x0, y0);
if ((interiorColor != borderColor) && (interiorColor != fillColor)) {
    SetPixel(hdc, x0, y0, fillColor);
    Polygon_FloodFill(hdc, x0 + 1, y0, fillColor, borderColor);
    Polygon_FloodFill(hdc, x0, y0 + 1, fillColor, borderColor);
    Polygon_FloodFill(hdc, x0 - 1 ,y0, fillColor, borderColor);
    Polygon_FloodFill(hdc, x0, y0 - 1, fillColor, borderColor);
}

3 个答案:

答案 0 :(得分:1)

您可能要填充的区域太大,这会导致递归调用占用程序中的所有执行堆栈。

您的选择:

  • 如果可以的话,进一步扩大执行堆栈
  • 缩小面积(大约100x100或20x20?)
  • 停止使用执行堆栈,并使用类似的数据结构,但可以包含更多元素(通过提高效率和/或能够增长/更大)
  • 使用不同的算法(例如,考虑从单个像素到像素的水平跨度,后者将比前者少很多)

答案 1 :(得分:0)

  

什么导致堆栈溢出?

x0的范围是多少? +/- 2,000,000,000?那就是您的堆栈深度潜力。

除非GetPixel(out-of-range)返回不匹配值,否则代码显然不会阻止超出范围。

  

该如何解决?

代码在递归调用上需要更具选择性。
如果可以设置一行像素,则无需递归。
然后检查该行的邻居,并仅在邻居不需要持续进行设置时递归。

一种有前途的方法将处理中间问题,然后查看4个基本方向。

// Pseudo code
Polygon_FloodFill(x,y,c)
  if (pixel(x,y) needs filling) {    
    set pixel(x,y,c);
    for each of the 4 directions 
      // example: east
      i = 1; 
      // fill the east line first  
      while (pixel(x+i,y) needs filling) {     
        i++;
        set pixel(x,y,c);
      }
      // now examine the line above the "east" line
      recursed = false;
      for (j=1; j<i; j++) {
        if (pixel(x+j, y+j) needs filling) {     
          if (!recursed) {
            recursed = true;
            Polygon_FloodFill(x+j,y+j,c)
          } else  {
            // no need to call Polygon_FloodFill as will be caught with previous call
          }
        } else {
          recursed = false;
        }
      }
      // Same for line below the "east" line

      // do same for south, west, north.
    }

答案 2 :(得分:0)

要填充多少像素?每个像素都在递归深度一级,您会得到很多局部变量和递归函数的操作数+返回值和地址,因此对于到达像素,您可以存储以下变量:

void Polygon_FloodFill(HDC hdc, int x0, int y0, int fillColor, int borderColor) {
int interiorColor;

在32位环境中,我以[字节]为单位对此进行了估算:

4 Polygon_FloodFill return address
4 HDC hdc ?
4 int x0
4 int y0
4 int fillColor
4 int borderColor
4 int interiorColor
-------------------
~ 7*4 = 28 Bytes

可能还有更多取决于 C 引擎和调用顺序。

现在,如果您的填充区域具有256x256像素,那么您需要:

7*4*256*256 = 1.75 MByte

堆栈/堆上的内存。您获得多少内存取决于编译/链接所使用的设置,因此转到项目选项并查找内存堆栈/堆限制...

如何处理?

  1. 降低堆栈/堆垃圾

    仅对flood_fill不使用操作数,而是将它们移动到全局变量:

    HDC floodfill_hdc;
    int floodfill_x0,floodfill_y0,floodfill_fillColor,floodfill_borderColor;
    void _Polygon_FloodFill()
     {
     // here your original filling code
     int interiorColor;
     ...
     }
    void PolygonFloodFill(HDC hdc, int x0, int y0, int fillColor, int borderColor) // this is what you call when want to fill something
     {
     floodfill_hdc=hdc;
     floodfill_x0=x0;
     floodfill_y0=y0;
     floodfill_fillColor=fillColor;
     floodfill_borderColor=borderColor;
     _Polygon_FloodFill();
     }
    

    这将允许填充约14倍大的区域。

  2. 限制递归深度

    有时也称为优先级que ...您只需添加一个全局计数器即可计算实际的递归深度,如果命中极限值,则不允许递归。而是将像素位置添加到实际递归停止后将要处理的某些列表。

  3. 将填充从像素更改为线条

    这只是消除了从sqrt(n)n递归的粗略估计中的许多递归调用……您只需从起点到预定方向填充整行,直到碰到边界..因此,您只需要每行而不是每个像素进行递归调用。下面是示例(请参见[edit2]):

但是函数名称Polygon_FloodFill表示您获得了矢量形式的边界多边形。如果使用填充栅格,比使用以下栅格栅格化技术会更快更快

但是,该多边形必须是凸多边形,因此,如果不是这样,则需要首先进行三角剖分或分解为凸多边形(例如,使用耳朵剪裁)。