Making a palindrome

Pages: 12
Palindrome = number or word that has the same beginning characters as ending characters. Examples: "rotator" "racecar" "123321"

Ultimately I want to iterate over palindrome numbers, but right now I am just trying to figure out how to reverse a prefix and stick it in the suffix or the opposite of that if that is easier. To do this I believe I need a good handling of stringstreams, but I am not succeeding. The following is some code I have been playing with. I don't see why cString is empty.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>
#include <sstream>
#include <algorithm>
#include <string>

int main()
{
	std::stringstream stream;
	std::string aString = "dog";
	std::string bString;
	std::string cString;
	stream << aString;
	stream >> bString;
	std::reverse(bString.begin(), bString.end());
	stream << aString << bString;
	stream >> cString;

	// print results
	std::cout << aString << std::endl;
	std::cout << bString << std::endl;
	std::cout << cString << std::endl;
	std::cout << stream.str() << std::endl;
}


Output:
1
2
3
4
dog
god

dog
Last edited on

after line 14, adding this:

 
          stream.clear() ;



dog
god
doggod
dogdoggod
Program ended with exit code: 0
Last edited on
Why do you want to use the stringstream? It is rather problematic to use it like this.

You can do it without:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>
#include <algorithm>
#include <string>

int main()
{
	std::string aString = "dog";
	std::string bString = aString;
	std::reverse(bString.begin(), bString.end());
	std::string cString = aString + bString;

	// print results
	std::cout << aString << std::endl;
	std::cout << bString << std::endl;
	std::cout << cString << std::endl;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>
#include <sstream>
#include <algorithm>
#include <string>
 
int main()
{
        std::stringstream stream;
        std::string aString = "dog";
        std::string bString;
        std::string cString;
        stream << aString;
        stream >> bString;       stream.clear();   stream.str( "" );
        std::reverse(bString.begin(), bString.end());
        stream << aString << bString;
        stream >> cString;       stream.clear();   stream.str( "" );

        // print results
        std::cout << aString << std::endl;
        std::cout << bString << std::endl;
        std::cout << cString << std::endl;
        std::cout << stream.str() << std::endl;
}

Last edited on
You can also try to follow your code while it's working. It may help you understanding what's going on.

This is just you code with some 'couts':
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <algorithm>
#include <iostream>
#include <limits>
#include <sstream>
#include <string>


void waitForEnter();


int main()
{
    std::stringstream stream;
    std::string aString = "dog";
    std::string bString;
    std::string cString;
    stream << aString;
    std::cout << "\nstream: " << stream.str();
    stream >> bString;
    std::cout << "\nbString: " << bString;
    std::reverse(bString.begin(), bString.end());
    std::cout << "\nbString after reverse(): " << bString;
    stream << aString << bString;
    std::cout << "\nstream: " << stream.str();
    stream >> cString;
    std::cout << "\ncString: " << cString;

    // print results
    std::cout << "\naString: " << aString;
    std::cout << "\nbString: "  << bString;
    std::cout << "\ncString: "  << cString;
    std::cout << "\nstream: "  << stream.str() << '\n';

    waitForEnter();
    return 0;
}


void waitForEnter()
{
    std::cout << "\nPress ENTER to continue...\n";
    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}

using the std::string ctor with reverse iterators from the original string:
1
2
3
4
5
6
7
8
9
#include <iostream>
#include <string>

int main()
{
	std::string anyString = "dog";
	auto palindromeString = anyString + std::string{anyString.crbegin(), anyString.crend()};
	std::cout << palindromeString << "\n";
}
It may help you understanding what's going on.


When you find out, @Enoizat, please let me know! I actually thought that @Meden's original code would have worked ... but trying it proved me wrong.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
#include <algorithm>
#include <iostream>
#include <limits>
#include <sstream>
#include <string>


void waitForEnter();


int main()
{
    std::stringstream stream;
    std::string aString = "dog";
    std::string bString;
    std::string cString;
    std::cout << "\naString is " << aString
              << "; stream is "  << stream.str()
              << "; bString is " << bString
              << "; cString is " << cString << '\n';
    stream << aString;
    std::cout << "\nafter \"stream << aString;\" "
              << "aString is "   << aString
              << "; stream is "  << stream.str()
              << "; bString is " << bString
              << "; cString is " << cString << '\n';
    stream >> bString;
    std::cout << "\nafter \"stream >> bString;\" "
              << "aString is "   << aString
              << "; stream is "  << stream.str()
              << "; bString is " << bString
              << "; cString is " << cString << '\n';
    std::reverse(bString.begin(), bString.end());
    std::cout << "\nafter \"std::reverse(bString.begin(), bString.end());\" "
              << "aString is "   << aString
              << "; stream is "  << stream.str()
              << "; bString is " << bString
              << "; cString is " << cString << '\n';
    stream << aString << bString;
    std::cout << "\nafter \"stream << aString << bString;\" "
              << "aString is "   << aString
              << "; stream is "  << stream.str()
              << "; bString is " << bString
              << "; cString is " << cString << '\n';
    stream >> cString;
    std::cout << "\nafter \"stream >> cString;\" "
              << "aString is "   << aString
              << "; stream is "  << stream.str()
              << "; bString is " << bString
              << "; cString is " << cString << '\n';

    // print results
    std::cout << "\n\naString: " << aString;
    std::cout << "\nbString: "   << bString;
    std::cout << "\ncString: "   << cString;
    std::cout << "\nstream: "    << stream.str() << '\n';
    
    cString = stream.str();
    std::cout << "\n\nAnyway after \"cString = stream.str();\" "
              << "aString is "   << aString
              << "; stream is "  << stream.str()
              << "; bString is " << bString
              << "; cString is " << cString << '\n';
    
    std::cout << "\n;-)\n";

    waitForEnter();
    return 0;
}


void waitForEnter()
{
    std::cout << "\nPress ENTER to continue...\n";
    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}

Hi @Enoizat,

From the output of your code:

after "stream << aString << bString;" aString is dog; stream is dog; bString is god; cString is 

after "stream >> cString;" aString is dog; stream is dog; bString is god; cString is 


So in the first line, you write "dog" and then "god" to stream.
So one would expect stream to contain "doggod".
Then in the second line we write it back to cstring ... so we would expect cstring to also contain "doggod" .... but it doesn't: it's empty.


I checked the stream and fail bits were set when there is a << followed by the reverse operation >>. Thus
stream.clear();
is used to reset these (as pointed out by @ar2007). Previous data also seems to remain in the buffer unless you also clear that by
stream.str( "" );
(directly replacing the contents by an empty string).


I'm not suggesting that use of stringstream is a good idea here - @coder777 and @gunnerfunner both gave far simpler solutions for this particular task. I'm just left wondering why stringstream doesn't do what one might expect when you switch from << to >>.

I suspect the OP is actually going to be converting integers and strings, so these solely string operations won't be relevant.


The following also works, without having to use stream.clear(). Seemingly, stringstream just doesn't like switching between << and >>.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>
#include <sstream>
#include <algorithm>
#include <string>

int main()
{
	std::stringstream stream;
	std::string aString = "dog";
	std::string bString;
	std::string cString;
	stream << aString;
	bString = stream.str();   stream.str("");
	std::reverse(bString.begin(), bString.end());
	stream << aString << bString;
	cString = stream.str();   stream.str("");

	// print results
	std::cout << aString << std::endl;
	std::cout << bString << std::endl;
	std::cout << cString << std::endl;
	std::cout << stream.str() << std::endl;
}
Last edited on
Yes, @lastchance, I can't but confirm your analisys (as usual!).
It looks std::stringstream doesn't stand the string it 'creates' to be modified somewhere:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <algorithm>
#include <iostream>
#include <limits>
#include <sstream>
#include <string>


void waitForEnter();


int main()
{
    std::stringstream stream("dog");
    std::string aString;
    stream >> aString;
    std::reverse(aString.begin(), aString.end());
    std::cout << "\nafter \"std::reverse(aString.begin(), aString.end());\" "
              << "aString is "   << aString
              << "; stream is "  << stream.str() << '\n';
    stream << aString;
    if(!stream.good()) { std::cout << "stream problem!\n"; }
    std::cout << "\nstream << aString << aString;\" "
              << "aString is "   << aString
              << "; stream is "  << stream.str() << '\n';

    waitForEnter();
    return 0;
}


void waitForEnter()
{
    std::cout << "\nPress ENTER to continue...\n";
    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}


I suspect it depends on how overloaded operator>> is implemented:
basic_istream& operator>>( std::basic_streambuf<CharT,Traits>* sb );

But I have an appointment an I must exit. I look forward to reading your conclusion tonight!
Last edited on
I don't see why cString is empty.
The reason is the missing whitespace after "dog". On line 13: Trying to read the whitespace leads to eof error. After that it does not accept io anymore.
closed account (48T7M4Gy)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
#include <sstream>
#include <algorithm>
#include <string>

int main()
{
    std::stringstream stream;
    
    std::string aString = "dog";
    
    stream << aString;
    std::reverse(aString.begin(), aString.end());
    stream << aString;
    
    std::string bString = stream.str();
    
    std::cout << stream.str() << '\n';
    std::cout << bString << '\n';

    return 0;
}


doggod
doggod
Program ended with exit code: 0
Last edited on
closed account (48T7M4Gy)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <iostream>
#include <sstream>
#include <algorithm>
#include <string>

int main()
{
    std::stringstream stream;
    
    // **********************
    std::string aString = "dog";
    
    stream << aString;
    std::reverse(aString.begin(), aString.end());
    stream << aString;
    
    std::string bString = stream.str();
    std::cout << stream.str() << '\n';
    std::cout << bString << '\n';
    
    // ***********************
    stream.str(std::string());
    double aDouble = 0.12345;
    
    stream << aDouble;
    std::string aDbl = stream.str();
    std::reverse(aDbl.begin(), aDbl.end());
    stream << aDbl;
    
    std::cout << stream.str() << '\n';
    
    return 0;
}


doggod
doggod
0.1234554321.0
Program ended with exit code: 0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>
#include <sstream>
#include <string>
using namespace std;

template <class T> string ToString( T val )
{
   stringstream ss;
   ss << val;
   return ss.str();
}

template <class T> string palindrome( T val )
{
   string a = ToString( val );
   return a + string( a.rbegin(), a.rend() );
}

int main()
{
   string a = "dog"  ;   cout << palindrome( a ) << endl;
   int    b = 12345  ;   cout << palindrome( b ) << endl;
   double c = 3.14159;   cout << palindrome( c ) << endl;
}


doggod
1234554321
3.1415995141.3






Hmm, I really ought to get out more ...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <iostream>
#include <sstream>
#include <string>
using namespace std;

template <class T> string ToString( T val )
{
   stringstream ss;
   ss << val;
   return ss.str();
}

template <class T> string palindrome( T val )
{
   string a = ToString( val );
   return a + string( a.rbegin(), a.rend() );
}

template <class T> void palpalindrome( T val )
{
   string a = palindrome( val );
   int size = a.size();
   cout << a << '\n';
   for ( int i = 1; i < size - 1; i++ )
   {
      for ( int j = 0; j < size; j++ )
      {
         if ( j == 0 || j == i || j == size - 1 - i || j == size - 1 ) cout << a[i];
         else                                                          cout << ' ' ;
      }
      cout << '\n';
   }
   cout << a << "\n\n";
}

int main()
{
   string a = "dog"  ;   palpalindrome( a );
   int    b = 12345  ;   palpalindrome( b );
   double c = 3.14159;   palpalindrome( c );
}


doggod
oo  oo
g gg g
g gg g
oo  oo
doggod

1234554321
22      22
3 3    3 3
4  4  4  4
5   55   5
5   55   5
4  4  4  4
3 3    3 3
22      22
1234554321

3.1415995141.3
..          ..
1 1        1 1
4  4      4  4
1   1    1   1
5    5  5    5
9     99     9
9     99     9
5    5  5    5
1   1    1   1
4  4      4  4
1 1        1 1
..          ..
3.1415995141.3
Last edited on
Thanks for all the help! I had to get to sleep last night after my post. Today I have been studying your replies.

@ar2007:

after line 14, adding this:

stream.clear() ;

@coder777:

Meden:
I don't see why cString is empty.

The reason is the missing whitespace after "dog". On line 13: Trying to read the whitespace leads to eof error. After that it does not accept io anymore.

Could this be explained a bit more? I am using Visual Studio and walking through the debugger while Watching all the variables. I notice that after stream << aString;, stream's _Mystate goes from 0 to 1. Does this signify that (I am not sure how to put this.) eofbit has gone into an error state? If _Mystate might have been 2 or 3, would this signify error states of failbit or badbit respectively? If _Mystate does not apply to the state of the stream, is there something that I can Watch that does? Is it possible to see the state of the stream during debugging rather than writing periodic statements to check? My questions are partly based on information found here: http://www.cplusplus.com/reference/ios/ios/bad/

Was coder777 saying that a stream needs whitespace to know that it is terminated? I wonder though if it should be preferable to avoid getting into these error states rather than setting them back to a good state. If the stream expected whitespace, would it not be better to give it whitespace?

@lastchance:

bString = stream.str(); stream.str("");

How is stream.str("") applied in this instance? I understand that it empties the stream without clearing error state. But what exactly is the rationale of why it is used and what issues it will solve?

@coder777:

Why do you want to use the stringstream? It is rather problematic to use it like this.

My primary objective I suppose is to learn about stringstream, but I am also working on a palindrome math problem where I need to iterate over a sequence of palindromes. It is Project Euler problem number 4. https://projecteuler.net/problem=4

The reason I am using stringstream is that it seems to be the most popular answer in how one might concatenate integers. I realize I could devise a mathematical method to convert a three digit number into a six digit palindrome, but with all of the extra variables and assignments necessary for that, I wonder if it might not be better to use a string method instead.

I wrote code for the iteration of a palindrome number sequence. I based it on kemort's double type palindrome and stole std::stringstream().swap(convert); from here: https://stackoverflow.com/questions/20731/how-do-you-clear-a-stringstream-variable

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <iostream>
#include <sstream>
#include <algorithm>

int main()
{

	std::string palindrome;
	int palindromeInt = 0;
	std::stringstream convert;
	for (int prefix = 987; true; prefix--) {

		// swap convert with a default constructed stringstream
		std::stringstream().swap(convert);

		// convert = 987
		convert << prefix;

		// palindrome = "987"
		palindrome = convert.str();

		// palindrome = "789"
		std::reverse(palindrome.begin(), palindrome.end());

		// convert = 987789
		convert << palindrome;

		// palindromeInt = 987789
		convert >> palindromeInt;

		// do math on palindromeInt and return if math has desired answer;
	}
}


How is my code? Could it be improved?
Last edited on
closed account (48T7M4Gy)
How is my code?

stringstream is OK if you are trying it out just for interest sake. But I think gunners solution way above is simple, straightforward and elegant (slight exaggeration, but nevertheless)

Could it be improved?

It will be interesting to see how you apply the method of palindrome construction to PE 4. The reason is your program doesn't test for palindromicity. But that's not to say that PE 4 has to be solved in any particular way. That's the beauty and horror of PE problems
@kenmort:
It will be interesting to see how you apply the method of palindrome construction to PE 4.

My math part looks like this:

1
2
3
4
5
6
for (int divisor = 999; divisor > 99; divisor--) {
	if (palindromeInt % divisor == 0 && palindromeInt / divisor >= 100 && palindromeInt / divisor <= 999) {
		std::cout << "Answer: " << palindromeInt << std::endl;
		return 0;
	}
}

The opposite approach I suppose might look like this:
1
2
3
4
5
6
/*
Loop int factor1 999 to 100;
	Loop int factor2 (factor1 to 100);
		Check if factor1 * factor2 == palindrome;
			Save if larger than previously saved palindrome;
*/

but that might be 450,000 iterations before any palindrome checking. There is likely a way to optimize it, but I decided to just start with the largest palindrome instead. My code runs about 84,000 iterations.
closed account (48T7M4Gy)
I can see what you have done and how constructing the palindrome fits now.

I assume you construct palindromeInt using streams/strings/conversions outside your snippet.

Not a bad idea at all and it might be quicker than brute force in the other direction - try both maybe.

Good luck with it :)

