Here's a code to find out if the number is palindrome or not.

#include <stdio.h>

int main()
{
	int num,chknum1,chknum2=0,i,rmndr;/*here rmndr is remainder after mod,chknum is reversed num*/
	printf("enter the number");
	scanf("%d",&num);
	chknum1=num;/*saving num,since it is manipulated*/
	for(i=0;i<=sizeof(chknum1);i++)
		{
			rmndr=num%10;
			num=num/10;
			chknum2=chknum2*10+rmndr;
		}
	printf("chknum1 %d,chknum2 %d",chknum1,chknum2);
	//if(chknum1=chknum2)
		//printf("Is palindrome");
	//else
		//printf("is not palindrome.");
	return 0;
}

But it prints couple of extra zeros when the number is reversed,hence will fail to tell if the number is palindrome or not.
Can anyone tell me what am I missing?

Recommended Answers

All 24 Replies

I was assuming that the sizeof(int) will give the number of digits in the number,but
now I know I was wrong(It returns the size of the var in bytes).
Is there a way(builtin library functions,methods..etc.) to find the number of digits in the integer?Or I have to write a separate function for that.

Is there a way(builtin library functions,methods..etc.) to find the number of digits in the integer?

Nope, you have to write that yourself. Though you can certainly use standard library functions to make it easier (log10() for example).

There could be usefull and easier stop condition based on num considering line:

num=num/10;

for loop and the i variable are not good fit for the purpose. I suggest while instead.

You could also convert the number to a string and count the characters or get the strlen();

Is that giving too much away?

You could also convert the number to a string and count the characters or get the strlen();

Is that giving too much away?

Food for thought: converting a number to a string involves locating and interpreting each digit, which is only a short leap from counting the digits. So you're adding unnecessary steps to the process, presumably for the sake of simplicity. There's no doubt that it's simple, but all of the work you're doing is likely to be dreadfully slow relative to other solutions.

Yes, there *is* a lot involved in the string method:

#include <stdio.h>
#include <string.h>

int main()
{
	const int MAX_NUM_LEN = 128;
	char strNumIn[MAX_NUM_LEN] = "";
	char strNumOut[MAX_NUM_LEN] = "";
	
	int num = 0;
	int iLen = 0;
	int iPos = 0;
	
	printf("Enter the number: ");
	scanf("%d", &num);
	sprintf(strNumIn, "%d", num);
   
	iLen = strlen(strNumIn);
	iPos = (iLen-1);
	
	/* reverse the string */
	strNumOut[iLen] = '\0';
	for(int i=0; i < iLen; i++)
	{
		strNumOut[iPos--] = strNumIn[i];
	}
	
	printf("%s %s a palindrome", strNumIn,
		(!strcmp(strNumIn, strNumOut) ? "is" : "is NOT"));

   return 0;
}

Really much simpler the original way (but we should not give full solutions):

#include <stdio.h>
#include <stdlib.h>

int main() {
	int num, checknum, checknum2 = 0;
	printf("enter the number: ");
	scanf("%d",&num);
	checknum = num;/* copying num,since it is manipulated */
	while(checknum){
            checknum2 = checknum2 * 10 + checknum % 10;
            checknum /= 10;
        }
	printf("%i is %spalindrome", num, num == checknum2 ? "" : "not ");
	return EXIT_SUCCESS;
}

Excellent!

I had done it like this,

unsigned int is_palindrome(unsigned int);
unsigned int Siz_of(int);

unsigned int is_palindrome(unsigned int num)/* checks if the number(+ve integer only) is palindrome or not*/
{

	int chknum1,chknum2=0,i,rmndr;/*here rmndr is remainder after modulo,chknum is reversed num*/


	chknum1=num; /*saving num,since it is manipulated*/

	for(i=0;i<Siz_of(chknum1);i++)
		{
			rmndr=num%10;
			num=num/10;
			chknum2=chknum2*10+rmndr;
		}


	if(chknum1==chknum2)
		return(1);
	else
		return (0);

}

unsigned int Siz_of(int n)
{  int sum = 0,i,res;
   res=n;

   if (n<=-1)
	   n=-(n);
   for(i=1;i<n;i++)
	   {
		   res=res/10;
		   sum++;
		   if(res==0)
			   break;
		}
	return (sum);
}

