平凡的函数给出了意想不到的 return 值
Trivial function gives unexpected return value
我编写了一个函数,它接收一个双精度矩阵并向后查找零条目。如果找到一个,它会将条目的值更改为 -2.0
和 returns true
。否则它 returns false
.
代码如下:
#include <iostream>
#include <vector>
bool remove1zero(std::vector<std::vector<double>> & matrix)
{
size_t dim = matrix.size();
for (size_t j = dim - 1; j >= 0; j--)
for (size_t i = dim - 1; i >= 0; i--)
if ((matrix[j])[i] == 0.0)
{
(matrix[j])[i] = -2.0;
return true;
}
return false;
}
int main()
{
std::vector<std::vector<double>> testMatrix(3);
testMatrix[0] = std::vector<double> {-2.0, -2.0, 3.0};
testMatrix[1] = std::vector<double> {-2.0, -1.0, 3.0};
testMatrix[2] = std::vector<double> {2.0, 2.0, -1.0};
std::cout << remove1zero(testMatrix);
}
由于该矩阵没有零项,if 条件不应激活,最终 remove1zero
应该 return false
。然而,事实并非如此。我已经在我的机器上和 http://cpp.sh/ 中试过了,输出是 1
/true
。我将不胜感激任何关于为什么会发生这种情况的见解。
如评论中所述,由于 size_t
是 unsigned 类型,因此 j >= 0
和 i >= 0
比较将 always 评估为“真”,当任一索引达到零时,下一个值(在递减该零值之后)将回绕到 size_t
类型的最大值,导致未定义的行为(越界访问)。
一个很好的 'trick' 解决这个问题的方法是使用“转到”伪运算符 -->
,它实际上是两个运算符的组合:What is the "-->" operator in C/C++?.
您可以在 for
循环中使用它,如下所述,将“迭代表达式”留空(因为递减是在“条件表达式”中完成的)并从一个更高的索引开始循环在“初始化语句”中(因为该减量将在进入循环体之前应用)。
这是您使用此方法的函数版本(请注意,我在 x-- > 0
表达式中包含了一个 space,以澄清实际上涉及两个独立的运算符):
bool remove1zero(std::vector<std::vector<double>>& matrix)
{
size_t dim = matrix.size();
for (size_t j = dim ; j-- > 0; )
for (size_t i = dim ; i-- > 0; )
if (matrix[j][i] == 0.0) {
matrix[j][i] = -2.0;
return true;
}
return false;
}
不要使用 size_t 作为循环的类型。它可以评估小于零,因为它是无符号的。只需将大小转换为整数并使用它即可。
bool remove1zero(std::vector<std::vector<double>> & matrix)
{
int dim = (int)matrix.size();
printf("matrix size=%d\n",dim);
for (int j = dim - 1; j >= 0; j--)
for (int i = dim - 1; i >= 0; i--)
{
printf("%d, %d\n",i,j);
if ((matrix[j])[i] == 0.0)
{
(matrix[j])[i] = -2.0;
return true;
}
}
return false;
}
size_t
等于 unsigned long
。当你在for循环中检查j
或i
时,你不能得到一个负数。因此,当您从 0 中减去 1 时,j
和 i
会得到一个奇怪的值。解决方案是将 size_t
更改为简单的 long
.
#include <iostream>
#include <vector>
bool remove1zero(std::vector<std::vector<double>> & matrix)
{
long dim = (long)matrix.size();
for (long j = dim - 1; j >= 0; j--)
{
for (long i = dim - 1; i >= 0; i--)
if (matrix[j][i] == 0.0)
{
matrix[j][i] = -2.0;
return true;
}
}
return false;
}
int main()
{
std::vector<std::vector<double>> testMatrix(3);
testMatrix[0] = std::vector<double> {-2.0, -2.0, 3.0};
testMatrix[1] = std::vector<double> {-2.0, -1.0, 3.0};
testMatrix[2] = std::vector<double> {2.0, 2.0, -1.0};
std::cout << remove1zero(testMatrix);
}
对于(无符号)size_t j = dim - 1;
,j >= 0
始终是 true
。所以你有越界访问,而不是停止循环。
在 C++20 中,std::ranges::reverse_view
你可能会这样做:
bool remove1zero(std::vector<std::vector<double>> & matrix)
{
for (auto& col : matrix | std::views::reverse)) {
for (double& d : col | std::views::reverse) {
if (d == 0.0) {
d = -2.0;
return true;
}
}
}
return false;
}
我编写了一个函数,它接收一个双精度矩阵并向后查找零条目。如果找到一个,它会将条目的值更改为 -2.0
和 returns true
。否则它 returns false
.
代码如下:
#include <iostream>
#include <vector>
bool remove1zero(std::vector<std::vector<double>> & matrix)
{
size_t dim = matrix.size();
for (size_t j = dim - 1; j >= 0; j--)
for (size_t i = dim - 1; i >= 0; i--)
if ((matrix[j])[i] == 0.0)
{
(matrix[j])[i] = -2.0;
return true;
}
return false;
}
int main()
{
std::vector<std::vector<double>> testMatrix(3);
testMatrix[0] = std::vector<double> {-2.0, -2.0, 3.0};
testMatrix[1] = std::vector<double> {-2.0, -1.0, 3.0};
testMatrix[2] = std::vector<double> {2.0, 2.0, -1.0};
std::cout << remove1zero(testMatrix);
}
由于该矩阵没有零项,if 条件不应激活,最终 remove1zero
应该 return false
。然而,事实并非如此。我已经在我的机器上和 http://cpp.sh/ 中试过了,输出是 1
/true
。我将不胜感激任何关于为什么会发生这种情况的见解。
如评论中所述,由于 size_t
是 unsigned 类型,因此 j >= 0
和 i >= 0
比较将 always 评估为“真”,当任一索引达到零时,下一个值(在递减该零值之后)将回绕到 size_t
类型的最大值,导致未定义的行为(越界访问)。
一个很好的 'trick' 解决这个问题的方法是使用“转到”伪运算符 -->
,它实际上是两个运算符的组合:What is the "-->" operator in C/C++?.
您可以在 for
循环中使用它,如下所述,将“迭代表达式”留空(因为递减是在“条件表达式”中完成的)并从一个更高的索引开始循环在“初始化语句”中(因为该减量将在进入循环体之前应用)。
这是您使用此方法的函数版本(请注意,我在 x-- > 0
表达式中包含了一个 space,以澄清实际上涉及两个独立的运算符):
bool remove1zero(std::vector<std::vector<double>>& matrix)
{
size_t dim = matrix.size();
for (size_t j = dim ; j-- > 0; )
for (size_t i = dim ; i-- > 0; )
if (matrix[j][i] == 0.0) {
matrix[j][i] = -2.0;
return true;
}
return false;
}
不要使用 size_t 作为循环的类型。它可以评估小于零,因为它是无符号的。只需将大小转换为整数并使用它即可。
bool remove1zero(std::vector<std::vector<double>> & matrix)
{
int dim = (int)matrix.size();
printf("matrix size=%d\n",dim);
for (int j = dim - 1; j >= 0; j--)
for (int i = dim - 1; i >= 0; i--)
{
printf("%d, %d\n",i,j);
if ((matrix[j])[i] == 0.0)
{
(matrix[j])[i] = -2.0;
return true;
}
}
return false;
}
size_t
等于 unsigned long
。当你在for循环中检查j
或i
时,你不能得到一个负数。因此,当您从 0 中减去 1 时,j
和 i
会得到一个奇怪的值。解决方案是将 size_t
更改为简单的 long
.
#include <iostream>
#include <vector>
bool remove1zero(std::vector<std::vector<double>> & matrix)
{
long dim = (long)matrix.size();
for (long j = dim - 1; j >= 0; j--)
{
for (long i = dim - 1; i >= 0; i--)
if (matrix[j][i] == 0.0)
{
matrix[j][i] = -2.0;
return true;
}
}
return false;
}
int main()
{
std::vector<std::vector<double>> testMatrix(3);
testMatrix[0] = std::vector<double> {-2.0, -2.0, 3.0};
testMatrix[1] = std::vector<double> {-2.0, -1.0, 3.0};
testMatrix[2] = std::vector<double> {2.0, 2.0, -1.0};
std::cout << remove1zero(testMatrix);
}
对于(无符号)size_t j = dim - 1;
,j >= 0
始终是 true
。所以你有越界访问,而不是停止循环。
在 C++20 中,std::ranges::reverse_view
你可能会这样做:
bool remove1zero(std::vector<std::vector<double>> & matrix)
{
for (auto& col : matrix | std::views::reverse)) {
for (double& d : col | std::views::reverse) {
if (d == 0.0) {
d = -2.0;
return true;
}
}
}
return false;
}