简体   繁体   中英

Splitting up a string from end to start into groups of two in C++

I was curious about the way I could make a program, that takes a string, then detects the end of it, and then starts splitting it up "from end toward the start", into the groups of two? For instance, the user enters mskkllkkk and the output has to be m sk kl lk kk .

I tried to search the net for the tools I needed, and got familiar with iterators, and tried to use them for this purpose. I did something like this:

#include "iostream"
#include "string"
#include "conio.h"

int main() {
    int k=0,i=-1;
    std::string str1;
    std::string::iterator PlaceCounter;
    std::cin >> str1;
    PlaceCounter = str1.end();
    for (PlaceCounter; PlaceCounter != str1.begin(); --PlaceCounter)
    {
        ++k;
        if (k % 2 == 0 && k-1 != 0) {
            ++i;
            str1.insert(str1.end()-k-i,' ');
        }
    }
    std::cout << str1;
    _getch();
return 0;
}

At first, it seemed to be working just fine when I entered a couple of arbitrary cases(Such thing can exactly be used in calculators to make the numbers more readable by putting each three digits in one group, from the end toward the start), But suddenly when I entered this: jsfksdjfksdjfkdsjfskjdfkjsfn , I got the error message:" String iterator not decrementable ".

Presumably I need to study much more pages of my book for C++ to be able to solve this myself, but for now I'm just being super-curious as a beginner. Why is that error message? Thanks in advance.

When you insert() into your string the iterators to it may get invalidated. In particular all iterators past the insertion point should be considered invalidated in all cases but also all iterators get invalidated if the std::string needs to get more memory: the internal buffer will be replaced by a bigger one, causing all existing iterator (and references and pointers) to string elements to be invalidated.

The easiest fix to the problem is to make sure that the string doesn't need to allocate more memory by reserve() ing enough space ahead of time. Since you add one space for every two characters, making sure that there is space for str1.size() + str1.size() / 2u characters should be sufficient:

str1.reserve(str1.size() + str1.size() / 2u);
for (auto PlaceCounter = str1.end(); PlaceCounter != str1.begin(); --PlaceCounter) {
    // ...
}

Note that your algorithm is rather inefficient: it is an O(n 2 ). The operation can be done with O(n) complexity instead. You'd resize the string to the appropriate size right from the start, filling the tail with some default characters and then copy the content moving from the end directly to the appropriate location.

str1.insert(str1.end()-k-i,' ');

This modifies the string the loop is iterating over. Specifically, this inserts something into the string.

With a std::string , much like a std::vector , insertion into a string will (may) invalidate all existing iterators pointing to the string. The first insertion performed by the shown code results in undefined behavior, as soon as the existing, now invalidated, iterators are referenced afterwards.

You will need to either replace your iterators with indexes into the string, or instead of modifying the existing string construct a new string, leaving the original string untouched.

Here is a possible C++ approach to try. From my tool bag, here is how I insert commas into a decimal string (ie s is expected to contain digits):

Input: "123456789"

// insert comma's from right (at implied decimal point) to left
std::string digiCommaL(std::string s)
{
   // Note: decrementing a uint (such as size_t) will loop-around, 
   //       and not underflow.  Be sure to use int ...

   int32_t sSize = static_cast<int32_t>(s.size()); // change to int
   //      ^^^^^-----------_____
   if (sSize > 3)          vvvvv
      for (int32_t indx = (sSize - 3); indx > 0; indx -= 3)
         s.insert(static_cast<size_t>(indx), 1, ',');

   return(s);
} 

Returns: "123,456,789"

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM