How to handle integer overflow in C - c

I'm trying to create anagrams from words where answers are supposed to be for example:
The word "at" should have two anagrams.
ordeals should have 5040 anagrams.
abcdABCDabcd shoud have 29937600 anagrams.
abcdefghijklmnopqrstuvwxyz should have 403291461126605635584000000 anagrams.
abcdefghijklmabcdefghijklm should have 49229914688306352000000.
My program seems to work for the first three examples but not for the last two. How can I change the program to make it work?
#include <stdio.h>
#include <memory.h>
int contains(char haystack[], char needle) {
size_t len = strlen(haystack);
int i;
for (i = 0; i < len; i++) {
if (haystack[i] == needle) {
return 1;
}
}
return 0;
}
unsigned long long int factorial(unsigned long long int f) {
if (f == 0)
return 1;
return (f * factorial(f - 1));
}
int main(void) {
char str[1000], ch;
unsigned long long int i;
unsigned long long int frequency = 0;
float answer = 0;
char visited[1000];
int indexvisited = 0;
printf("Enter a string: ");
scanf("%s", str);
for (i = 0; str[i] != '\0'; ++i);
unsigned long long int nominator = 1;
for (int j = 0; j < i; ++j) {
ch = str[j];
frequency = 0;
if (!contains(visited, ch)) {
for (int k = 0; str[k] != '\0'; ++k) {
if (ch == str[k])
++frequency;
}
printf("Frequency of %c = %lld\n", ch, frequency);
visited[indexvisited] = ch;
visited[++indexvisited] = '\0';
nominator = nominator * factorial(frequency);
}
}
printf("Number of anagrams = %llu\n", (factorial( i )/nominator ) );
return 0;
}

Even though an unsigned long long is pretty big, it's not completely unbounded. Its maximum value is around 1*10^19. If your source string is 26 characters long, you calculate factorial(26) - which is around 4*10^26, much much bigger than will fit in an unsigned long long.

When you need to work with ridicously large numbers you have to split things, i'd say that using a long double to store the root number and a long unsigned int to store the 10th potence would do the trick.
4*10^26 == ld 4, lui 26 == ld * 10^lui
this could be usefull for calculations, not sure tho how to represent it, it'll overflow everything but a string

Just for the fun, here's the best I could come up with using only built-in datatypes. Instead of calculating factorials over and over (and, btw, avoid recursion for such things!), it has an "intelligent" n over k function. Note that it attempts to detect an overflow, but this is not really reliable.
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef size_t AsciiCountTable[0x80];
static int countAsciiCharacters(const char *input, AsciiCountTable table)
{
const char *c = input;
while (*c)
{
if ((unsigned char)*c > 0x7f)
{
// not an ascii character
return 0;
}
++table[(int)*c];
++c;
}
return 1;
}
static unsigned long long nOverK(size_t n, size_t k)
{
unsigned long long result = 1;
size_t barrier = n - k;
if (k > barrier) barrier = k;
for (size_t i = n; i > barrier; --i)
{
result *= i;
}
for (size_t i = 2; i <= n - barrier; ++i)
{
result /= i;
}
return result;
}
int main(int argc, char **argv)
{
if (argc < 2)
{
fprintf(stderr, "Usage: %s <word>\n", argv[0]);
return EXIT_FAILURE;
}
AsciiCountTable countTable = {0};
if (!countAsciiCharacters(argv[1], countTable))
{
fputs("Only ASCII characters allowed.\n", stderr);
return EXIT_FAILURE;
}
size_t positions = strlen(argv[1]);
unsigned long long permutations = 1;
for (int i = 0; i < 0x80; ++i)
{
size_t n = positions;
size_t k = countTable[i];
if (k > 0)
{
unsigned long long temp = permutations;
permutations *= nOverK(n, k);
if (temp > permutations)
{
fputs("Overflow detected.\n", stderr);
return EXIT_FAILURE;
}
positions -= k;
}
}
printf("permutations: %" PRIuMAX "\n", permutations);
return EXIT_SUCCESS;
}

Related

Convert long integer(decimal) to base 36 string (strtol inverted function in C)

