overflow of cummulative sum - c

Suppose I want to add 1+11+111....adding n times.
It is clear that from a certatin value of n, there may be an overflow of the cummulative sum.
Suppose I use the following very simple function to calcuate the sum above:
int calcSum(int num)
{
int sum = 0, sequnt = 1, i;
for (i = 0; i < num; i++)
{
sum += sequnt;
sequnt = (sequnt * 10) + 1;
}
return sum;
}
To that function I want to add a check for overflowing.
I have tried to get some help here How to check if a number overflows an 'int'
but I have to admit it made me confused, and I still find some difficulties with implementing it in my task.
Any help would be appreaciated.

As either of the 2 additions or multiplication are roughly overflow candidates, call a safe overflow checker for each. Use constants in <limits.h> to guide range checking.
#include <limits.h>
int is_undefined_add(int a, int b) {
return (a < 0) ? (b < INT_MIN - a) : (b > INT_MAX - a);
}
int is_undefined_mult(int a, int b) {
if (a > 0) {
if (b > 0) {
return a > INT_MAX / b; // a positive, b positive
}
return b < INT_MIN / a; // a positive, b not positive
}
if (b > 0) {
return a < INT_MIN / b; // a not positive, b positive
}
return a != 0 && b < INT_MAX / a; // a not positive, b not positive
}
int calcSum(int num) {
int sum = 0, sequnt = 1, i;
for (i = 0; i < num; i++) {
if (is_undefined_add(sum, sequnt) Handle_Overflow();
sum += sequnt;
if (is_undefined_mult(sequnt, 10) Handle_Overflow();
sequnt *= 10;
if (is_undefined_add(sequnt, 1) Handle_Overflow();
sequnt++;
}
return sum;
}
is_undefined_add() and is_undefined_mult() are valid for all combinations of int a, int b.

Simply use INT_MAX from limits.h
int calcSum(int num)
{
int sum = 0, sequnt = 1, i;
for (i = 0; i < num; i++)
{
if (INT_MAX - sequnt < sum) exit(1); // overflow
sum += sequnt;
if (INT_MAX/10 <= sequnt) exit(1); // overflow on the two next sentences.
sequnt *= 10;
sequnt++;
}
return sum;
}
The exit(1) is just to make the example short. You can add whatever error handling that you like.

If you are sure you are using two's complement signed integers, then you can check the following: Two positive numbers added must give a positive result and two negative numbers added must give a negative result. It's impossible in only one sum to get two overflows, so if you are adding positive numbers, an overflow will arrive when your result is negative for the first time.
Either case, if you want your code to be portable, then the recommendation is to do something similar to this:
#include <limits.h>
...
if ((a > 0 && b > 0 && MAX_INT - a > b) ||
(a < 0 && b < 0 && MIN_INT - a < b)) {
/* OVERFLOW OF a + b WILL OCCUR */
...
}
if signs of operands are different it is impossible for a + b to be greater than a or b in absolute value, so it is impossible for an overflow to happen.
For unsigneds you have a similar approach (while you save half of the test, as operands can be only positive) but this time the first way is valid always (as standard says unsigned addition is considered a sum module 2^n where n is the wordsize in bits) and in that case you can make the sum and later check if the result is less than any of the operands (if both are positive, sum must be larger than or equal than any of the operands):
unsigned a, b;
...
unsigned sum = a + b;
if (sum < a || sum < b) {
/* OVERFLOW ON a + b HAS HAPPENED */
...
}
You have also to check for integer multiplication overflow. If a and b are to be multiplied, then a*b can overflow. But this time the problem goes further, as overflow can occur more than once, and you cannot do it a posteriori. In that case you can have overflow with equal or different signs, as you are adding a times b (and b has the same sign as itself) if both signs are equal the product will be positive, and overflows will occur
if (MAX_INT/b < a) { /* overflow */ }
if signs are different, the product should be negative, and then
if (MIN_INT/b < a) { /* overflow */ }
if one of the numbers is 0, then no overflow occurs on multipliying, as the result is 0.

Related

Failed to reuse variable in C

I'm trying to code a program that can tell apart real and fake credit card numbers using Luhn's algorithm in C, which is
Multiply every other digit by 2, starting with the number’s
second-to-last digit, and then add those products’ digits together.
Add the sum to the sum of the digits that weren’t multiplied by 2.
If the total’s last digit is 0 (or, put more formally, if the total
modulo 10 is congruent to 0), the number is valid!
Then I coded something like this (I already declared all the functions at the top and included all the necessary libraries)
//Luhn's Algorithm
int luhn(long z)
{
int c;
return c = (sumall(z)-sumodd(z)) * 2 + sumaodd(z);
}
//sum of digits in odd position starting from the end
int sumodd(long x)
{
int a;
while(x)
{
a = a + x % 10;
x /= 100;
}
return a;
}
//sum of all digits
int sumall(long y)
{
int b;
while(y)
{
b = b + y % 10;
y /= 10;
}
return b;
}
But somehow it always gives out the wrong answer even though there's no error or bug detected. I came to notice that it works fine when my variable z stands alone, but when it's used multiple times in the same line of code with different functions, their values get messed up (in function luhn). I'm writing this to ask for any fix I can make to make my code run correctly as I intended.
I'd appreciate any help as I'm very new to this, and I'm not a native English speaker so I may have messed up some technical terms, but I hope you'd be able to understand my concerns.
sumall is wrong.
It should be sumeven from:
Add the sum to the sum of the digits that weren’t multiplied by 2.
Your sumall is summing all digits instead of the non-odd (i.e. even) digits.
You should do the * 2 inside sumodd as it should not be applied to the other [even] sum. And, it should be applied to the individual digits [vs the total sum].
Let's start with a proper definition from https://en.wikipedia.org/wiki/Luhn_algorithm
The check digit is computed as follows:
If the number already contains the check digit, drop that digit to form the "payload." The check digit is most often the last digit.
With the payload, start from the rightmost digit. Moving left, double the value of every second digit (including the rightmost digit).
Sum the digits of the resulting value in each position (using the original value where a digit did not get doubled in the previous step).
The check digit is calculated by 10 − ( s mod ⁡ 10 )
Note that if we have a credit card of 9x where x is the check digit, then the payload is 9.
The correct [odd] sum for that digit is: 9 * 2 --> 18 --> 1 + 8 --> 9
But, sumodd(9x) * 2 --> 9 * 2 --> 18
Here's what I came up with:
// digsum -- calculate sum of digits
static inline int
digsum(int digcur)
{
int sum = 0;
for (; digcur != 0; digcur /= 10)
sum += digcur % 10;
return sum;
}
// luhn -- luhn's algorithm using digits array
int
luhn(long z)
{
char digits[16] = { 0 };
// get check digit and remove from "payload"
int check_expected = z % 10;
z /= 10;
// split into digits (we use little-endian)
int digcnt = 0;
for (digcnt = 0; z != 0; ++digcnt, z /= 10)
digits[digcnt] = z % 10;
int sum = 0;
for (int digidx = 0; digidx < digcnt; ++digidx) {
int digcur = digits[digidx];
if ((digidx & 1) == 0)
sum += digsum(digcur * 2);
else
sum += digcur;
}
int check_actual = 10 - (sum % 10);
return (check_actual == check_expected);
}
// luhn -- luhn's algorithm using long directly
int
luhn2(long z)
{
// get check digit and remove from "payload"
int check_expected = z % 10;
z /= 10;
int sum = 0;
for (int digidx = 0; z != 0; ++digidx, z /= 10) {
int digcur = z % 10;
if ((digidx & 1) == 0)
sum += digsum(digcur * 2);
else
sum += digcur;
}
int check_actual = 10 - (sum % 10);
return (check_actual == check_expected);
}
You've invoked undefined behavior by not initializing a few local variables in your functions, for instance you can remove your undefined behaviour in sumodd() by initializing a to zero like so:
//sum of digits in odd position starting from the end
int sumodd(long x)
{
int a = 0; //Initialize
while(x)
{
a += x % 10; //You can "a += b" instead of "a = a + b"
x /= 100;
}
return a;
}
It's also important to note that long is only required to be a minimum of 4-bytes wide, so it is not guaranteed to be wide enough to represent a decimal-16-digit-integer. Using long long solves this problem.
Alternatively you may find this problem much easier to solve by treating your credit card number as a char[] instead of an integer type altogether, for instance if we assume a 16-digit credit card number:
int luhn(long long z){
char number[16]; //Convert CC number to array of digits and store them here
for(int c = 0; c < 16; ++c){
number[c] = z % 10; //Last digit is at number[0], first digit is at number[15]
z /= 10;
}
int sum = 0;
for(int c = 0; c < 16; c += 2){
sum += number[c] + number[c + 1] * 2; //Sum the even digits and the doubled odd digits
}
return sum;
}
...and you could skip the long long to char[] translation part altogether if you treat the credit card number as an array of digits in the whole program
This expression:
(sumall(z)-sumodd(z)) * 2 + sumall(z);
Should be:
((sumall(z)-sumodd(z)) * 2 + sumodd(z))%10;
Based on your own definition.
But how about:
(sumall(z) * 2 - sumodd(z))%10
If you're trying to be smart and base off sumall(). You don't need to call anything twice.
Also you don't initialise your local variables. You must assign variables values before using them in C.
Also you don't need the local variable c in the luhn() function. It's harmless but unnecessary.
As others mention in a real-world application we can't recommend enough that such 'codes' are held in a character array. The amount of grief caused by people using integer types to represent digit sequence 'codes' and identifiers is vast. Unless a variable represents a numerical quantity of something, don't represent it as an arithmetic type. More issue has been caused in my career by that error than people trying to use double to represent monetary amounts.
#include <stdio.h>
//sum of digits in odd position starting from the end
int sumodd(long x)
{
int a=0;
while(x)
{
a = a + x % 10;
x /= 100;
}
return a;
}
//sum of all digits
int sumall(long y)
{
int b=0;
while(y)
{
b = b + y % 10;
y /= 10;
}
return b;
}
//Luhn's Algorithm
int luhn(long z)
{
return (sumall(z)*2-sumodd(z))%10;
}
int check_luhn(long y,int expect){
int result=luhn(y);
if(result==expect){
return 0;
}
return 1;
}
int check_sumodd(long y,int expect){
int result=sumodd(y);
if(result==expect){
return 0;
}
return 1;
}
int check_sumall(long y,int expect){
int result=sumall(y);
if(result==expect){
return 0;
}
return 1;
}
int main(void) {
int errors=0;
errors+=check_sumall(1,1);
errors+=check_sumall(12,3);
errors+=check_sumall(123456789L,45);
errors+=check_sumall(4273391,4+2+7+3+3+9+1);
errors+=check_sumodd(1,1);
errors+=check_sumodd(91,1);
errors+=check_sumodd(791,8);
errors+=check_sumodd(1213191,1+1+1+1);
errors+=check_sumodd(4273391,15);
errors+=check_luhn(1234567890,((9+7+5+3+1)*2+(0+8+6+4+2))%10);
errors+=check_luhn(9264567897,((9+7+5+6+9)*2+(7+8+6+4+2))%10);
if(errors!=0){
printf("*ERRORS*\n");
}else{
printf("Success\n");
}
return 0;
}

How to print values in reverse without the use of arrays nor pointers in C

I've been working on a code that converts a given number (decimal base) to any other base from 2 to 16.
Clearly, I've come across the issue that the function base_conversion_it (it stands for iterative) prints the values in reverse.
I cannot use arrays nor pointers, and everyone on the internet seems to solve this issue like that. My assignment requires making both an iterative and a recursive function (which I did and works).
void base_conversion_it(unsigned int n, unsigned int b) {
if (n > 0) {
//bases between 2 and 16
if (b >= 2 && b <= 16) {
int r; //r = remainder
int q = 1; //quotient
int num; //saves the remainder
while (q != 0) {
r = n % b;
printf("%X", r);
q = n / b;
n = q;
}
}
}
}
You start converting from the units digit.
Maybe start with the most significant digit instead?
// It's Undefined Behaviour if `b` is outside the range [2...16]
void base_conversion_it(unsigned int n, unsigned int b) {
unsigned highestbase = 1;
while (highestbase * b <= n) highestbase *= b; //possible wrap around and infinite loop
while (highestbase) {
printf("%X", n / highestbase);
n %= highestbase;
highestbase /= b;
}
printf("\n");
}
Sorry missed iterative.
char digits[] = "0123456789ABCDEFGHIJKLMNOP";
void print(unsigned long long val, unsigned base)
{
unsigned long long mask = base;
while(val / mask >= base) mask *= base;
do
{
printf("%c", digits[val / mask]);
val %= mask;
mask /= base;
}while(val);
}
int main(void)
{
print(45654756453, 10); printf("\n");
print(45654756453, 16); printf("\n");
print(45654756453, 24); printf("\n");
print(45654756453, 2); printf("\n");
}
https://godbolt.org/z/W3fGnnhYs
Recursion:
char digits[] = "0123456789ABCDEF";
void print(unsigned long long val, unsigned base)
{
if(base <= 16 && base > 1)
{
if(val >= base) print(val / base, base);
printf("%c", digits[val % base]);
}
}
https://godbolt.org/z/84hYocnjv
If you cannot use either arrays (including strings) or recursion, then I think you need to compute the output digits in most-significant-first order. This is a bit less natural than computing them in the opposite order and reversing the result, but it can be done:
use a loop to find the place value of the most significant non-zero base-b digit of n. For example, check the result of dividing n by successive powers of b until the result is 0, then back off one step.
In a separate loop, read off the base-b digits of n one by one, starting with the one at the discovered most-significant position. For each digit,
Divide the current value of n by the place value pv of the current digit to get a digit value.
Replace n with n % pv.
Be careful to continue all the way down to place value 1, as opposed, say, to stopping when n becomes zero.

When inserting exponents (n) above 10, this function gives the wrong values

Just a quick issue I have in c. In this case x is always 10, and n varies. the function works fine when n < 11, but as soon as it goes above 11 the function churns out random values which are sometimes negative too. Any tips?
int myPow(int x,int n)
{
int i; /* Variable used in loop counter */
long number = 1;
for (i = 0; i < n; i++)
number *= x;
return(number);
}
Typically code like this is undefined behavior due to int overflow.
Yet OP is using long in the multiplication, so it is UB once the product exceeds LONG_MAX.
When INT_MAX and LONG_MAX are 2,147,483,647 (231 - 1), codes suffers UB with my_pow(10,10).
When LONG_MAX in 9,223,372,036,854,775,807 (263 - 1), codes suffers UB with my_pow(10,19) and my_pow(10,10) is implementation defined behavior converting the large long to int on the return.
Code using wider intergern types to cope with larger values, but integer math is only good for so far with an exponential function
Some dusty old sample code the considers all int values and uses Exponentiation by squaring with projection against signed integer overflow.
#define DIV0 INTMAX_MIN
// Likely needs work ...
static bool safe_mul(intmax_t a, intmax_t b, intmax_t *product) {
if (a > 0) {
if (b > 0) {
if (a > INTMAX_MAX / b)
return true; // a positive, b positive
} else if (b < INTMAX_MIN / a)
return true; // a positive, b not positive
} else if (b > 0) {
if (a < INTMAX_MIN / b)
return true; // a not positive, b positive
} else if (a != 0 && b < INTMAX_MAX / a)
return true; // a not positive, b not positive
*product = a * b;
return false;
}
intmax_t pow_i(int base, int expo) {
if (expo < 0) {
if (base == 1)
return 1;
if (base == -1)
return (expo % 2) ? -1 : 1;
if (base == 0)
return DIV0; //
return 0; // round toward 0
}
intmax_t wide_base = base;
intmax_t pow = 1;
while (expo > 0) {
if (expo % 2) {
if (safe_mul(pow, wide_base, &pow))
return 0;
}
if (safe_mul(wide_base, wide_base, &wide_base))
return 0;
expo /= 2;
}
return pow;
}

How do I reverse the order of the digits of an integer using recursion in C programming?

Problem statement :
Given a 32-bit signed integer, reverse digits of an integer.
Note: Assume we are dealing with an environment that could only store
integers within the 32-bit signed integer range: [ −2^31, 2^31 − 1]. For
the purpose of this problem, assume that your function returns 0 when
the reversed integer overflows.
I'm trying to implement the recursive function reverseRec(), It's working for smaller values but it's a mess for the edge cases.
int reverseRec(int x)
{
if(abs(x)<=9)
{
return x;
}
else
{
return reverseRec(x/10) + ((x%10)*(pow(10, (floor(log10(abs(x)))))));
}
}
I've implemented non recursive function which is working just fine :
int reverse(int x)
{
long long val = 0;
do{
val = val*10 + (x%10);
x /= 10;
}while(x);
return (val < INT_MIN || val > INT_MAX) ? 0 : val;
}
Here I use variable val of long long type to check the result with MAX and MIN of signed int type but the description of the problem specifically mentioned that we need to deal within the range of 32-bit integer, although somehow it got accepted but I'm just curious If there is a way to implement a recursive function using only int datatype ?
One more thing even if I consider using long long I'm failing to implement it in the recursive function reverseRec().
If there is a way to implement a recursive function using only int datatype ?
(and) returns 0 when the reversed integer overflows
Yes.
For such +/- problems, I like to fold the int values to one side and negate as needed. The folding to one side (- or +) simplifies overflow detection as only a single side needs testing
I prefer folding to the negative side as there are more negatives, than positives. (With 32-bit int, really didn't make any difference for this problem.)
As code forms the reversed value, test if the following r * 10 + least_digit may overflow before doing it.
An int only recursive solution to reverse an int. Overflow returns 0.
#include <limits.h>
#include <stdio.h>
static int reverse_recurse(int i, int r) {
if (i) {
int least_digit = i % 10;
if (r <= INT_MIN / 10 && (r < INT_MIN / 10 || least_digit < INT_MIN % 10)) {
return 1; /// Overflow indication
}
r = reverse_recurse(i / 10, r * 10 + least_digit);
}
return r;
}
// Reverse an int, overflow returns 0
int reverse_int(int i) {
// Proceed with negative values, they have more range than + side
int r = reverse_recurse(i > 0 ? -i : i, 0);
if (r > 0) {
return 0;
}
if (i > 0) {
if (r < -INT_MAX) {
return 0;
}
r = -r;
}
return r;
}
Test
int main(void) {
int t[] = {0, 1, 42, 1234567890, 1234567892, INT_MAX, INT_MIN};
for (unsigned i = 0; i < sizeof t / sizeof t[0]; i++) {
printf("%11d %11d\n", t[i], reverse_int(t[i]));
if (t[i] != INT_MIN) {
printf("%11d %11d\n", -t[i], reverse_int(-t[i]));
}
}
}
Output
0 0
0 0
1 1
-1 -1
42 24
-42 -24
1234567890 987654321
-1234567890 -987654321
1234567892 0
-1234567892 0
2147483647 0
-2147483647 0
-2147483648 0
You could add a second parameter:
int reverseRec(int x, int reversed)
{
if(x == 0)
{
return reversed;
}
else
{
return reverseRec(x/10, reversed * 10 + x%10);
}
}
And call the function passing the 0 for the second parameter. If you want negative numbers you can check the sign before and pass the absolute value to this function.
In trying to learn C programming I programed this question and get some correct results and some incorrect. I don't see the reason for the difference.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h> // requires adding link to math -lm as in: gcc b.c -lm -o q11
int ReverseInt(int startValue, int decimalPlace)
{
if(decimalPlace == 0) // if done returns value
{
return startValue;
}
int temp = startValue % 10; // gets units digit
int newStart = (startValue -temp)/10; // computes new starting value after removing one digit
int newDecimal = decimalPlace -1;
int value = temp*pow(10,decimalPlace);
return value + ReverseInt(newStart,newDecimal); // calls itself recursively until done
}
int main()
{
int x, decimalP, startValue;
printf("Input number to be reversed \n Please note number must be less than 214748364 :");
scanf("%d", &x);
if (x > 214748364)
{
printf("Input number to be reversed \n Please note number must be less than 214748364 :");
scanf("%d", &x);
}
decimalP = round(log10(x)); // computes the number of powers of 10 - 0 being units etc.
startValue = ReverseInt(x, decimalP); // calls function with number to be reversed and powers of 10
printf("\n reverse of %d is %d \n", x, startValue);
}
Output is: reverse of 1234 is 4321 but then reverse of 4321 is 12340
It's late and nothing better does not come into my mind. No float calculations. Of course, integer has to be big enough to accommodate the result. Otherwise it is an UB.
int rev(int x, int partial, int *max)
{
int result;
if(x / partial < 10 && (int)(x / partial) > -10)
{
*max = partial;
return abs(x % 10) * partial;
}
result = rev(x, partial * 10, max) + abs(((x / (int)(*max / partial)) % 10) * partial);
return result;
}
int reverse(int x)
{
int max;
return rev(x, 1, &max) * ((x < 0) ? -1 : 1);
}
int main(void){
printf("%d", reverse(-456789));
}
https://godbolt.org/z/M1eezf
unsigned rev(unsigned x, unsigned partial, unsigned *max)
{
unsigned result;
if(x / partial < 10)
{
*max = partial;
return (x % 10) * partial;
}
result = rev(x, partial * 10, max) + (x / (*max / partial) % 10) * partial;
return result;
}
unsigned reverse(unsigned x)
{
unsigned max;
return rev(x, 1, &max);
}
int main(void){
printf("%u", reverse(123456));
}
when using long long to store the result all possible integers can be reversed
long long rev(int x, long long partial, long long *max)
{
long long result;
if(x / partial < 10 && (int)(x / partial) > -10)
{
*max = partial;
return abs(x % 10) * partial;
}
result = rev(x, partial * 10, max) + abs(((x / (int)(*max / partial)) % 10) * partial);
return result;
}
long long reverse(int x)
{
long long max;
return rev(x, 1, &max) * ((x < 0) ? -1 : 1);
}
int main(void){
printf("%d reversed %lld\n", INT_MIN, reverse(INT_MIN));
printf("%d reversed %lld\n", INT_MAX, reverse(INT_MAX));
}
https://godbolt.org/z/KMfbxz
I am assuming by reversing an integer you mean turning 129 to 921 or 120 to 21.
You need an initial method to initialize your recursive function.
Your recursive function must figure out how many decimal places your integer uses. This can be found by using log base 10 with the value and then converting the result to a integer.
log10 (103) approx. 2.04 => 2
Modulus the initial value by 10 to get the ones place and store it in a variable called temp
Subtract the ones place from the initial value and store that in a variable called newStart.
divide this value by 10
Subtract one from the decimal place and store in another variable called newDecimal.
Return the ones place times 10 to the power of the decimal place and add it to the function where the initial value is newStart and the decimalPlace is newDecimal.
#include <stdio.h>
#include <math.h>
int ReverseInt(int startValue, int decimalPlace);
int main()
{
int i = -54;
int positive = i < 0? i*-1 : i;
double d = log10(positive);
int output = ReverseInt(positive,(int)d);
int correctedOutput = i < 0? output*-1 : output;
printf("%d \n",correctedOutput);
return 0;
}
int ReverseInt(int startValue, int decimalPlace)
{
if(decimalPlace == 0)
{
return startValue;
}
int temp = startValue % 10;
int newStart = (startValue -temp)/10;
int newDecimal = decimalPlace -1;
int value = temp*pow(10,decimalPlace);
return value + ReverseInt(newStart,newDecimal);
}

Reverse integer in c gives overflow

I am solving reverse integer problem in leetcode in c language.But it gives runtime error on line sum=sum+rem*10;.
runtime error: signed integer overflow: 964632435 * 10 cannot be represented in type 'int'
Here is the code.
#define INT_MAX 2147483647
#define INT_MIN -2147483648
int reverse(int x){
int sum=0,rem=0;
int p;
if(x > INT_MAX || x < INT_MIN){return 0;}
if(x==0){return 0;}
if(x<0){p=x;x=abs(x);}
while(x%10==0){x=x/10;}
while(x>0){
rem=x%10;
if(sum > INT_MAX || sum*(-1) < INT_MIN){return 0;}
sum=sum*10+rem;
x/=10;
}
if(p<0){sum=sum*(-1);return sum;}
else{return sum;}
}
One way - which isn't performance optimal but simple - is to convert the integer to a string and then revert the string and then convert back to integer.
The below solution is for positive integers - I'll leave it to OP to extend it to handle negative integers.
Could look like:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
int reverse(const int n)
{
if (n < 0)
{
printf("Handling of negative integers must be added\n");
exit(1);
}
char tmp1[100];
char tmp2[100] = { 0 };
sprintf(tmp1, "%d", n);
printf("Input : %s\n", tmp1);
size_t sz = strlen(tmp1);
for (size_t i = 0; i < sz; ++i)
{
tmp2[i] = tmp1[sz-i-1];
}
int result = tmp2[0] - '0';
char* p = tmp2+1;
while(*p)
{
if ((INT_MAX / 10) < result)
{
printf("oh dear: %d can't be reversed to int\n", n);
exit(1);
}
result = result * 10;
if ((INT_MAX - (*p - '0')) < result)
{
printf("oh dear: %d can't be reversed to int\n", n);
exit(1);
}
result += *p - '0';
p++;
}
return result;
}
int main()
{
printf("Output: %d\n", reverse(123));
printf("Output: %d\n", reverse(123456789));
printf("Output: %d\n", reverse(1234567899));
return 0;
}
Output:
Input : 123
Output: 321
Input : 123456789
Output: 987654321
Input : 1234567899
oh dear: 1234567899 can't be reversed to int
But it gives runtime error on line sum=sum+rem*10;.
To test for potential int overflow of positive sum, rem, compare against INT_MAX/10 and INT_MAX%10 beforehand.
if (sum >= INT_MAX / 10 && (sum > INT_MAX / 10 || rem > INT_MAX % 10)) {
// overflow
} else {
sum = sum * 10 + rem;
}
Handling negatives
Watch out for x = INT_MIN ... x = -x;. That is int overflow and undefined behavior.
Sometimes it is fun to solve such int problems of positive and negative numbers by converting the positive numbers to negative ones embrace the dark side - its your only hope. (maniacal laughter)
There are more int values less than zero than there are int values more than zero - by one. So x = -x is always well defined when x > 0.
// C99 or later code
#include <limits.h>
int reverse(int x) {
int x0 = x;
if (x0 > 0) {
x = -x; // make positive values negative, embrace the dark side
}
int reversed = 0;
while (x < 0) {
int rem = x % 10;
x /= 10;
if (reversed <= INT_MIN / 10
&& (reversed < INT_MIN / 10 || rem < INT_MIN % 10)) {
// overflow
return 0;
}
reversed = reversed * 10 + rem;
}
if (x0 > 0) {
if (reversed < -INT_MAX) {
// overflow
return 0;
}
reversed = -reversed;
}
return reversed;
}
Test code
#include <stdio.h>
int main() {
int x[] = {0, 1, -1, 42, 123456789, INT_MAX/10*10+1, INT_MIN/10*10-1,INT_MAX, INT_MIN};
size_t n = sizeof x / sizeof x[0];
for (size_t i = 0; i < n; i++) {
printf("Attempting to reverse %11d ", x[i]);
printf("Result %11d\n", reverse(x[i]));
}
}
Sample output
Attempting to reverse 0 Result 0
Attempting to reverse 1 Result 1
Attempting to reverse -1 Result -1
Attempting to reverse 42 Result 24
Attempting to reverse 123456789 Result 987654321
Attempting to reverse 2147483641 Result 1463847412
Attempting to reverse -2147483641 Result -1463847412
Attempting to reverse 2147483647 Result 0
Attempting to reverse -2147483648 Result 0
First, you should not be defining your own values for INT_MAX and INT_MIN. You should instead #include <limits.h> which defines these value.
Second, this:
sum > INT_MAX
Will never be true because sum can never hold a value larger than INT_MAX. So you can't perform an operation and then check afterward if it overflowed. What you can do instead is check the operation first and do some algebra that prevents overflow.
if ( INT_MAX / 10 < sum) return 0;
sum *= 10;
if ( INT_MAX - rem < sum) return 0;
sum += rem;

Resources