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

CS50滤镜作业代码出现段错误,请求排查问题

CS50滤镜作业边缘检测函数段错误排查

这段代码来自CS50的滤镜作业集,检查后未发现明显非法内存访问,但程序始终出现段错误。以下是问题代码:

// Detect edges
void edges(int height, int width, RGBTRIPLE image[height][width])
{
    int Gx[3][3] = {{-1, 0, 1}, {-2, 0, 2}, {-1, 0, 1}};
    int Gy[3][3] = {{-1, -2, -1}, {0, 0, 0}, {1, 2, 1}};
    int Gx_red = 0;
    int Gx_blue = 0;
    int Gx_green = 0;
    int Gy_red = 0;
    int Gy_blue = 0;
    int Gy_green = 0;

    for (int i = 1; i <= (width - 2); i++) {
        for (int j = 1; j <= (height - 2); j++) {

            for (int m = i - 1; m <= i + 1; m++) {
                for (int n = j - 1; n <= j + 1; n++) {
                    Gx_red += image[m][n].rgbtRed * Gx[m - (i - 1)][n - (j - 1)];
                    Gx_blue += image[m][n].rgbtBlue * Gx[m - (i - 1)][n - (j - 1)];
                    Gx_green += image[m][n].rgbtGreen * Gx[m - (i - 1)][n - (j - 1)];
                    Gy_red += image[m][n].rgbtRed * Gy[m - (i - 1)][n - (j - 1)];
                    Gy_blue += image[m][n].rgbtBlue * Gy[m - (i - 1)][n - (j - 1)];
                    Gy_green += image[m][n].rgbtGreen * Gy[m - (i - 1)][n - (j - 1)];

                }
            }

            image[i][j].rgbtRed = round(sqrt((pow(Gx_red,2) + pow(Gy_red, 2))));
            image[i][j].rgbtBlue = round(sqrt(pow(Gx_blue, 2) + pow(Gy_blue, 2)));
            image[i][j].rgbtGreen = round(sqrt(pow(Gx_green, 2) + pow(Gy_green, 2)));
        }
    }
    return;
}

问题分析与修复

1. 数组维度索引颠倒(段错误直接原因)

函数参数image[height][width]定义了第一个下标对应行(高度方向,范围0height-1)**,第二个下标对应**列(宽度方向,范围0width-1)。但代码中把宽度方向的索引i/m作为image的第一个下标,高度方向的索引j/n作为第二个下标,即image[m][n]。

当图像宽度大于高度时,m的取值可能超过height-1,直接访问数组外的内存,触发段错误。正确的索引顺序应为image[n][m](n对应高度,m对应宽度)。

2. 累加变量未重置

每次计算完一个像素的Gx/Gy分量后,Gx_red、Gy_red等变量未清零,会导致后续像素计算累加旧值,不仅结果错误,还可能引发整数溢出。需要在每个像素的内层循环前,将这些变量重新初始化为0。

3. 未处理边界像素(逻辑错误)

原代码仅处理中间区域的像素,忽略了边界。边缘检测中通常将超出图像范围的像素视为0,否则会丢失边缘信息。

4. 直接修改原数组(逻辑错误)

直接修改image会导致后续像素计算使用已修改的值,结果失真。应使用临时数组存储计算结果,最后再复制回原数组。

修复后的代码

// Detect edges
void edges(int height, int width, RGBTRIPLE image[height][width])
{
    int Gx[3][3] = {{-1, 0, 1}, {-2, 0, 2}, {-1, 0, 1}};
    int Gy[3][3] = {{-1, -2, -1}, {0, 0, 0}, {1, 2, 1}};
    RGBTRIPLE temp[height][width]; // 临时数组存储结果,避免修改原数组

    for (int col = 0; col < width; col++) {
        for (int row = 0; row < height; row++) {
            // 每次计算前重置累加变量
            int Gx_red = 0, Gx_blue = 0, Gx_green = 0;
            int Gy_red = 0, Gy_blue = 0, Gy_green = 0;

            for (int m = -1; m <= 1; m++) {
                for (int n = -1; n <= 1; n++) {
                    int curr_col = col + m;
                    int curr_row = row + n;
                    // 处理边界:超出范围的像素视为0,跳过计算
                    if (curr_col < 0 || curr_col >= width || curr_row < 0 || curr_row >= height) {
                        continue;
                    }
                    // 计算Gx/Gy的权重索引(转换为0~2的范围)
                    int gx_idx = m + 1;
                    int gy_idx = n + 1;
                    // 修正image的索引顺序:row在前,col在后
                    Gx_red += image[curr_row][curr_col].rgbtRed * Gx[gy_idx][gx_idx];
                    Gx_blue += image[curr_row][curr_col].rgbtBlue * Gx[gy_idx][gx_idx];
                    Gx_green += image[curr_row][curr_col].rgbtGreen * Gx[gy_idx][gx_idx];
                    Gy_red += image[curr_row][curr_col].rgbtRed * Gy[gy_idx][gx_idx];
                    Gy_blue += image[curr_row][curr_col].rgbtBlue * Gy[gy_idx][gx_idx];
                    Gy_green += image[curr_row][curr_col].rgbtGreen * Gy[gy_idx][gx_idx];
                }
            }

            // 计算最终颜色值,并限制在0~255范围内
            int red = round(sqrt(pow(Gx_red, 2) + pow(Gy_red, 2)));
            int blue = round(sqrt(pow(Gx_blue, 2) + pow(Gy_blue, 2)));
            int green = round(sqrt(pow(Gx_green, 2) + pow(Gy_green, 2)));
            temp[row][col].rgbtRed = (red > 255) ? 255 : red;
            temp[row][col].rgbtBlue = (blue > 255) ? 255 : blue;
            temp[row][col].rgbtGreen = (green > 255) ? 255 : green;
        }
    }

    // 将临时数组的结果复制回原数组
    for (int row = 0; row < height; row++) {
        for (int col = 0; col < width; col++) {
            image[row][col] = temp[row][col];
        }
    }
    return;
}

内容的提问来源于stack exchange,提问作者Ali Moustafa

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 01:31:21