but pyTony's is more effiecient.I'll use that instead for sure.

for loop and the i variable are not good fit for the purpose. I suggest while instead.

I know how to use while loop but have never used it like
this way: while(i) when I write my own(though I have seen others' many times)
instead I only use while loops like
this way : while(i<3)
What does the line

while(checknum)

mean?
Does it mean that the loop will be terminated if checknum==0.

It is little hackish as it uses the knowledge that 0 is considered False while all other values are considered True, so it is same as:

while(checknum != 0)

So you understood it correctly.

Actually I would also rename checknum as numbers_left and checknum2 as reversed_number. Also better to put the action (the while loop) in separate is_palindrome_number funcion, which has no input or output as you had done in your code.

#include <stdio.h>
#include <stdlib.h>

int is_palindrome_number(int original) {
    int numbers_left = original, reversed_number = 0;
    while(numbers_left){
        reversed_number = reversed_number * 10 + numbers_left % 10;
        numbers_left /= 10;
    }
    return original == reversed_number;
}

int main() {
    int num;
    printf("enter the number: ");
    scanf("%d",&num);
    printf("%i is %spalindrome", num, (is_palindrome_number(num) ? "" : "not "));
    return EXIT_SUCCESS;
}

and what about

while(!checknum)

That means while checknum is zero. The test we use is opposite of this !!checknum == checknum (except !!checknum is always 0 or 1)

Actually, Tony, I wouldn't recommend that solution at all. By building the reversed number you're limiting the range of possible input values because the reversed number might overflow. For example, an original of 12,345 would be acceptable as an original, but when reversed to 54,321 would overflow a 16-bit int.

Somewhat less importantly, but still of concern is trailing zeros will not become leading zeros, they'll be removed entirely such that the algorithm would hit a false negative. This may or may not be a bug, depending on the requirements. If it's a bug, the best solution is to accept a string rather than an int to avoid leading zeros being ignored. If still accepting an int, you need to decide if trailing zeros are to be considered significant, since a number with trailing zeros would never be a palindrome. In my opinion that's something that would be up to the caller.

A better solution would be to merge the steps of extracting digits and testing them, much like you would do with a string:

int is_palindrome_number(int original, int radix, int keep_trailing)
{
    int n, mask, i;
    
    if (!keep_trailing) {
        /* Treat trailing zeros as insignificant */
        original = trim_zeros(original, radix);
    }
    
    n = n_digits(original) - 1;
    mask = imask(n, radix);
    
    for (i = 0; i < n; i += 2) {
        int lefty = abs(original / mask);
        int righty = abs(original % radix);
        
        if (lefty != righty)
            return 0;
        
        original %= mask;
        original /= radix;
        mask /= squared(radix);
    }
    
    return 1;
}

The overflow issue is correct, but I am debth here with your code, especially how n_digits gets to know the radix, so I go back to forum of more suitable language to me.

especially how n_digits gets to know the radix

That's an oversight on my part. ;) It's easily fixed, but since I didn't post the implementation for my helper functions (to avoid giving everything away), you can just change the line to this and pretend it works:

n = n_digits(original, radix) - 1;

That's an oversight on my part.

I got the overflow thing too but rest of it went over my head.

I've got another example here using string.

#include <stdio.h>
#include <string.h>

int main()
{
	char number[20];
	int l,i,j,flag=1;
	printf("enter the number");
	fgets(number,20,stdin);


	l=strlen(number);
	for(i=0,j=l-1;i<l/2;i++,j--)
		{
			if(number[i]!=number[j])
				{
					flag=0;
					break;
				}
		}
	if(flag)
		printf("Is Palindrome number");
	else
		printf("not a palindrome");

	return 0;
}

Here's a problem

char number[20];

How can we make it more flexible (accept larger numbers)?

Here is my basic code simplified from general palindrome code, I added check for number. Coded my own as the googled code looked so stupid. I consider you showing effort by posting running code earlier, so this is fully working code. Got mystified with the newline stuff from fgets for a while.

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <errno.h>


int isnumber(char* p) {
    while(*p >= '0' && *p <= '9') {
            p++;
    }
    return *p == '\0';
}

int is_palindrome(char* sentence){
    char* front;
    char* back;
    front = sentence;
    back = &sentence[strlen(sentence) - 1];
    for(;front < back + 1; front++, back--){
        if (*front != *back) return 0;
    }
    return 1;
}

int main(){

    char num[BUFSIZ];

    printf("enter the number: ");

    if(!fgets(num, BUFSIZ, stdin)){
        printf(strerror(errno));
        return EXIT_FAILURE;
    }

    // seems to need null setting in the end or it is '\n'
    num[strlen(num)-1] = '\0';

    if(!isnumber(num)){
        printf("Non-numeric input %s", num);
        return EXIT_FAILURE;
    }


    printf("%s is %spalindrome", num, (is_palindrome(num) ? "" : "not "));
    return EXIT_SUCCESS;
}

How can we make it more flexible (accept larger numbers)?

That question can be generalized to how can we accept strings of arbitrary length? You can still use fgets(), but there's more work involved because now we need to account for strings that exceed the buffer size. Obviously this involves dynamic allocation of memory:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char *get_line(FILE *in)
{
    char *mem = NULL; /* Input string returned to caller */
    char buf[BUFSIZ]; /* Temporary buffer for substrings */
    size_t cap = 0;   /* Current capacity of mem */
    
    /*
        Read and append substrings until a newline
    */
    while (fgets(buf, sizeof buf, in) != NULL) {
        size_t len = strlen(buf);
        char *save = NULL;
        
        /* Make room to append the substring */
        save = realloc(mem, cap + len + 1);
        
        if (save == NULL)
            break;
            
        mem = save;
        
        /* strcpy() instead of strcat() simplifies '\0' logic */
        strcpy(mem + cap, buf);
        cap += len;
        
        if (mem[cap - 1] == '\n') {
            /* The newline is no longer meaningful */
            mem[cap - 1] = '\0';
            break;
        }
    }

    return mem;
}

int main(void)
{
    char *p;

    while ((p = get_line(stdin)) != NULL) {    
        printf(">%s<\n", p);
        free(p);
    }
    
    return 0;
}

@Tony

int isnumber(char* p) {
    while(*p >= '0' && *p <= '9') {
            p++;
    }
    return *p == '\0';
}

I'll assume that by a "number", you aren't allowing any kind of sign notation. Otherwise, your code doesn't account for a leading '-' or '+'. Anyway, there are a few issues.

  • isnumber is a reserved identifier. You can fix that by adding an underscore between "is" and "number".
  • The string isn't modified in this function, so it would be better practice to pass it as const char*.
  • The standard library already provides isdigit()

I'd write something more like this:

int is_number(const char *p)
{
    while (isdigit((unsigned char)*p))
        ++p;

    return *p == '\0';
}
char* front;
char* back;
front = sentence;
back = &sentence[strlen(sentence) - 1];

Is there any particular reason you aren't simply initializing the pointers?

char* front = sentence;
char* back = &sentence[strlen(sentence) - 1];
printf("enter the number: ");

Unless you're printing a newline, fflush() is warranted to ensure that the prompt shows before fgets() blocks for input:

printf("enter the number: ");
fflush(stdout);
num[strlen(num)-1] = '\0';

fgets() will not store a newline if the buffer is full, so it's better to check that you have a newline before overwriting it. The purpose of that newline is so that we can verify whether or not a partial line was read. You'll most often see just a conditional removal, which is fine in example code:

while (fgets(buf, sizeof buf, stdin) != NULL) {
    char *nl = strchr(buf, '\n');

    if (nl != NULL)
        *nl = '\0';

    ...
}

For speed, strchr() has generally tested better than other options, but I often prefer the one-liner approach despite it being slower (not forgetting that the code is I/O bound in the first place):

while (fgets(buf, sizeof buf, stdin) != NULL) {
    buf[strcspn(buf, "\n")] = '\0';

    ...
}

In production code, you're more likely to see either an arbitrary length function like I showed above, or logic to check for and handle partial lines as an error.

Thanks to both of you guys for posting your codes.
pyTony‘s code works fine (except string.h is missing) and also considering issues pointed out by Narue.

I was thinking about dynamic allocation , but couldn’t figure out how to do it (especially reallocating logic) since I have no experience whatsoever. So Narue’s code taught me another new thing.

Yes, exactly.

Thanks for Goddess Narue for her divine advice, here is my trying to apply it and also dropping those stupid strlen functions:

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <errno.h>
#include <strings.h>


int get_number_len(char* p){
    // length of string of digits ending in '\n' without terminator
    // (will be tranformed to '\0' and length returned, rest of string ignored)
    // return 0 for non-number -1 for number not ending with '\n'
    int numlen=0;
    while(isdigit((unsigned char)*p)  && numlen <= BUFSIZ) {
            p++;
            numlen++;
    }
    // fix newline out and do not accept unfinnished
    if (*p == '\n') {
        *p= '\0';
        return numlen;
    } else {
        //printf("Letter %i, numlen %i\n", *p, numlen);
        if(numlen == BUFSIZ - 1) return *p == '\0'?  -1 : BUFSIZ - 1;
        return -1;
    }
}

int is_palindrome(char* number, int number_length){
    char* front = number;
    char* back = number + number_length - 1;
    for(;front < back + 1; front++, back--){
        if (*front != *back) return 0;
//        printf("%c%c\n", *front, *back);
    }
    return 1;
}

int main(){

    char num[BUFSIZ];
    int number_length;

    printf("enter the number (max length %i): ", BUFSIZ - 1);
    fflush(stdin);

    if(!fgets(num, BUFSIZ, stdin)){
        printf(strerror(errno));
        return EXIT_FAILURE;
    }

    // seems to need null setting in the end or it is '\n'
    number_length = get_number_len(num);

    if(number_length < 1){
        if(number_length==0){
            printf("Non-numeric %s", num);
        } else {
            printf("Too long input");
        }
        return EXIT_FAILURE;
    }

//    printf("number_length: %i\n", number_length);
    printf("%s, number of length %i, is %spalindrome", num, number_length, (is_palindrome(num, number_length) ? "" : "not "));
    return EXIT_SUCCESS;
}

The dynamic version I will surely save in most holy sectors of my hard disk protected by all the daemons! ;)

