Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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--) {
    }
like image 434
Ian Thompson Avatar asked Dec 22 '22 15:12

Ian Thompson


2 Answers

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.

like image 69
WhozCraig Avatar answered Dec 27 '22 10:12

WhozCraig


As noted in the comments, the size() member function of the std::string class returns a value of type size_t. The exact nature of this type will vary between platforms and compilers, but it will always be an unsigned type. Generally, it is equivalent to either unsigned long int or unsigned long long int.

So, to avoid the compiler warning about initialising your int i, you should declare that loop index as a size_t variable: for (size_t i = text.size(); ....

However, as also noted in the comments, your loop test condition (i >= 0) is then no good, because, for any unsigned type, that condition can never be false. So, instead, you should change that condition to i > 0; you should also be sure that any access to your test elements based on that i variable should use the index value i - 1 (rather than just i): the last element will be at size - 1 and the first element will be at 0, so your loop will hold for the following:

for (size_t i = text.size(); i > 0; --i) {
    char element = text[i - 1]; // We need to offset our loop index by -1 ...
    // Do something with or to 'element'
    // ...
}
like image 33
Adrian Mole Avatar answered Dec 27 '22 10:12

Adrian Mole