C语言 在循环中使用size_t时的无限循环

cs7cruho  于 2023-05-22  发布在  其他
关注(0)|答案(6)|浏览(144)

因此,我在任何索引for循环中使用size_t而不是int,以防止负索引。但当倒计时时,这会导致溢出:

for (size_t i = 10; i >= 0; --i) {
    // Do something, f.ex. array[i] = i
}

有什么好的方法可以防止这种情况发生?

  • 使用int代替?
  • 使用i == 0作为终止条件?(如果我需要0,这将不起作用)

我会很感激任何反馈!

cedebl8k

cedebl8k1#

for (size_t i = 10; i <= 10; --i) // do something

当溢出发生时,它将舍入到最大整数,因此条件将失败。

c3frrgcw

c3frrgcw2#

从技术上讲,它不是溢出,因为size_t是无符号类型,但它肯定是一个无限循环,因为终止条件始终为真。
无符号整数在0处递减时 * 环绕 *。请注意,循环将在回绕发生之前运行11次,而不是10次。
在递减索引之前必须检查条件。以比最大有效索引大一的初始值开始枚举,可以提高视觉一致性并简化测试。
下面是一个修正后的版本,你可以看到i的初始值是数组的元素数:

int array[11];
for (size_t i = 11; i-- > 0; ) {
    // Do something, f.ex. array[i] = i
}
az31mfrm

az31mfrm3#

for (size_t i = 11; i-- > 0; ) {
    // Do something, f.ex. array[i] = i
}

注意:问题以value=10开始循环(这很奇怪,但并非不可能)。我从11开始,但第一次进入循环体时,它已经递减到10了。

f2uvfpb9

f2uvfpb94#

惯用的方法是使用slide操作符,虽然不是每个人都喜欢:

for (size_t i = 10 + 1; i--> 0; )

它不是一个真正的运营商,但这就是它多年来所知道的。

0x6upsns

0x6upsns5#

size_t i = 10; i >= 0;永远不会为false,因为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,而是创建等效的高效代码。
代码是一种最能传达代码整体含义的时尚。

muk1a3rh

muk1a3rh6#

最简单的方法是增加上限值。举个例子

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 );

相关问题