#include <strings.h>

Probably just a typo, but it's <string.h> .

while(isdigit((unsigned char)*p)  && numlen <= BUFSIZ) {

It's not really a good practice for a function to make unwarranted assumptions about the arguments. The assumption that BUFSIZ is in any way meaningful for string p is unwarranted, and actually puts a limitation on callers to provide at least that much or guarantee that the number of digits doesn't exceed that limit.

Since we're already assuming that p represents a valid string, there's no need to do any extra tests. The first half of the condition will fail on '\0'. Likewise, your games with BUFSIZ later in the function are an unneeded complication:

int get_number_len(char* p)
{
    int n = 0;

    while (isdigit((unsigned char)*p)) {
        ++n;
        ++p;
    }

    if (*p == '\n')
        *p = '\0';

    return n;
}

Though I would also point out in a code review that your get_number_len() function pulls double duty of counting digits and removing a trailing newline, which isn't a good design, especially since the removal of a trailing newline is silent (only knowable by reading the comment).

int is_palindrome(char* number, int number_length){

Once again, number isn't modified so you should make it a pointer to const char. Const correctness is important because it protects you from yourself and gives callers of the function confidence in passing string literals.

printf("enter the number (max length %i): ", BUFSIZ - 1);
fflush(stdin);

Ack! I double checked and my statement about fflush() quite clearly had an example of fflush(stdout) . Not only does fflush(stdin) not do what you want in this case, it's also undefined behavior because fflush() is only specified to work on output streams.

printf(strerror(errno));

perror() will do this for you.

Though I would also point out in a code review that your get_number_len() function pulls double duty of counting digits and removing a trailing newline, which isn't a good design, especially since the removal of a trailing newline is silent (only knowable by reading the comment).

On the contrary, by magic numbers 0 and -1 as error codes, it loudly complains if it can not remove the newline or non-number is encountered. I hate that function that surely must traverse through all string and so know the length of string throws away the information and force us to scan the string again to get length of the string in palindrome function or do another scan of string for newline or not checking. So I included it in function. As function name

parse_next_number_terminated_by_newline_and_return_the_length_or_error_code

seemed little unusable, so I did compromize with naming added by comment in function for input (which is newline terminated number). Side effect of ending the string similartly to strtok seemed reasonable trade off, instead of leaving the caller to do manually the operation every time after receiving length > 0. Of course in principle I would agree that side effects are nasty, but C language seems to be full of them.

Changed function name with end _len clearly points that this is not is_number function, but is function to verify valid number ending in newline while counting the length of number and returning magic number return codes 0 and -1. It is not accepting zero terminated input except in rare case that number is exactly the length of buffer - 1 so that newline does not fit but null does, I tested this by doing global replace of BUF_SIZ by small constant to make it easier to test the corner case of exactly maximum length of input with no space for newline available. For me it is logical as returning length of number (be it is in string format) does not make sense if input is not valid number. Input validity is not assumed, of course it is assumed to point one string somewhere.

I would have liked to eliminate the checking the limit. Your version of function does not satisfy the specification as it does not tell input overflowed the buffer, but checks the beginning of string for palindrome silently ignoring the invalidity of number.
(Tested by adding

// debug, remove after debug !!!
#undef BUFSIZ
#define BUFSIZ 5

after the includes, result of my main program:

enter the number (max length 4): 122132342342
1221, number of length 4, is palindrome
Process returned 0 (0x0)   execution time : 11.688 s
Press any key to continue.

)
Your version also accepts number without newline termination.

By the error handling of 0 for not valid number (available as magic number as empty string is not valid for number) and -1 indicates input overflowing the buffer and not including the newline, so it will be quickly be eliminated without extra scan for finding the newline in string.

Ack! I double checked and my statement about fflush() quite clearly had an example of fflush(stdout) . Not only does fflush(stdin) not do what you want in this case, it's also undefined behavior because fflush() is only specified to work on output streams.

I did it because of the reason in text which clearly talked about problem getting input from user without fflush, which does not necessary have anything to do with output. Why should I do something stdout to clear stdin for input? I did not get that you were talking problem of outputting the prompt before input is expected from user, not problem of reading input. I should have read your code for fix also, of course.

perror() will do this for you.

Thank you for information changed code to use the shortcut.

Here corrected code. Removed the try to us buffer until the last byte referencing the buffer length in test function:

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <errno.h>
#include <string.h>
// debug, remove after debug !!!
//#undef BUFSIZ
//#define BUFSIZ 12

int get_number_len(char* p){
    // length of string of digits ending in '\n' without terminator
    // (will be tranformed to '\0' and length returned, rest of string ignored)
    // return 0 for non-number -1 for number not ending with '\n'
    int numlen=0;
    while(isdigit((unsigned char)*p)) {
            p++;
            numlen++;
    }
    // fix newline out and do not accept unfinnished
    if (*p == '\n') {
        *p= '\0';
        return numlen;
    } else {
        return *p == '\0' ? -1: 0;
    }
}

int is_palindrome(const char* number, int number_length){
    char* front = number;
    char* back = number + number_length - 1;
    for(;front < back + 1; front++, back--){
        if (*front != *back) return 0;
//        printf("%c%c\n", *front, *back);
    }
    return 1;
}

int main(){

    char num[BUFSIZ];
    //char test[] = "123124";
    int number_length;

    printf("enter the number (max length %i): ", BUFSIZ - 2);
    fflush(stdout);

    if(!fgets(num, BUFSIZ, stdin)){
        perror(errno);
        return EXIT_FAILURE;
    }

    // seems to need null setting in the end or it is '\n'
    number_length = get_number_len(num);

    if(number_length < 1){
        if(number_length==0){
            printf("Non-numeric %s", num);
        } else {
            printf("Too long input");
        }
        return EXIT_FAILURE;
    }

    printf("%s, number of length %i, is %spalindrome.\n", num, number_length, (is_palindrome(num, number_length) ? "" : "not "));
    //printf("\n%s is %s", test, get_number_len(test) > 0 ? "newline terminated number": "not newline terminated number");
    return EXIT_SUCCESS;
}
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.