I can use the strtol function for turning a base36 based value (saved as a string) into a long int:
long int val = strtol("ABCZX123", 0, 36);
Is there a standard function that allows the inversion of this? That is, to convert a long int val variable into a base36 string, to obtain "ABCZX123" again?
There's no standard function for this. You'll need to write your own one.
Usage example: https://godbolt.org/z/MhRcNA
const char digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
char *reverse(char *str)
{
char *end = str;
char *start = str;
if(!str || !*str) return str;
while(*(end + 1)) end++;
while(end > start)
{
int ch = *end;
*end-- = *start;
*start++ = ch;
}
return str;
}
char *tostring(char *buff, long long num, int base)
{
int sign = num < 0;
char *savedbuff = buff;
if(base < 2 || base >= sizeof(digits)) return NULL;
if(buff)
{
do
{
*buff++ = digits[abs(num % base)];
num /= base;
}while(num);
if(sign)
{
*buff++ = '-';
}
*buff = 0;
reverse(savedbuff);
}
return savedbuff;
}
One of the missing attributes of this "Convert long integer to base 36 string" is string management.
The below suffers from a potential buffer overflow when destination is too small.
char *long_to_string(char *destination, long num, int base);
(Assuming 32-bit long) Consider the overflow of below as the resultant string should be "-10000000000000000000000000000000", which needs 34 bytes to encode the string.
char buffer[33]; // Too small
long_to_string(buffer, LONG_MIN, 2); // Oops!
An alternative would pass in the buffer size and then provide some sort of error signaling when the buffer is too small.
char* longtostr(char *dest, size_t size, long a, int base)
Since C99, code instead could use a compound literal to provide the needed space - without calling code trying to compute the needed size nor explicitly allocate the buffer.
The returned string pointer from TO_BASE(long x, int base) is valid until the end of the block.
#include <assert.h>
#include <limits.h>
#define TO_BASE_N (sizeof(long)*CHAR_BIT + 2)
// v. compound literal .v
#define TO_BASE(x, b) my_to_base((char [TO_BASE_N]){""}, (x), (b))
char *my_to_base(char *buf, long a, int base) {
assert(base >= 2 && base <= 36);
long i = a < 0 ? a : -a; // use the negative side - this handle _MIN, _MAX nicely
char *s = &buf[TO_BASE_N - 1];
*s = '\0';
do {
s--;
*s = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[-(i % base)];
i /= base;
} while (i);
if (a < 0) {
s--;
*s = '-';
}
// Could add memmove here to move the used buffer to the beginning
return s;
}
#include <limits.h>
#include <stdio.h>
int main(void) {
long ip1 = 0x01020304;
long ip2 = 0x05060708;
long ip3 = LONG_MIN;
printf("%s %s\n", TO_BASE(ip1, 16), TO_BASE(ip2, 16), TO_BASE(ip3, 16));
printf("%s %s\n", TO_BASE(ip1, 2), TO_BASE(ip2, 2), TO_BASE(ip3, 2));
puts(TO_BASE(ip1, 8));
puts(TO_BASE(ip1, 36));
puts(TO_BASE(ip3, 10));
}
Here is another option with no need for source array of charaters, but less portable since not all character encodings have contiguous alphabetic characters, for example EBCDIC. Test HERE
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#include <limits.h>
char get_chars(long long value)
{
if (value >= 0 && value <= 9)
return value + '0';
else
return value - 10 + 'A';
}
void reverse_string(char *str)
{
int len = strlen(str);
for (int i = 0; i < len/2; i++)
{
char temp = str[i];
str[i] = str[len - i - 1];
str[len - i - 1] = temp;
}
}
char* convert_to_base(char *res, int base, long long input)
{
bool flag = 0;
int index = 0;
if(input < 0){
input = llabs(input);
flag = 1;
}
else if(input == 0){
res[index++] = '0';
res[index] = '\0';
return res;
}
while(input > 0)
{
res[index++] = get_chars(input % base);
input /= base;
}
if(flag){
res[index++] = '-';
}
res[index] = '\0';
reverse_string(res);
return res;
}
int main() {
long long input = 0;
printf("** Integer to Base-36 **\n ");
printf("Enter a valid number: ");
scanf("%lld", &input);
if(input >= LLONG_MAX && input <= LLONG_MIN){
printf("Invalid number");
return 0;
}
int base = 36;
char res[100];
printf("%lld -> %s\n", input, convert_to_base(res, base, input));
return 0;
}

Iterate Over Char Array Elements in C

This code is supposed to take a user's input and convert it to binary. The input is grouped into an integer array to store character codes and/or adjacent digits, then each item in the integer array is converted to binary. When the user types "c357", "c" should be converted to 99, then converted to binary. Then, "357" should be converted to binary as well. In the main() function, strlen(convert) does not accurately represent the number of items in array convert, thus only iterating over the first array item.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <unistd.h>
#include <string.h>
#define EIGHT_BITS 255
#define SIXTEEN_BITS 65535
#define THIRTY_TWO_BITS 4294967295UL
// DETERMINE NUMBER OF BITS TO OUTPUT
int getBitLength(unsigned long d) {
int l;
if (d <= EIGHT_BITS) {
l = 8;
}
else if (d > EIGHT_BITS && d <= SIXTEEN_BITS) {
l = 16;
}
else if (d > SIXTEEN_BITS && d <= THIRTY_TWO_BITS) {
l = 32;
}
return l;
}
// CONVERT INPUT TO BINARY VALUE
char* convertToBinary(unsigned long int decimal) {
int l = getBitLength(decimal);
static char b[33];
char bin[33];
int i, j, k = 0, r;
b[33] = '\0';
bin[33] = '\0';
printf("Bits................ %ld\n", l);
// creates array
for (i = 0; i < l; i++) {
r = decimal % 2;
decimal /= 2;
b[i] = r;
}
// reverses array for binary value
for (j = l - 1; j >= 0; j--) {
bin[k] = b[j];
strncpy(&bin[k], &b[j], l);
snprintf(&bin[k], l, "%d", b[j]);
k++;
}
printf("Binary Value: %s\n", bin);
return bin;
}
unsigned long int* numbersToConvert(char* input) {
const int MAX_INPUT = 20;
int i, k = 0, z = 0;
char numbers[MAX_INPUT];
unsigned long int *toConvert = malloc(MAX_INPUT * sizeof(int));
numbers[MAX_INPUT] = '\0';
for (i = 0; i < strlen(input); i++) {
if (isdigit(input[i])) {
numbers[z] = input[i];
if (!isdigit(input[i + 1])) {
toConvert[k] = strtol(numbers, NULL, 10);
printf("----- %ld -----\n", toConvert[k]);
z = 0;
}
else {
z++;
}
}
else {
printf("----- %c -----\n", input[i]);
printf("Character Code: %d\n", input[i]);
toConvert[k] = (unsigned long int) input[i];
}
k++;
}
return toConvert;
}
int main(void) {
const int MAX_INPUT = 20;
int i, p;
char input[MAX_INPUT];
unsigned long int* convert;
printf("------- Input --------\n");
scanf("%s", input);
input[MAX_INPUT] = '\0';
// PRINT INPUT AND SIZE
printf("\nInput: %s\n", input);
convert = numbersToConvert(input);
convert[MAX_INPUT] = '\0';
printf("strlen: %ld\n", strlen(convert));
for (i = 0; i < strlen(convert); i++) {
printf("num array: %ld\n", convert[i]);
convertToBinary(convert[i]);
}
return 0;
}
I have attempted to null terminate each string to prevent undefined behavior. I am unsure if certain variables, if any, are meant to be static.
It is hard to read your code.
Here you have something working (converting the number to binary):
static char *reverse(char *str)
{
char *end = str + strlen(str) - 1;
char *saved = str;
int ch;
while(end > str)
{
ch = *end;
*end-- = *str;
*str++ = ch;
}
return saved;
}
char *tostr(char *buff, unsigned long long val)
{
if(buff)
{
char *cpos = buff;
while(val)
{
*cpos++ = (val & 1) + '0';
val >>= 1;
}
*cpos = 0;
reverse(buff);
}
return buff;
}
int main()
{
char buff[128];
printf("%s\n", tostr(buff, 128));
}
https://godbolt.org/z/6sRC4C

How to convert to binary as string in code C