Forgive me if I’m so nagging, expecially after all your fantastic codes, but, getting back to original code, I’d like to confirm what coder777 stated few posts above:
coder777 wrote:
Trying to read the whitespace leads to eof error. After that it does not accept io anymore.

Browsing around on Internet, it seams many people chanced upon troubles after having used operator>> from a stringstream. That's because, I think, the buffer is still there, as lastchance pointed out, but the position in the stream has already got to its boundary. Taking advantage of clear(), as ar2007 suggested from the very beginning, looks the most sensible choice to me, but just to emphasise that we can use a stringstream more or less how we use a file, I opted for seekg():
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include <algorithm>
#include <iostream>
#include <limits>
#include <sstream>
#include <string>

int main()
{
    std::stringstream stream;
    std::string aString = "dog";
    std::string bString;
    std::string cString;
    stream << aString;
    stream >> bString;
    if(stream.good()) {
        std::cout << "\nThe stream is an a good state.\n";
    } else {
        std::cout << "\nThe stream is in a bad state.\n";
        switch(stream.rdstate()) {
        case std::ios_base::badbit:
            std::cout << "std::ios_base::badbit seems to be set.\n";
            break;
        case std::ios_base::eofbit:
            std::cout << "std::ios_base::eofbit seems to be set.\n";
            break;
        case std::ios_base::failbit:
            std::cout << "std::ios_base::failbit seems to be set.\n";
            break;
        default:
            std::cout << "an unknown state seems to be set.\n";
            break;
        }
    }
    std::reverse(bString.begin(), bString.end());
    stream.seekg(0);
    stream << aString << bString;
    stream >> cString;

    // print results
    std::cout << aString << std::endl;
    std::cout << bString << std::endl;
    std::cout << cString << std::endl;
    std::cout << stream.str() << std::endl;

    std::cout << "\nPress ENTER to continue...\n";
    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
    return 0;
}


