The demonstrations appearing in this section implement the algorithms developed in the previous section and rely on previously introduced concepts. Please review the following as needed:
%
()
itoa
function, implying that some compilers don't support it and that it goes by various names. Figure 3 implements a simple itoa version.
_itoa(int value, char* s, int base)
: a common version. The arguments are (l to r): the number to convert, the C-string to hold the converted number, and the radix or base (i.e., base-10) of the converted number._itoa_s(int value, char* s, int size, int base)
: Microsoft's safe or secure version. The third parameter is the size of the C-string array or buffer.cpalnumber.cpp presents two C-string-based programs that solve the Palindrome-Number Problem. Both programs follow the solution outline formed in that section, and each program implements one of the algorithms developed there. The first program (Figure 1) uses a single C-string and compares pairs of characters in it. The second program (Figure 3) copies the C-string that contains a potential palindrome, reverses it, and then compares the original and the reversed C-strings for equality.
#include <iostream> #include <cstring> using namespace std; int main() { for (int number = 1; ; number++) // (a/I.i and I.ii) { int square = number * number; // (b/II) //---------------------------------------------- III char s[100]; // (c) //_itoa(square, s, 10); // (d) _itoa_s(square, s, 100, 10); // (e) //---------------------------------------------- IV if (strlen(s) < 6) // (f/IV.i) continue; if (s[0] == '0' || s[strlen(s) - 1] == '0') // (g/IV.ii) continue; //---------------------------------------------- IV.iii int i; // (h) for (i = 0; i < strlen(s) / 2; i++) // (i) if (s[i] != s[strlen(s) - 1 - i]) // (j) break; if (i == strlen(s) / 2) // (k) { cout << number << " " << square << endl; // (l) break; } } return 0; }
i < strlen(s) / 2
divides the string in half, skipping the middle character if the string length is odd.s[i]
, to the character pointed to by the right hand, s[strlen(s)-1-i]
. The loop continues while each pair of characters matches, but the string is not a palindrome if a pair of characters is different, which ends the palindrome test.So, what happens if you use a compiler that doesn't support any version of itoa? You can find its source code on the internet, but we can also write a simple version. Given an integer, our task is to convert that integer into a string that looks like the number. We must convert each digit of the number into the ASCII character that represents that digit and then sequence the characters together to form a string.
The solution involves working with an integer one digit of the number at a time. If we work from left to right, the resulting string will contain the digits in the correct order. However, working from left to right is more difficult because we don't know how many digits are in the number, making it difficult to isolate them. Working from right to left is easier, but doing so converts the digits to characters in the reverse order. So, we'll use a stack to reverse the digits. (Download links to the stack code used here are found at the bottom of the Automatic Stack Implementation page.)
Before we can use our itoa function, we must modify the cpalnumber.cpp code in Figure 1 in three ways:
#include "stack.h"
void itoa(int n, char* s);
_itoa_s(square, s, 100, 10);
with a call to our function: itoa(square, s);
void itoa(int n, char* s) // (a) { bool sign = n < 0; // (b) stack st; // (c) init_stack(&st); // (d) if (sign) // (e) n = -n; // converts the number to characters do // (f) { push(&st, (char)(n % 10 + '0')); // (g) n /= 10; // (h) } while (n); // (i) if (sign) // (j) push(&st, '-'); // reverses the characters & makes the C-string int index = 0; // (k) while(size(&st) > 0) // (l) s[index++] = pop(&st); // (m) s[index] = '\0'; // (n) }
n % 10
isolates the one's digit. The key is remembering how the
mod operator works.
If we use 123 as an example, 123 % 10 = 3
(10 divides 123 12 times with a remainder of 3)+ '0'
adds the ASCII code for a character '0' to the numeric value produced by the previous expression. Continuing the previous example, 123 % 10 = 3 and the ASCII code for '0' (from an ASCII table) is 48; so, 3 + 48 = 51
(char)51
casts the numeric 51
to a character '3'push(&st, . . .);
pushes the character onto the stack defined at step (c)123 / 10 = 12
(using integer division), and the operation with assignment stores 12 back into n123 % 10 = 12
, 12 % 10 = 1
, and finally 1 % 10 = 0
pop(&st)
pops one character off the stack and returns its[index++]
stores a character at the current index location in s and then increments indexA palindrome is a string that reads the same forwards and backward. The program described below relies on that definition to solve the palindrome-number problem. The solution copies the candidate string, reverses it, and then compares it to the original string. If the two are the same (i.e. if they are equal), then the candidate string is a palindrome; if the two are not the same, then the candidate is not a palindrome.
This version of the program leaves in place the itoa
function written above, but you may switch back to _itoa_s if you wish. The reverse solution (Figure 3) has a great deal in common with the "finger" solution (Figure 1), so only the changed code is described. The code for reverse
function is presented in Figure 4.
#define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <cstring> using namespace std; void itoa(int n, char* s); void reverse(char* s); int main() { for (int number = 1; ; number++) { int square = number * number; char s[100]; itoa(square, s); if (strlen(s) < 6) continue; if (s[0] == '0' || s[strlen(s) - 1] == '0') continue; char r[100]; // (a) strcpy(r, s); // (b) reverse(r); // (c) if (strcmp(s, r) == 0) // (d) { cout << number << " " << square << endl; break; } } return 0; }
r = s;
, will copy the address stored in s to r but will not copy the contents or charactersCaution
if (r == s)
will compile but does NOT test the contents of the two C-strings for equality. Both r and s are character arrays, and (like all arrays) the array names are addresses, so r == s returns true if and only if r and s refer to the same C-string. So, r == s will always be false in this program!
You should carefully compare the body of the reverse function with the "finger" loop in the first version of the program. Although the two versions of the program seem to approach testing for a palindrome in quite different ways, their code is quite similar! The key to understanding this function is to notice that the loop only goes to the middle of the string. What would happen if we allowed the loop to go to the end of the string?
void reverse(char* s) // (a) { for (size_t i = 0; i < strlen(s) / 2; i++) // (b) { char temp = s[i]; // (c) s[i] = s[strlen(s) - 1 - i]; // (d) s[strlen(s) - 1 - i] = temp; // (e) } } |
![]() |
"A palindrome is a word, number, phrase, or other sequence of characters which reads the same backward as forward...Sentence-length palindromes ignore capitalization, punctuation, and word boundaries." Our previous palindrome detection algorithms are not robust enough to detect these general palindromes. Fortunately, we only need to filter out the spaces and punction characters and convert all the alphabetic characters to the same case. Once these steps are complete, either of our palindrome algorithms will work.
bool is_palindrome(const char* s) { // filter char temp[1000]; // store the filtered C-string int j = 0; // filters punctuation, converts case for (size_t i = 0; i < strlen(s); i++) if (isalnum(s[i])) temp[j++] = tolower(s[i]); temp[j] = '\0'; // null terminate temp // check for palindrome char r[1000]; // an array to hold the reversed C-string strcpy(r, temp); // copy the candidate temp to r reverse(r); // reverse C-string r return strcmp(r, temp) == 0; // s is a palindrome if r and temp are equal }
isalnum
returns true if s is an alphabetic or digit character. tolower
converts upper case letters to lower case but does not affect other characters. You can also replace tolower
with toupper
. The "reverse" palindrome algorithm tests the filtered string.
All source code files are formatted with 8-character tab stops.