Set matrix zeroes首行首列参考法实现报heap-buffer-overflow错误
矩阵置零算法堆缓冲区溢出错误排查
给定m×n整数矩阵matrix,若某元素为0,则需将其所在整行、整列全部置为0。采用第1行、第1列作为参考行/参考列的思路实现时,触发运行时错误:ERROR: AddressSanitizer: heap-buffer-overflow on address....,对应的C++实现代码如下:
class Solution { public: void setZeroes(vector<vector<int>>& matrix) { int x=1, y=1, col=1,row=1; int m=matrix.size(); int n=matrix[0].size(); //for 1st row i.e considered as reference row for inner matrix for(int i=0;i<m;i++){ if(matrix[i][0]==0) x=0; } // for 1st column i.e considered as reference column for inner matrix; for(int a=0;a<n;a++){ if(matrix[0][a]==0) y=0; } //loop for the inner matrix for(int i=1;i<m;i++){ for(int j=1;j<n;j++){ if(matrix[i][j]==0){ matrix[0][j]=0; matrix[i][0]=0; } } } //for iterating over 1st row of the matrix to check for zeroes. for(int i=1;i<m;i++){ if(matrix[0][i]==0){ while(i<n){ matrix[i][col]=0; col++; }; break; } } //for iterating over 1 column of the matrix to check for zeroes for(int j=1;j<n;j++){ if(matrix[j][0]==0){ while(j<m){ matrix[row][j]=0; row++; }; break; } } if(x==0){ for(int i=0;i<m;i++) matrix[0][i]=0; } if(y==0){ for(int j=0;j<n;j++) matrix[j][0]=0; } } };
错误原因
代码索引逻辑完全混乱,是触发堆缓冲区溢出的核心原因,具体问题如下:
- 标记变量对应关系写反:注释标注
x用来标记第一行是否有0、y标记第一列是否有0,但实际代码中x是遍历第一列得到的结果,y是遍历第一行得到的结果,后续置零逻辑完全错位。 - 遍历参考标记时循环边界错误:遍历第一行的参考标记时,循环终止条件写为
i<m(m是矩阵总行数),但第一行的有效列索引范围是0~n-1,当m大于n时,访问matrix[0][i]会直接超出数组边界。 - 置零内层while循环逻辑错误:检测到参考位为0后,while循环只自增列/行偏移变量,不更新外层的行/列索引,会无限向同一行/列的越界内存位置写入0,直接触发堆溢出。比如处理列置零的代码块中,
while(i<n)判断条件用的是行索引i,但循环内只做col++操作,i的值永远不变,既会死循环,又会随着col增大访问到矩阵外的内存。 - 最后处理第一行、第一列置零的逻辑同样索引错位:比如
x==0本应给第一列置零,代码却遍历写入matrix[0][i](第一行的位置),当m大于n时同样会越界访问。
修正方案
采用首行首列作为参考位的标准实现逻辑如下:
- 先用两个布尔变量分别标记第一行、第一列本身是否存在0,避免后续标记覆盖原始状态。
- 遍历从(1,1)坐标开始的内部矩阵,遇到0就把对应位置的首行参考位
matrix[0][j]、首列参考位matrix[i][0]置0。 - 再次遍历内部矩阵,只要当前位置对应的首行参考位或首列参考位为0,就把当前位置置0。
- 最后根据第一步存储的布尔标记,单独处理第一行和第一列的置零。
修正后的可运行代码:
class Solution { public: void setZeroes(vector<vector<int>>& matrix) { int m = matrix.size(); int n = matrix[0].size(); bool firstRowHasZero = false, firstColHasZero = false; // 标记第一列是否存在0 for(int i = 0; i < m; i++){ if(matrix[i][0] == 0){ firstColHasZero = true; break; } } // 标记第一行是否存在0 for(int j = 0; j < n; j++){ if(matrix[0][j] == 0){ firstRowHasZero = true; break; } } // 用首行首列存储内部矩阵的置零标记 for(int i = 1; i < m; i++){ for(int j = 1; j < n; j++){ if(matrix[i][j] == 0){ matrix[i][0] = 0; matrix[0][j] = 0; } } } // 根据标记给内部矩阵置零 for(int i = 1; i < m; i++){ for(int j = 1; j < n; j++){ if(matrix[i][0] == 0 || matrix[0][j] == 0){ matrix[i][j] = 0; } } } // 单独处理首行置零 if(firstRowHasZero){ for(int j = 0; j < n; j++){ matrix[0][j] = 0; } } // 单独处理首列置零 if(firstColHasZero){ for(int i = 0; i < m; i++){ matrix[i][0] = 0; } } } };
内容的提问来源于stack exchange,提问作者sakshi jain
相关产品推荐
相关产品推荐

