【问题标题】:iterating an array backwards in For loop condition to stop at 0 when using unsigned integers causing infinite loop当使用无符号整数导致无限循环时,在 For 循环条件中向后迭代数组以在 0 处停止
【发布时间】:2016-01-25 11:30:35
【问题描述】:

我有一个必须从 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]!='\0'){
        i++;
    }


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

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


    getch();
    return 0;
}

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

【问题讨论】:

    标签: c size-t


    【解决方案1】:
    for(j=i; j>0; j--) {
        printf("%c", str[j-1]);
    }
    

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

    编辑:我想说最好的应该是 l3x 的 for(j=i; j-- &gt; 0;)
    检查 j 是否大于 0 后递减。

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

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

    【讨论】:

    • 这看起来像是一个带有奇怪格式的丑陋代码的纯粹示例。
    【解决方案2】:

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

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

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

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

    请注意,在您的情况下,您也在打印 \0 空字节,这是一个不可打印的字符。 (因为j 以等于字符串长度的值开头)。上述条件也考虑到了这一点。

    还有:

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

    【讨论】:

    • 是的,我注意到 j 应该从 i-1 开始,我已修复,谢谢
    • 谢谢我的问题已经通过很多解决方案解决了,我知道我可以使用 strlen()..但是请你向我解释为什么 mu 代码会导致无限循环?为什么如果我只是用 int 替换 size_t 输出将是正确的?size_t 有什么问题?假设循环到达 j=0 它应该打印元素零,然后应该退出,因为条件将为假,所以为什么它进入无限循环??
    • size_t,一个无符号整数不能有小于0的值。所以如果你做j--当j为0的时候,那么它会变成SIZE_MAX(size_t可以容纳的最大值) .假设 SIZE_MAX 是 4294967295,那么循环将从 j -> 0 -> 4294967295 -> 0 -> 运行,并且循环将继续。如果您使用int,它将按您的预期工作。但是size_t 是用于查找字符串长度的正确类型。因此,您将获得无限循环。如果您使用int,它将按您的预期工作。但是size_t 是用于查找字符串长度的正确类型。
    【解决方案3】:

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

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

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

    附带说明:您的第一个 while 循环与 string.h 中的 strlen() 相同。

    【讨论】:

    • j=i; do { ...; j--; } while(j != 0); 可能更具可读性。
    • ssize_t 被定义为 size_t 的签名版本。
    【解决方案4】:

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

    const size_t max = i-1; // maximum value that j can have
    
    for(j=0; j<=max; j++)
    {
      ... str[max-j];
    }
    

    【讨论】:

      【解决方案5】:

      无符号整数将在 C 中换行。任何无符号整数始终等于或大于 0,在代码中:uint &gt;= 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

      【讨论】:

        【解决方案6】:

        问题是j &gt;= 0 总是true 因为junsigned

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

        while (j-- > 0)
        

        【讨论】:

          【解决方案7】:

          无符号值环绕,因此当j == 0 和循环执行j-- 时,j &gt;= 0 仍然为真。

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

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

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

          【讨论】:

          • 虽然不是反对者,但我认为他们不喜欢你所说的方式 "...易于阅读的解决方案就像..."..while (j --&gt; 0)... which将使用户ask this question;其次,您在 字符串文字 上过度使用了strlenstr 的大小长度在编译时是已知的。
          猜你喜欢
          • 2011-03-29
          • 2017-05-02
          • 2017-03-18
          • 1970-01-01
          • 2022-08-18
          • 1970-01-01
          • 2015-07-03
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多