In your example, s1.length()
is evaluated to 2u
(i.e. 2
, but in an unsigned
type), s2.length()
is evaluated to 6u
, s1.length() - s2.length()
is most probably evaluated to 4294967292u
(because there is no -4
in unsigned types), and s1.length() - s2.length() + 1
is evaluated to 4294967293u
.
.length()
return size_t
in C++, which is unsigned value. Subtracting an unsigned value from another unsigned value yields an unsigned value, e.g. 1u - 2u
may result in 4294967295
.
When mixing signed and unsigned values (e.g. s.length() - 1
or i < s.length()
), the signed value is converted to an unsigned, e.g. -1 > 1u
is typically true
because -1
is converted to 4294967295
. Modern compilers will warn you about such type of comparisons if you enable warnings.
Knowing that, you may expect that your loop is running for 4 billion iterations, but that's not necessarily true, because i
is a signed int
, and if it's 32-bit (most probably), it cannot become bigger than 2147483647
. And the moment your program increases it from 2147483647
, signed overflow happens, which is undefined behavior in C++. So your loop may very well run infinitely.
I suspect you're doing competitive programming. My recommendation for competitive programming would be to always cast .length()
to int
whenever you want to calculation anything. You can create a macro like this:
#define sz(x) ((int)(x).size())
and then write sz(s)
instead of s.length()
everywhere to avoid such bugs.
However, that approach is highly frowned upon in any area of programming where code has to live longer than few hours. E.g. in the industry or open-source. For such cases, use explicit static_cast<int>(s.length())
/static_cast<ssize_t>(s.length())
every time you need it. Or, even better, ask about during code review to get specific recommendations concerning your code, there are lots of possible caveats, see comments below for some examples.