Search code examples
c++sizestdstringunsigned-long-long-int

Assigning length of a string to an integer: C++


Using C++, I want to create a for loop as follows (text is a std::string):

 for(int i = text.size(); i >= 0; i--) {
 {

Please could somebody help me understand why my complier (Xcode) requires me to initialise i as an unsigned long, and not as integer?

I assume the following, but I don't know, and I'd like to develop a better understanding: I believe it is to do with an integer having a maximum value of 2147483647, whereas an unsigned long has a maximum value of 18,446,744,073,709,551,615. Since a string can hold up to 4294967295 characters, the use of an integer is inappropriate since its maximum value couldn't represent the maximum length of a string?

Finally, is the unsigned long data type appropriate, or should I use a long int?

My amended for loop is as follows:

 for(unsigned long i = text.size(); i >= 0; i--) {
    }

or

for(long int i = text.size(); i >= 0; i--) {
    }

Solution

  • std::string::size() returns an unsigned integer type (std::size_t). Changing the type of i is easy enough, but introduces another problem. With i being type std::size_t the loop condition is broken; by definition an unsigned type is always going to be >= 0

    There are alternatives, the most direct being to modify the entire for-loop to:

    1. Declare i as std::size_t
    2. Move the decrement as a post-decrement in the condition check
    3. Remove the increment step entirely.

    The result looks like this:

    for (std::size_t i = text.size(); i-- > 0;)
    {
        // use text[i] here
    }
    

    This will enumerate within the loop body from (text.size()-1) through 0 inclusively, and break the loop thereafter. It will work even if the string is empty.

    Note that such hijinks are a sign of a larger problem: using the wrong construct in the first place. std::string provides reverse iterators for walking the string content backward:

    for (auto it = text.rbegin(); it != text.rend(); ++it)
    {
        // use *it  to access each character in reverse order
    }
    

    Of these two methods, the second is preferred.