I am trying to convert int to binary as string but I can not.
Please help me. How to convert integer to binary, please tell me.
Input: 32
Output: 00100000
My code:
#include <stdio.h>
#include <string.h>
char converttobinary(int n)
{
int i;
int a[8];
char op;
for (i = 0; i < 8; i++)
{
a[i] = n % 2;
n = (n - a[i]) / 2;
}
for (i = 7; i >= 0; i--)
{
op = strcat(op, a[i]);
}
return op;
}
int main()
{
int n;
char str;
n = 254;
str = converttobinary(n);
printf("%c", str);
return 0;
}
I have tried to modify your solution with minimal changes to make it work. There are elegant solutions to convert Integer to Binary for example using shift operators.
One of the main issue in the code was you were using character instead of character array.
i.e char str; instead of char str[SIZE];
Also you were performing string operations on a single character. Additionally, iostream header file is for C++.
There is room for lot of improvements in the solution posted below (I only made your code work with minimal changes).
My suggestion is to make your C basics strong and approach this problem again.
#include <stdio.h>
#include <string.h>
void converttobinary(int n, char *op)
{
int i;
int a[8];
for (i = 0; i < 8; i++)
{
a[i] = n % 2;
n = (n - a[i]) / 2;
}
for (i = 7; i >= 0; i--)
{
op[i]=a[i];
}
}
int main()
{
int n,i;
char str[8];
n = 8;
converttobinary(n,str);
for (i = 7; i >= 0; i--)
{
printf(" %d ",str[i]);
}
return 0;
}
char *rev(char *str)
{
char *end = str + strlen(str) - 1;
char *saved = str;
while(end > str)
{
int tmp = *str;
*str++ = *end;
*end-- = tmp;
}
return saved;
}
char *tobin(char *buff, unsigned long long data)
{
char *saved = buff;
while(data)
{
*buff++ = (data & 1) + '0';
data >>= 1;
}
*buff = 0;
return rev(saved);
}
int main()
{
char x[128];
unsigned long long z = 0x103;
printf("%llu is 0b%s\n", z, tobin(x, z));
return 0;
}
I modify your code a little bit to make what you want,
the result of this code with
n = 10
is
00001010
In this code i shift the bits n positions of the imput and compare if there is 1 or 0 in this position and write a '1' if there is a 1 or a '0' if we have a 0.
#include <stdio.h>
void converttobinary(int n, char op[8]){
int auxiliar = n;
int i;
for (i = 0; i < 8; i++) {
auxiliar = auxiliar >> i;
if (auxiliar & 1 == 1){
op[7-i] = '1';
} else{
op[7-i] = '0';
}
auxiliar = n;
}
}
int main (void){
int n = 10;
int i;
char op[8];
converttobinary(n, op);
for(i = 7; i > -1; i--){
printf("%c",op[i]);
}
return 0;
}

Continued Power Function Message

