当使用导致无限循环的无符号整数时,在 For 循环条件中向后迭代数组以在 0 处停止

iterating an array backwards in For loop condition to stop at 0 when using unsigned integers causing infinite loop

我有一个必须从 j 到 0(含)的循环。我的 j 变量是 size_t 类型,通常是无符号的。

我的代码:

#include<stdio.h>
#include<conio.h>

#define SIZE 100

int main(){
    char str[SIZE];
    size_t i=0;
    size_t j;
    puts("Enter any string");
    scanf("%s",str);
    while(str[i]!='[=10=]'){
        i++;
    }


    for(j=i-1;j>=0;j--){

        printf("%c",str[j]);
    }


    getch();
    return 0;
}

我得到一个无限循环。如果我删除零的相等性,它会输出没有第一个字母的字符串的反转。那么这里有什么问题?

size_t 是一个无符号整数,它永远不会小于 0。所以 for 循环中的条件始终为真:

for(j=i;j>=0;j--)

你可以修改条件为(虽然有点难看):

for(j=i; j-- > 0;){
   ...
}

请注意,在您的情况下,您也在打印 [=15=] 空字节,这是一个 non-printable 字符。 (因为 j 以等于字符串长度的值开头)。上面的条件也可以解决这个问题。

另外:

  • 您可以使用 strlen() 而不是自己循环。
  • 如果输入读取 wad 成功,请检查 scanf() 的 return 值。

无符号整数将在 C 中换行。任何无符号整数始终等于或大于 0,在代码中:uint >= 0,始终为真。

您可以使用与 SIZE_MAX 的比较,因为这是类型 size_t 的最大值。代码将迭代并打印到 0,正如它应该的那样,然后换行到 SIZE_MAX,循环将结束。 (这假设字符串的长度不是 SIZE_MAX。)

for(j=i; j < SIZE_MAX ;j--){

    printf("%c",str[j]);
}

另请注意,您的代码打印了空字符。所以起始索引应该是 j=i-1,这与包装行为很好地配合,因为如果字符串的长度是 0,for 循环将不会打印任何东西,因为 i-1 == SIZE_MAX.

for(j=i; j>0; j--) {
    printf("%c", str[j-1]);
}

将是另一种选择。
对于初学者来说可能更容易理解。
但其他答案会更好。

编辑:我认为最好的是 for(j=i; j-- > 0;) by l3x。
检查 j 是否大于 0 后递减 j。

使用 do{}while() 循环也可以。

j = i;
do {
   j--;
   printf("%c", str[j]);
} while (j > 0);

您可以将 jsize_t 更改为 long,这可确保所有数据仍然适合,并且您可以达到 -1 值。

另一种选择是使用以下语句结束 for 循环:

for (j = i - 1;;--j)
{
    // code
    if (j == 0) break;
}

作为 side-note:您的第一个 while 循环与 string.h 中的 strlen() 相同。

递减计数循环往往会变得有点晦涩难懂。考虑改用此替代方法:

const size_t max = i-1; // maximum value that j can have

for(j=0; j<=max; j++)
{
  ... str[max-j];
}

无符号值环绕,所以当 j == 0 并且循环执行 j-- 时,j >= 0 仍然为真。

一个基本且易于阅读的解决方案如下:

void reversePrint(char str[])
{
    size_t j = strlen(str);
    while (j-- > 0)
        printf("%c", str[j]);
}

将以相反的顺序打印字符串:olleH.

问题是 j >= 0 总是 true 因为 junsigned

当用 unsigned 倒数到零时,我通常使用后缀 --:

while (j-- > 0)