The stream is in a bad state.
std::ios_base::eofbit seems to be set.
dog
god
dogdoggod
dogdoggod

Press ENTER to continue...

Last edited on
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# include <iostream>
# include <string>
# include <sstream>
# include <vector>
# include <algorithm>
# include <utility>
# include <functional>

int main()
{
    int maxProduct{};

    size_t stage1Screen{}, stage2_3_Screen{};

    for (size_t i = 100; i < 999; ++i)
    {
        for (size_t j = 100; j < 999; ++j)
        {
            int num = i * j;
            int numCopy = num;

            int last = num % 10;
            while (num >= 10)
            {
                num /= 10;
            }
            if(num == last)
            //stage 1 screening
            {
                ++stage1Screen;
                std::stringstream stream;
                stream << numCopy;
                if(stream.str()[1] == stream.str()[stream.str().size()-2] &&
                   //stage 2 screening
                   stream.str()[2] == stream.str()[stream.str().size()-3])
                   //stage 3 screening

                   {
                     int pNum;
                     stream >> pNum;

                     if(pNum > maxProduct)maxProduct = pNum;
                        ++stage2_3_Screen;
                    }
            }
        }
    }

    std::cout << "stage 1 screen : " << stage1Screen << "\n";
    std::cout << "stage 2/3 screen: " << stage2_3_Screen << "\n";
    std::cout << "max palindrome number: " << maxProduct << "\n";
}
Pages: 12