8.3.4. palnumber.cpp

Review

Just as the string class version of the name-box program paralleled and was structurally identical to the C-string version, the string version of the palindrome-number program parallels the C-string version. Nevertheless, the string class provides some operators that ease the implementation. Significantly, it provides a more reliable conversion from numbers to strings. Implementing the palindrome validation programs, the number-to-string conversion functions, and the reverse function, demonstrate numerous string functions and operators.

Identifying string Palindromes With The Finger Method

#define _CRT_SECURE_NO_WARNINGS					// Microsoft only
#include <iostream>
#include <string>
using namespace std;

string to_stringR2L(int n);
string to_stringL2R(int n);

int main()
{
	for (int number = 1; ; number++)			// (a/I.i and I.ii)
	{
		int	square = number * number;		// (b/II)

		// ----------------------------------		   III (c)
		string s = to_string(square);			// (c)
		//string s = to_stringR2L(square); 
		//string s = to_stringL2R(square);

		// ----------------------------------		   IV - begin case analysis
		if (s.length() < 6)				// (d/IV.i)
			continue;

		if (s[0] == '0' || s[s.length() - 1] == '0')	// (e/IV.ii)
		//if (s.at(0) == '0' || s.at(s.length() - 1) == '0')
		//if (s.find_first_of('0') == 0 || s.find_last_of('0') == s.length() - 1)
		//if (s.find('0') == 0 || s.rfind('0') == s.length() - 1)
			continue;

		// ----------------------------------		   IV.iii - palindrome solution
		int	i;					// (f)
		for (i = 0; i < s.length() / 2; i++)		// (g)
			if (s[i] != s[s.length() - 1 - i])	// (h)
				break;

		if (i == s.length() / 2)			// (i)
		{
			cout << number << " " << square << endl;
			break;
		}
	}

	return 0;
}
palnumber1.cpp: The string pal-number solution using the finger method. palnumber demonstrates the string class, but implements the same "finger method " as cpalnumber1, making the two logically and structurally equivalent. The Roman numerals in the comments correspond to the steps in the palindrome-number problem solution outline. string objects provide multiple options for performing some operations, as illustrated by the commented-out statements.
  1. Creates a sequence of candidate numbers; omitting the middle expression creates an infinite for-loop.
  2. Squares the number.
  3. The C++11 to_string(square) function converts a number to an instance of the string class.
  4. Rejects strings that are less than six characters long.
  5. Rejects strings that begin or end with a '0' (to_string doesn't put a leading 0 in the string, but the program includes the test to further the demonstration). The functions find and find_first behave the same way when the argument is a single character (see "Searching" for more detail).
  6. Defines the loop control variable outside the scope of the for-loop so that it is still in scope and usable at step (i).
  7. Compares the two characters indicated by the "left and right hands." i < s.length() / 2 divides the string in half, skipping the middle character if the number of characters is odd.
  8. s[i] and s[s.length() - 1 - i] are the left- and right-hand characters, respectively. break operates on the inner for-loop.
  9. The string is a palindrome only if "the fingers meet in the middle of the string." The break applies to the outer for-loop, ending the program.

Converting Numbers To Strings

The ANSI C++ 2011 standard added the to_string function to C++ to convert numbers to strings. Before then, the palnumber example included its own version of to_string. (I'm personally amused that the ANSI committee chose the same name and syntax for their conversion functions as I did for this longstanding example.) Although writing a to_string function is no longer necessary, it demonstrates the string class's concatenation operators.

Right To LeftLeft To Right
string my_to_stringR2L(int n)
{
    string	s;
    string	sign;

    if (n < 0)
    {
        sign = "-";
         n = -n;
    }

    do
    {
        s = (char)(n % 10 + '0') + s;
        n /= 10;
    } while (n);

    return sign + s;
}
string to_stringL2R(int n)
{
    if (n == 0)
        return "0";

    string    s;

    if (n < 0)
    {
        s += '-';
        n = -n;
    }

    for (int digit = (int)log10(n); digit >= 0; digit--)
        s += char((n / (int)pow(10, digit)) % 10 + '0');

    return s;
}
  • n % 10 extracts the rightmost digit
  • For brevity, ... stands for the previous operation
  • ... + '0' adds the ASCII code for a '0'
  • char()(...) casts the value to a character
  • ... + s concatenates the character to the left side of s
  • Example: n = 123
  • 123 % 10 = 3
  • 3 + '0' = 3 + 48 = 51
  • (char)51 = '3'
  • '3' + '' = '3'
  • Digit isolation concepts illustrates the mathematics
  • (int)log10(n) counts the digits in the number
  • (int)pow(10, digit) is the divisor for discarding the rightmost digits
  • For brevity, ... stands for the previous operation
  • n / ... discards the rightmost digits
  • ... % 10 discards digits to the left of the target digit
  • char(... + '0') converts the number to a character
  • s += ... concatenates the character to s's right side. The left-hand operand must be a string
to_stringR2L and to_stringL2R functions convert an integer to a string. The string concatenation and concatenation with assignment operators, + and +=, respectively, support the conversion process in two ways: First, the operators allow individual characters, and second, they allow concatenation on the left side in addition to the right. Both versions convert their parameter, n, to a string object by isolating each digit, converting it to an ASCII character by adding an ASCI '0' to it, and concatenating it to a string object.

Identifying string Palindromes With The Reverse Method

The reverse string solution is logically and structurally similar to the C-string version, and relies on the same definition of a palindrome as a string that reads the same forwards and backward (without considering spaces or other punctuation characters). The next example solves the palindrome-number problem based on the definition of a palindrome. It reverses the candidate string and compares it to the original. If and only if the two strings are the same (i.e., equal), the candidate is a palindrome.

#define _CRT_SECURE_NO_WARNINGS						// Microsoft only
#include <iostream>
#include <string>
using namespace std;

string reverse(string s);

int main()
{
	for (int number = 1; ; number++)				// (I.i and I.ii)
	{
		int	square = number * number;			// (II)

		string s = to_string(square);				// (III)

		//----------------------------------------------	   IV - begin case analysis
		if (s.length() < 6)					// (IV.i)
			continue;

		if (s.find('0') == 0 || s.rfind('0') == s.length() - 1)	// (IV.ii)
			continue;

		//----------------------------------------------	   IV.iii - palindrome detection
		if (s == reverse(s))
		{
			cout << number << " " << square << endl;
			break;
		}
	}

	return 0;
}
palnumber2.cpp: Solving the palindrome-number problem using the reverse method. The reverse and finger (Figure 1) solutions differ only at step IV.iii (the palindrome solution). Consequently, the following elaboration highlights that step. The next figure presents the reverse function.

 

Traditional For-Loop For-Range Loop
string reverse(string s)
{
	string r;

	for (int i = 0; i < s.length(); i++)
		r += s[s.length() - 1 - i];

	return r;
}
string reverse(string s)
{
	string r;

	for (char c : s)
		r = c + r;

	return r;
}
The string reverse function. Although the C++ string class provides many useful functions and operators, it doesn't have a reverse function. Both versions of the reverse function share three common features: First, the string that it reverses is the function's argument; second, the function creates a local string, r, where it constructs the reversed string; and finally, and lastly, they use one of the string concatenation operators to build the reverse string.
  1. The traditional for-loop version extracts the string's characters from right to left, and right-concatenates or appends them to the right side of r with the concatenation with assignment operator: +=
  2. The for-range loop version extracts the characters from left to right - in the original order. The function concatenates the extracted characters on the left side of r with the concatenation operator, +, and assigns results back to r.

Downloadable string palindrome programs and functions

ViewDownloadComments
palnumber1.cpp palnumber1.cpp string solution of the palindrome-number puzzle using the finger method
to_stringR2L.cpp to_stringR2L.cpp Number-to-string right-to-left processing order.
to_stringL2R.cpp to_stringL2R.cpp Number-to-string left-to-right processing order.
validate.cpp validate.cpp A driver validating the to_stringR2L and to_stringL2Rfunctions.
palnumber2.cpp palnumber2.cpp string solution of the palindrome-number puzzle using the reverse method
reverse.cpp reverse.cpp Function to reverse a string object