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
相关产品推荐
相关产品推荐

