[英]Infinite loop when using size_t in a count down for loop
所以我在任何索引 for 循環中使用size_t
而不是int
來防止負索引。 但是在倒計時時,這會導致溢出:
for (size_t i = 10; i >= 0; --i) {
// Do something, f.ex. array[i] = i
}
什么是防止這種情況的好方法?
int
代替?我很感激任何反饋!
for (size_t i = 10; i <= 10; --i) // do something
當溢出 do 發生時,它將四舍五入到最大的整數,因此條件將失敗。
for (size_t i = 11; i-- > 0; ) {
// Do something, f.ex. array[i] = i
}
注意:問題以 value=10 開始循環(這很奇怪,但並非不可能)。 我從11開始,但是第一次進入循環體時,它已經遞減到10了。
從技術上講,這不是溢出,因為size_t
是無符號類型,但它絕對是無限循環,因為終止條件始終為真。
無符號整數在0
遞減時回繞。 請注意,您的循環將在環繞發生之前運行11
次,而不是10
。
在遞減索引之前,您必須檢查條件。 以比最大有效索引大 1 的初始值開始枚舉可提高視覺一致性並簡化測試。
這是一個更正的版本,您可以看到i
的初始值是數組的元素數:
int array[11];
for (size_t i = 11; i-- > 0; ) {
// Do something, f.ex. array[i] = i
}
慣用的方式,雖然不是每個人的口味,是使用幻燈片運算符:
for (size_t i = 10 + 1; i--> 0; )
它並不是真正的運營商,但這就是多年來人們所熟知的。
最簡單的方法是增加上限值。 例如
const size_t N = 10;
for (size_t i = N + 1; i != 0; --i) {
// Do something, f.ex. array[i-1] = i-1
}
或者
const size_t N = 10;
for (size_t i = N + 1; i-- != 0; ) {
// Do something, f.ex. array[i] = i
}
在一般情況下,當 i 可以等於存儲在size_t
類型的對象中的最大值時,您可以使用以下技巧
#include <stdio.h>
int main( void )
{
const size_t N = 10;
for (size_t i = N, j = N; !( i == 0 && j == -1 ); j--)
{
i = j;
printf( "%zu ", i );
}
printf( "\n" );
}
否則,您可以使用 do-while 循環。 在這種情況下更合適。 例如
size_t i = N;
do
{
printf( "%zu ", i );
} while ( i-- != 0 );
size_t i = 10; i >= 0;
永遠不會為假,因為size_t
是某種無符號類型並且所有值都大於或等於零。
...
size_t
這是sizeof
運算符結果的無符號整數類型; ...
C11 §7.19 2
啟用警告的良好編譯器會對此發出警告。
希望這種無限循環永遠不會發生,因為對警告的調查會首先糾正問題。
最佳選擇取決於編碼目標
好的代碼會避免像 10 這樣的幻數。最好是代碼派生出來的。 在這個簡單的例子中,它應該是 11。
#define A_SIZE 11
int array[A_SIZE];
...
for (size_t i = A_SIZE; i-- > 0; ) {
// Do something, f.ex. array[i] = i
}
OTOH,代碼可能在循環中有break
條件,需要在后面的代碼中使用i
來指示array[]
用法
size_t i = A_SIZE;
while (i > 0) {
if (...) break;
i--;
// Do something, f.ex. array[i] = i
if (...) break;
}
// Do something with i
代碼可能有一個合同要求在不同的地方使用10
。
// Contract says loop must handle indexes 0 to N, inclusive
#define N 10
int array[N + 1];
for (size_t i = N; i + 1 > 0; i--) {
// Do something, f.ex. array[i] = i
}
好的優化編譯器不會對每個i + 1 > 0
執行+1
,而是創建等效的高效代碼。
代碼是一種最能傳達代碼整體含義的時尚。
問題是在您的實現中 size_t 的類型為unsigned long
或unsigned int
。
當 i=0 條件完成並且 --i 將其轉換為 4294967295UL = ULONG_MAX,因此循環中的測試條件i >= 0
永遠不會為 false 。
size_t 有一些無符號類型,我永遠不會是負數。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.