C++ | 使用 xxx.size() 作为循环条件的问题
问题代码
#include<bits/stdc++.h>
using namespace std;
int main()
{
string s="a";
printf("%d\n",s.size()-5);
cout<<s.size()-5<<endl;
for(int i=0;i<=s.size()-5;i++)
printf("ViVid-BinGo\n");
system("pause");
return 0;
}
以上是问题代码的运行结果,这时就会有问题出现了。
① 字符串 s 的大小为 1 ,那么 s.size() - 5 == -4。但是用 printf("%d") 和 cout 输出 s.size() - 5 的结果分别为 -4 和 18446744073709551612 ,显然结果并不相同。
② 不严谨的说,for循环中判断条件 0 <= -4 显然不成立,那么一句 “ViVid-BinGo” 也不会输出。但是通过运行结果可以看出,“ViVid-BinGo” 被输出出来了,而且不止输出了一次。
解决
可以从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\n",s.size()-5);
cout<<s.size()-5<<endl;
int len=s.size()-5;
for(int i=0;i<=len;i++)
printf("ViVid-BinGo\n");
system("pause");
return 0;
}
#include<bits/stdc++.h>
using namespace std;
int main()
{
string s="a";
printf("%d\n",s.size()-5);
cout<<s.size()-5<<endl;
for(int i=0;i<=(int)s.size()-5;i++)
printf("ViVid-BinGo\n");
system("pause");
return 0;
}