I keep getting the error message that my I have an undefined reference to the power function, but I'm not really sure where that is occurring or why my code is coming up with that error because I have used to power function before in this way. If anyone could help me figure out why it isn't working now I would really appreciate it.
#include "stdio.h"
#include "string.h" //Needed for strlen()
#include "math.h"
#define MAX_BITS 32
#define MAX_LENGTH 49
#define NUMBER_TWO 2
#define NUMBER_ONE 1
#define TERMINATOR '\0'
//Code to find the index of where the string ends
int last_index_of(char in_str[], char ch) {
for (int i = 0; i < MAX_LENGTH; i++) {
if(in_str[i] == ch) {
last_index_of == i;
}
}
return last_index_of;
}
//Code to find the start of the fractional aspect
void sub_string(char in_str[], char out_str[], int start, int end){
int i = 0;
while (i < 1) {
out_str[i] = in_str[start] + in_str[end-1];
i++;
}
}
int main()
{
//Declaration of variable
char input[MAX_LENGTH +1]; // +1 for '\0'
int number;
double exponent;
char output[MAX_BITS];
int fraction;
sub_string(input, output, 0, TERMINATOR);
//Input from the user
printf("Enter a floating point value in binary: ");
scanf("%s", input);
//Calculates the Decimal Part
for (int i = 0; i < last_index_of(input, TERMINATOR) ; i++) {
number = number + number + input[i];
}
printf("%d", number);
exponent = -1;
//Calculates the Fractional Part
for (int j = 0; j < last_index_of(input, TERMINATOR); j++) {
if (j == last_index_of) {
fraction = NUMBER_ONE/(pow(NUMBER_TWO, exponent));
printf("%d/n", fraction);
}
else {
fraction = NUMBER_ONE/(pow(NUMBER_TWO, exponent));
printf("%d + ", fraction);
exponent--;
}
}
return 0;
}
Some problems:
you need -lm option to linker to tell it where to find pow function
last_index_of is not correctly written, you use the function name as an internal variable, you can correct it this way:
//Code to find the index of where the string ends
int last_index_of(char in_str[], char ch) {
int ret = 0;
for (int i = 0; i < MAX_LENGTH; i++) {
if(in_str[i] == ch) {
ret = i;
}
}
return ret;
}
Note that you can replace your last_index_of() function by strlen()
as pointed in comment, sub_string() is not functionnal. A corrected version could be:
//Code to find the start of the fractional aspect
void sub_string(char in_str[], char out_str[], int start, int end){
int i = 0;
while (start != end) {
/* warning, bounds are still not tested...*/
out_str[i++] = in_str[start++];
}
out_str[i] = '\0'
}
Instead of calling last_index_of() in your exist for loop condition, you should take its value to re-use it:
for (int j = 0; j < last_index_of(input, TERMINATOR); j++) {
/* Error here: will never be TRUE */
if (j == last_index_of) {
/* ... */
}
else {
/* ... */
}
}
would become:
int last_index = last_index_of(input, TERMINATOR);
for (int j = 0; j < last_index; j++) {
if (j == last_index) {
/* ... */
}
else {
/* ... */
}
}
Another problem, you use number variable without initializing it, you should write int number = 0 instead of int number;
After that, there is also a problem with your logic.
You have some idea of what you want to do, but it is not clear in your code.
It seems that you want
the user to input some string in the form 10010.100111
to split this string into two parts 10010 and 100111
to convert the first part into integer part 10010 -> 18
to convert the second part into fractional part 100111 -> 0.609...
This decomposition may lead you to write this kind of code:
#include "stdio.h"
#include "string.h"
#define MAX_BITS 32
#define MAX_LENGTH 49
//Code to find the index of where the string ends
int last_index_of(char in_str[], char ch)
{
int ret = 0;
for (int i = 0; i < MAX_LENGTH; i++) {
if (in_str[i] == ch) {
ret = i;
}
}
return ret;
}
void sub_string(char in_str[], char out_str[], int start, int end)
{
int i = 0;
while (start != end) {
/* warning, bounds are still not tested... */
out_str[i++] = in_str[start++];
}
out_str[i] = '\0';
}
void split(char *input, char *first, char *second)
{
int idx = last_index_of(input, '.');
sub_string(input, first, 0, idx);
sub_string(input, second, idx + 1, strlen(input));
}
int main()
{
//Declaration of variable
char input[MAX_LENGTH + 1]; // +1 for '\0'
char first[MAX_BITS];
char second[MAX_BITS];
/* Input from the user */
printf("Enter a floating point value in binary: ");
scanf("%s", input);
/* split integer and fractionnal parts */
split(input, first, second);
/* decode integer part */
printf("integer part:\n");
for (int i = strlen(first) - 1, j = 1; i > -1; --i, j <<= 1) {
if (first[i] == '1') {
printf("%d ", j);
}
}
/* decode frac part */
printf("\nfractionnal part:\n");
for (int i = 0; i < strlen(second); ++i) {
if (second[i] == '1') {
printf("1/%d ", 2 << i);
}
}
return 0;
}

Counting characters in a string or file

I have the following code:
#include "stdafx.h"
#include "string.h"
#include "ctype.h"
/*selection sort*/
void swap(int A[], int j, int k)
{
int p = A[k];
int i;
for (i = 0; i < (k - j); i++)
{
A[k - i] = A[k - i - 1];
}
A[j] = p;
}
/*greatest number in an array*/
int max(int A[], int N, int k)
{
int max = k, i;
for (i = k; i < N; i++)
{
if (A[max] < A[i])
max = i;
}
return max;
}
int count_nonspace(const char* str)
{
int count = 0;
while(*str)
{
if(!isspace(*str++))
count++;
}
return count;
}
int _tmain(int argc, _TCHAR* argv[])
{
int a[256];
int i = 0, j = 0, count[256] = { 0 };
char string[100] = "Hello world";
for (i = 0; i < 100; i++)
{
for (j = 0; j<256; j++)
{
if (tolower(string[i]) == (j))
{
count[j]++;
}
}
}
for (j = 0; j<256; j++)
{
printf("\n%c -> %d \n", j, count[j]);
}
}
Program is calculating the number of apperances of each character in a string. Now it prints the number of apperances of all 256 characters, whereas i want it to prinf only the character with greatest number of apperances in a string. My idea was to use the selection sort method to the array with the nubmer of apperances, but this is not working, thus my question is how to printf only the character with the greatest number of apperances in the string?
If anybody would have doubts, this is NOT my homework question.
EDIT: I've just noticed that this code printf apperances of characters begining with "j" why is that?
I started typing this before the others showed up, so I'll post it anyway. This is probably nearly the most efficient (increasing efficiency would add some clutter) way of getting an answer, but it doesn't include code to ignore spaces, count characters without regard to case, etc (easy modifications).
most_frequent(const char * str)
{
unsigned counts[256];
unsigned char * cur;
unsigned pos, max;
/* set all counts to zero */
memset(counts, 0, sizeof(counts));
/* count occurences of each character */
for (cur = (unsigned char *)str; *cur; ++cur)
++counts[*cur];
/* find most frequent character */
for (max = 0, pos = 1; pos < 256; ++pos)
if ( counts[pos] > counts[max] )
max = pos;
printf("Character %c occurs %u times.\n", max, counts[max]);
}
Create an array with your char as index.
Keep incrementing the value in the array based on the characters read.
Now get the max out of the array which gives you the most occurring char in your input.
Code will look like:
#include <stdio.h>
#include<string.h>
#include<stdlib.h>
int main(void) {
char buf[100];
int i=0,max =0,t=0;
int a[256];
memset(a,0,sizeof(a));
fgets(buf,100,stdin);
buf[strlen(buf)-1] = '\0';
while(buf[i] != '\0')
{
a[(int)buf[i]]++;
i++;
}
i=0;
for(i=0;i<256;i++)
{
if(a[i] > max)
{
max = a[i];
t = i;
}
}
printf("The most occurring character is %c: Times: %d",t,max);
return 0;
}
Here is a solution for that, based on your own solution, and using qsort().
#include <string.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
struct Frequency
{
int character;
int count;
};
int compare(const void *const lhs, const void *const rhs)
{
return ((struct Frequency *)rhs)->count - ((struct Frequency *)lhs)->count;
}
int main(int argc, char* argv[])
{
int i = 0, j = 0;
struct Frequency count[256];
memset(&count, 0, sizeof(count));
char string[100] = "Hello world";
for (i = 0 ; i < 100 ; i++)
{
for (j = 0 ; j < 256 ; j++)
{
count[j].character = j;
if (tolower(string[i]) == j)
{
count[j].count += 1;
}
}
}
qsort(count, sizeof(count) / sizeof(*count), sizeof(*count), compare);
/* skip the '\0' which was counted many times */
if (isprint(count[1].character))
printf("\nThe most popular character is: %c\n", count[1].character);
else
printf("\nThe most popular character is: \\%03x\n", count[1].character);
for (j = 0 ; j < 256 ; j++)
{
if (isprint(count[j].character))
printf("\n%c -> %d \n", count[j].character, count[j].count);
else
printf("\n\\%03x -> %d \n", count[j].character, count[j].count);
}
}
notice that the '\0' is set for all the remainig bytes in
char string[100] = "Hello world";
so the count of '\0' will be the highest.
You could use strlen() to skip '\0', in the counting loop, but don't
for (i = 0 ; i < strlen(string) ; ++i) ...
do it this way
size_t length = strlen(string);
for (i = 0 ; i < length ; ++i) ...

Resources