C++ | 使用 xxx.size() 作为循环条件的问题

问题代码

#include<bits/stdc++.h>
using namespace std;
int main()
{
    string s="a";

    printf("%d
",s.size()-5);
    cout<<s.size()-5<<endl;

    for(int i=0;i<=s.size()-5;i++)
        printf("ViVid-BinGo
");

    system("pause");
    return 0;
}

C++ | 使用 xxx.size() 作为循环条件的问题

  

  以上是问题代码的运行结果,这时就会有问题出现了。

  ① 字符串 s 的大小为 1 ,那么 s.size() - 5 == -4。但是用 printf("%d") 和 cout 输出 s.size() - 5 的结果分别为 -4 和 18446744073709551612 ,显然结果并不相同。

  ② 不严谨的说,for循环中判断条件 0 <= -4 显然不成立,那么一句 “ViVid-BinGo” 也不会输出。但是通过运行结果可以看出,“ViVid-BinGo” 被输出出来了,而且不止输出了一次。

解决

C++ | 使用 xxx.size() 作为循环条件的问题

  可以从C++参考手册中看到,s.size() 的返回值为无符号整型。那么我们可以想到,与 s.size() 进行运算的 -5 是个有符号整型。

  当出现不同类型的变量参与运算时,那么低级类型会向上转换以至于达到同一个类型,在这里因为无符号类型比有符号类型级别高,所以 -5 应该先转换到无符号类型,然后再和 s.size() 运算。

  有无符号数转换规则:

    ① 有符号数转换为无符号数时,负数转换为大的正数,相当于在原值上加上2^n,而正数保持不变。

    ② 无符号数转换为有符号数时,对于小的数将保持原值,对于大的数将转换为负数,相当于原值减去2^n。

第一个问题

  根据有无符号数转换规则可以得出:

     -5 ---> -5 + 2^64 = 18446744073709551611‬,再加上 s.size() = 1,所以 18446744073709551611‬ + 1 = 18446744073709551612

  所以 s.size() - 5 = 18446744073709551612。

  因为使用 printf("%d") 进行输出的时候,因为“%d”的缘故,有一个强制类型转换,即将无符号类型转换成有符号类型,所以 18446744073709551612 - 2^64 = -4,所以printf输出的是 -4.

  然而在使用 cout 输出的时候没有类型转换,则直接输出,那么输出的就是 18446744073709551612 。

第二个问题

  如果第一个问题解决了,那么第二个问题就解决了。

  因为在 for 循环中,s.size() - 4 没有进行类型转换,所以等价于下面的 for 循环

  for(i = 0 ; i <= 18446744073709551612 ; i++)

  所以程序运行结果中 “ViVid-BinGo”才会被打印出来。

总结

废话不多说。

#include<bits/stdc++.h>
using namespace std;
int main()
{
    string s="a";

      printf("%d
",s.size()-5);
    cout<<s.size()-5<<endl;
    
    int len=s.size()-5;
    for(int i=0;i<=len;i++)
        printf("ViVid-BinGo
");

    system("pause");
    return 0;
}
#include<bits/stdc++.h>
using namespace std;
int main()
{
    string s="a";

      printf("%d
",s.size()-5);
    cout<<s.size()-5<<endl;

    for(int i=0;i<=(int)s.size()-5;i++)
        printf("ViVid-BinGo
");

    system("pause");
    return 0;
}