2010-08-14 98 views
10

我有一個循環,必須從N到0(包括)。我的i變量的類型是size_t,它通常是未簽名的。我目前使用下面的代碼:For循環條件使用無符號整數時停止在0?

for (size_t i = N; i != (size_t) -1; --i) { 
    ... 
} 

這是正確的嗎?有沒有更好的方法來處理這種情況?

謝謝,

文森特。

+1

嗯,這是一個非常好的問題。 – 2010-08-14 17:56:28

+1

'size_t'保證是無符號的,並且你對'(size_t)-1'的使用是正確的。當N等於該值時,您只有一個問題... – 2010-08-14 18:44:21

+0

{} while(i--)如何? – supercat 2010-08-14 20:41:07

回答

7

是的,這是正確的,這是一種非常普遍的做法。我不會考慮改變它。

無符號整數類型的算術保證使用模2^N算術(其中N是該類型中的值位數),並且溢出時的行爲已定義良好。通過加上或減去2^N的倍數(即模數2^N算術)將結果轉換成範圍02^N - 1

-1轉換爲無符號整數類型(其中size_t是1)轉換爲2^N - 1。對於無符號類型,--也使用模運算2^N,因此將值爲0的無符號類型遞減爲2^N - 1。你的循環終止條件是正確的。

4

您可以使用此:

for (size_t i = n + 1; i-- > 0;) 
{ 
} 

希望有所幫助。

+0

這將從'n-1'變爲0,而不是從'n'變爲0. – SoapBox 2010-08-14 17:59:34

+0

你是對的,我錯過了「包含性」的要求,那就是固定,謝謝 – KeatsPeeks 2010-08-14 18:00:57

+1

它不會在'n'爲'SIZE_MAX'的病理情況下工作。當然,你可能不希望從SIZE_MAX循環到0 ... – jamesdlin 2010-08-14 21:30:04

0

由於從零遞減時,無符號整數會滾動到其最高值,你可以嘗試以下方法,提供N是小於該最大值(有人請糾正我,如果這是UB):

for (size_t i = N; i <= N; i--) { /* ... */ } 
+0

這可能會在每次迭代時重新加載N的值,這無意中傷害了性能。 – 2010-08-15 18:22:56

+2

你從哪裏得到這個瘋狂的想法?這與'for(i = 0; i 2010-08-16 21:46:27

3
for (size_t i = N ; i <= N ; i--) { .... } 

這將做到這一點,因爲size_t是一個無符號整型。無符號整數是32位。當變量i的值爲0時,您希望您的循環執行條件。如果執行i--,計算機確實是

00000000000000000000000000000000 
-00000000000000000000000000000001 

這導致清除溢出,給出的值爲111111111 ... 1。對於一個有符號的二進制補碼整數,這個值顯然是負值。但是,我的類型是一個無符號整數,因此計算機會將111111 ... 1解釋爲一個非常大的正值。

所以,你有幾個選擇:

1),按上述並當溢出發生提前終止循環。

2)使循環從i = 0運行到i < = N,但在循環中的每個地方都使用(N-i)而不是i。例如,myArray [i]將變成myArray [N-i](取決於N實際表示的值)。

3)使for循環的條件利用一元運算符的優先級。作爲另一用戶發佈,

for (size_t i = N + 1 ; i-- > 0 ;) { ... } 

這將設置i到N + 1,檢查是否條件N + 1> 0仍然成立。它確實,但是我有一個副作用,所以i的值遞減到i = N。繼續下去,直到你到達i = 1。條件將是測試,1> 0是真的,副作用發生,那麼我= 0,它執行。

+0

請勿使用'i <= N'作爲條件。它可能會浪費時間在每次迭代時從內存中重新加載'N',並且如果'N'恰好是'SIZE_MAX',那麼您將有一個無限循環。 – 2010-08-15 18:25:21

1

您可以使用第二個變量作爲循環計數器,以使迭代的範圍對未來的審閱者清晰。

for (size_t j=0, i=N; j<=N; ++j, --i) { 
    // code here ignores j and uses i which runs from N to 0 
    ... 
} 
4

就個人而言,我只想用一個不同的循環結構,但每一個自己:

size_t i = N; 
do { 
    ... 
} while (i --> 0); 

(你可以只使用(i--)作爲循環條件,但人們不應該放過機會使用-->「運營商」)。

+1

使用' - >'運算符+1。 C代碼旨在被模糊處理,而且很有趣:) – 2010-08-15 03:27:42

5

正因爲for有一個方便的地方在每次迭代開始時進行測試並不意味着您必須使用它。要處理N到0 包括,測試應該在最後,至少如果你在意處理最大值。不要讓方便讓你把測試放在錯誤的地方。

for (size_t i = N;; --i) { 
    ... 
    if (i == 0) break; 
} 

一個do-while循環也將工作,但隨後你還放棄i被作用域循環。

1
for (i=N; i+1; i--) 
+0

請注意,除了do/while循環和/ break結構的等價物之外,如果'N'爲'SIZE_MAX',則將失敗。 – 2010-08-15 18:26:09