Search code examples
c++algorithmloopsiteratorstdstring

Capitalizing letters


I have got a small problem. I want to capitalize on doubled letters in a string. I managed to compile a program, but not successfully.

#include <iostream>
#include <cctype>
#include <string>

std::string::iterator function(
   std::string::const_iterator a, 
   std::string::const_iterator b,
   std::string::const_iterator e)
{
   for (; a < b; a++) 
   {
      if (*a == *(a + 1)) 
      {
         toupper(*a);
         toupper(*(a + 1));
      }
   }
}

int main()
{
   std::string in = "peppermint 1001 bubbles balloon gum", out(100, '*');
   auto e = function(in.cbegin(), in.cend(), out.begin());

   int n = e - out.begin();
   std::string s = out.substr(0, n);
   bool b = (s == "pePPermint 1001 buBBles baLLOOn gum");
   std::cout << std::boolalpha << b << std::endl;
}

What do I do wrong?


Solution

  • You have a couple of issues there.

    Firstly, your function promised to return std::string::iterator

    std::string::iterator function(....)
    {
      //... return statement is missing here!
    }
    

    and you are not keeping the promise. This will leads to undefined behaviour. For example, in your case, it just compiles and does not give the output.

    In order to get a defined behaviour, you should return from the function

    std::string::iterator function(...)
    {
       // ... code
       return {}; // return appropriately iterator of std::string
    }
    

    Secondly, you want to modify the characters of the string, which requires a modifiable iterator rather than std::string::const_iterator.

    Then in the loop, you need to alter the capitalized charector by reassigning to it. For example:

    *a = toupper(*a);
    

    Thirdly, you should be careful about doing this in the for-loop of your function

     for(; a < b; a++)
     {
         if(*a == *(a + 1))  // --->here
         // ... code
     }
    

    What would happen for the case when a== str.end()-1, you still would do the increment(i.e. *(a + 1)), right?. Incrementing the end iterator again leads you Undefined behaviour.

    In that case, you could use std::next from <iterator> header to safely check this.

    Following is the demonstrative code which clears the issues mentioned above:

    #include <iostream>
    #include <string>
    #include <iterator>  // std::next
    
    std::string::iterator function(
       std::string::iterator a, 
       std::string::iterator b, 
       std::string::iterator e)
    {
       auto beg = a;
       for (; a < b; a++)
       {
          if (std::next(a) != b && *a == *std::next(a)) {
             *a = toupper(*a);
             *std::next(a) = toupper(*std::next(a));
          }
       }
       std::cout << std::string{ beg, b };
       return {}; // return appropriately iterator of std::string
    }
    

    prints for now: https://godbolt.org/z/ZsLHxw

    pePPermint 1001 buBBles baLLOOn gum
    

    I assume that you want somehow to get the output to the third function parameter std::string::iterator e. I will let that part for you to figure it out. Meanwhile, have a look at the standard algorithm function std::transform, which might be handy to do such kind of transformation.