Size_t 变量作为循环计数器导致分段错误。为什么循环在 i = 0 时不退出?
Size_t variable as loop counter causing segmentation fault. Why does the loop not exit once i = 0?
导致问题的代码如下所示:
for(size_t i = 10; i >= 0; i--){
cout << i << ", ";
}
这输出:
4, 3, 2, 1, 0, 18446744073709551615,
然后程序 returns 出现分段错误,原因很明显,它试图以荒谬的索引访问我的项目。
为什么计数器不停在0?
编辑:我正在使用网络编译器进行作业。它没有提供任何警告。通常我在本地开发然后粘贴我所做的,因为我以前遇到过编译器问题。很高兴知道即使问题很小,我也不是完全愚蠢。感谢您的帮助!只是想在给出许多答案后我会添加一些额外的信息。
size_t
是无符号整数。这意味着 i
永远不会为负。当i
等于0
的时候,你减去1
,就会变成一个很大的数,而不是-1
。
条件 i >=0
基本上是说保持 运行 这个循环直到 i
小于零。由于 i
的类型,此条件永远不会满足。
您的编译器可能会向您指出这一点。我不确定您使用的是哪个编译器。但例如,如果您使用的是 gcc,则可以添加标志 -Wsign-compare
-Wtype-limits
.
编辑:更改为正确的 gcc 标志。致谢@Deduplicator
当您使用 for 循环从零数到九时,您执行以下操作:
for(int i = 0; i < 10; i++){
cout << i << endl;
}
请注意,此循环的条件是 i < 10。在第 9 次迭代结束时,i 递增 (i++
),然后检查 (i < 10
)。
在你的情况下, i 的类型是 size_t
,它是无符号的(也不能是负数)。因为 underflow,一旦 i--
被调用,i 从 0 变为 size_t
的最大值。由于此值为正,条件 returns 为真并且您的 for 循环继续。
如何解决这个问题?
用int
代替。 Size_t一般用来表示容器的大小,这里没必要写:D.
在这种情况下,size_t 是无符号的,显然它在为 0 时减 1 后达到最大值。并且可能您在代码中的某些地方使用此计数器 i
来访问一个数组元素然后越界,所以分段错误!
一个简单的解决方案如下:
for(size_t i = 10; i--;){
std::cout << i << ", ";
}
通过这种方式,循环将在零处停止!
如果比较总是非常正确(或错误),许多编译器会警告您。
在这种情况下,像 size_t
这样的无符号类型永远不能包含 sub-zero 值。
当然,你必须表示有兴趣得到警告,注意是可选的。
出于演示目的,请参阅 the following program compiled on coliru using gcc and clang
int main() {
for (unsigned i = 10; i >= 0; i--)
/**/;
}
如果您想在整个范围内工作,并继续使用单个无符号 loop-variable,重新排列一下即可完成:
for (size_t i = 11; i-->0; )
/**/;
当然,i-->0
可以简化为i--
,但是我不能link"What is the "-->" operator in C++? ".
导致问题的代码如下所示:
for(size_t i = 10; i >= 0; i--){
cout << i << ", ";
}
这输出: 4, 3, 2, 1, 0, 18446744073709551615,
然后程序 returns 出现分段错误,原因很明显,它试图以荒谬的索引访问我的项目。
为什么计数器不停在0?
编辑:我正在使用网络编译器进行作业。它没有提供任何警告。通常我在本地开发然后粘贴我所做的,因为我以前遇到过编译器问题。很高兴知道即使问题很小,我也不是完全愚蠢。感谢您的帮助!只是想在给出许多答案后我会添加一些额外的信息。
size_t
是无符号整数。这意味着 i
永远不会为负。当i
等于0
的时候,你减去1
,就会变成一个很大的数,而不是-1
。
条件 i >=0
基本上是说保持 运行 这个循环直到 i
小于零。由于 i
的类型,此条件永远不会满足。
您的编译器可能会向您指出这一点。我不确定您使用的是哪个编译器。但例如,如果您使用的是 gcc,则可以添加标志 -Wsign-compare
-Wtype-limits
.
编辑:更改为正确的 gcc 标志。致谢@Deduplicator
当您使用 for 循环从零数到九时,您执行以下操作:
for(int i = 0; i < 10; i++){
cout << i << endl;
}
请注意,此循环的条件是 i < 10。在第 9 次迭代结束时,i 递增 (i++
),然后检查 (i < 10
)。
在你的情况下, i 的类型是 size_t
,它是无符号的(也不能是负数)。因为 underflow,一旦 i--
被调用,i 从 0 变为 size_t
的最大值。由于此值为正,条件 returns 为真并且您的 for 循环继续。
如何解决这个问题?
用int
代替。 Size_t一般用来表示容器的大小,这里没必要写:D.
在这种情况下,size_t 是无符号的,显然它在为 0 时减 1 后达到最大值。并且可能您在代码中的某些地方使用此计数器 i
来访问一个数组元素然后越界,所以分段错误!
一个简单的解决方案如下:
for(size_t i = 10; i--;){
std::cout << i << ", ";
}
通过这种方式,循环将在零处停止!
如果比较总是非常正确(或错误),许多编译器会警告您。
在这种情况下,像 size_t
这样的无符号类型永远不能包含 sub-zero 值。
当然,你必须表示有兴趣得到警告,注意是可选的。
出于演示目的,请参阅 the following program compiled on coliru using gcc and clang
int main() {
for (unsigned i = 10; i >= 0; i--)
/**/;
}
如果您想在整个范围内工作,并继续使用单个无符号 loop-variable,重新排列一下即可完成:
for (size_t i = 11; i-->0; )
/**/;
当然,i-->0
可以简化为i--
,但是我不能link"What is the "-->" operator in C++? ".