简体   繁体   English

在目标C中填充洪水时为EXC_BAD_ACCESS

[英]EXC_BAD_ACCESS while Flood Filling in Objective C

I wrote a recursive flood fill method in objective c that I am currently using in an iPad app. 我在iPad应用程序中当前使用的目标c中编写了一个递归泛洪填充方法。

I get the color of the point the user touches in a UIImage via RGBA raw data for the image. 我通过图像的RGBA原始数据获得用户在UIImage中触摸的点的颜色。

The problem is that it runs for a while then the app crashes with a EXC_BAD_ACCESS while accessing the raw data. 问题是它运行了一段时间,然后在访问原始数据时应用程序崩溃并显示EXC_BAD_ACCESS。 My question is why, is this a "stack overflow"? 我的问题是为什么这是“堆栈溢出”? and would anyone be able to suggest a way to fix this / improve upon this approach. 并且任何人都可以提出解决此问题的方法/对此方法进行改进。

Here is my method (It could be cleaner, I apologize). 这是我的方法(很抱歉,这可能会更干净)。

-(unsigned char *)floodFill:(unsigned char *)data withImageRef:(CGImageRef)imgRef withColor:(UIColor *)color whereColor:(UIColor *)pixelColor atX:(int)xx andY:(int)yy
    {
        //create points for top bottom left and right pixel
        CGPoint top = CGPointMake(xx, yy-1);
        CGPoint bottom = CGPointMake(xx, yy+1);
        CGPoint left = CGPointMake(xx-1, yy);
        CGPoint right = CGPointMake(xx+1, yy);

        //convert new color to rgba values
        const CGFloat *rgb = CGColorGetComponents(color.CGColor);

        float newRed = rgb[0];
        float newGreen = rgb[1];
        float newBlue = rgb[2];
        float newAlpha = CGColorGetAlpha(color.CGColor);

        //convert old color to rgba values
        const CGFloat *rgb2 = CGColorGetComponents(pixelColor.CGColor);

        float oldRed = rgb2[0];
        float oldGreen = rgb2[1];
        float oldBlue = rgb2[2];
        float oldAlpha = CGColorGetAlpha(pixelColor.CGColor);

        NSUInteger width = CGImageGetWidth(imgRef);
        NSUInteger bytesPerPixel = 4;
        NSUInteger bytesPerRow = bytesPerPixel * width;
        int byteIndex = (bytesPerRow * yy) + xx * bytesPerPixel;

        //color current pixel
        data[byteIndex] = (char)newRed*255;
        data[byteIndex+1] = (char)newGreen*255;
        data[byteIndex+2] = (char)newBlue*255;
        data[byteIndex+3] = (char)newAlpha*255;


        CGFloat red, green, blue, alpha;
        CGPoint currentPoint;

        //check top pixel
        currentPoint=top;
        if(currentPoint.x>=0 && currentPoint.y>=0)
        {
            byteIndex = (bytesPerRow * currentPoint.y) + currentPoint.x * bytesPerPixel;
            red   = (data[byteIndex]     * 1.0) / 255.0;
            green = (data[byteIndex + 1] * 1.0) / 255.0;
            blue  = (data[byteIndex + 2] * 1.0) / 255.0;
            alpha = (data[byteIndex + 3] * 1.0) / 255.0;
            if(red==oldRed&&green==oldGreen&&blue==oldBlue&&alpha==oldAlpha)
                data=[self floodFill:data withImageRef:imgRef withColor:color whereColor:pixelColor atX:currentPoint.x andY:currentPoint.y];
        }

        //check bottom pixel
        currentPoint=bottom;
        if(currentPoint.x>=0 && currentPoint.y>=0)
        {
            byteIndex = (bytesPerRow * currentPoint.y) + currentPoint.x * bytesPerPixel;
            red   = (data[byteIndex]     * 1.0) / 255.0;
            green = (data[byteIndex + 1] * 1.0) / 255.0;
            blue  = (data[byteIndex + 2] * 1.0) / 255.0;
            alpha = (data[byteIndex + 3] * 1.0) / 255.0;
            if(red==oldRed&&green==oldGreen&&blue==oldBlue&&alpha==oldAlpha)
                data=[self floodFill:data withImageRef:imgRef withColor:color whereColor:pixelColor atX:currentPoint.x andY:currentPoint.y];
        }

        //check left pixel
        currentPoint=left;
        if(currentPoint.x>=0 && currentPoint.y>=0)
        {
            byteIndex = (bytesPerRow * currentPoint.y) + currentPoint.x * bytesPerPixel;
            red   = (data[byteIndex]     * 1.0) / 255.0;
            green = (data[byteIndex + 1] * 1.0) / 255.0;
            blue  = (data[byteIndex + 2] * 1.0) / 255.0;
            alpha = (data[byteIndex + 3] * 1.0) / 255.0;
            if(red==oldRed&&green==oldGreen&&blue==oldBlue&&alpha==oldAlpha)
                data=[self floodFill:data withImageRef:imgRef withColor:color whereColor:pixelColor atX:currentPoint.x andY:currentPoint.y];
        }

        //check right pixel
        currentPoint=right;
        if(currentPoint.x>=0 && currentPoint.y>=0)
        {
            byteIndex = (bytesPerRow * currentPoint.y) + currentPoint.x * bytesPerPixel;
            red   = (data[byteIndex]     * 1.0) / 255.0;
            green = (data[byteIndex + 1] * 1.0) / 255.0;
            blue  = (data[byteIndex + 2] * 1.0) / 255.0;
            alpha = (data[byteIndex + 3] * 1.0) / 255.0;
            if(red==oldRed&&green==oldGreen&&blue==oldBlue&&alpha==oldAlpha)
                data=[self floodFill:data withImageRef:imgRef withColor:color whereColor:pixelColor atX:currentPoint.x andY:currentPoint.y];
        }



        return data;
    }

Thanks -TJ 谢谢-TJ

Recursive methods are major cause of stack overflow exceptions because every recursive call is pushed onto stack until it reaches end condition, especially in flood fill algorithm this approach is not suitable at all, ipad has limited resources as compared to modern computers, consider using loop based implementation of flood fill algorithm or scan-line algorithm 递归方法是导致堆栈溢出异常的主要原因,因为每个递归调用都被推入堆栈直到达到结束条件,尤其是在洪水填充算法中,这种方法根本不适用,与现代计算机相比,ipad的资源有限,请考虑使用基于循环的方法填充算法或扫描线算法的实现

for more information visit this link Flood Fill algorithms 有关更多信息,请访问此链接洪水填充算法

You must check you do not go outside of the memory allocated for the image. 您必须检查是否没有超出为图像分配的内存。 You are partially doing this in your checks for currentPoint.x>=0 && currentPoint.y>=0 . 您正在检查currentPoint.x>=0 && currentPoint.y>=0 But that doesn't stop you going passed the end of the image when you are on the last row. 但这并不能阻止您在最后一行上通过图像的末尾。

You need to do check currentPoint.y < height && currentPoint.x < width . 您需要检查currentPoint.y < height && currentPoint.x < width

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM