How to convert a decimal ascii string to integer array in C? - c

I have written a program that works with IPv6 addresses, and I needed code that converts a four-integer array to decimal string that represented number of IPv6 addresses[1]. Now I ran into the situation when I need to do reverse: convert possibly large number (that do not fits into uint32_t or uint64_t, so atol() or strtol() are helpless here) represented as a single string to four-integer or byte (uint8_t) array (I converted function from [1] from 4-int to variable-uint8_t).
Is there any way to do that?
[1] How to convert a 128-bit integer to a decimal ascii string in C?
Thanks. This is my first question here, so sorry for bad English if any.

This is the kind of situation when using a library is recommended.
Using GMP, you can do these conversions (gmp.c):
#include <stdio.h>
#include <stdlib.h>
#include <gmp.h>
int main(int argc, char *argv)
{
// From string
char *s ="199999999999999999999999999999999999999";
mpz_t i;
// To big number, using GMP
// 10 here means base 10.
mpz_init_set_str(i, s, 10);
// Just to test if s is 128 bits long
printf("%s can be represented with %d digits in base 2\n",s, mpz_sizeinbase(i, 2));
// Then you can print it in hex
gmp_printf("%#32ZX\n", i);
// Or convert it back to int[4]
unsigned int a[4];
mpz_export(&a, NULL, 1, 4, 0, 0, i);
for(int x=0;x<4;x++)
printf("%X\n", a[x]);
mpz_clear(i);
return 0;
}
Output:
199999999999999999999999999999999999999 can be represented with 128 digits in base 2
0X96769950B50D88F41314447FFFFFFFFF
96769950
B50D88F4
1314447F
FFFFFFFF
I tested this code on a 32 bit Linux system. Please pay attention to different int sizes and endianess on different platforms.
You probably want the result in big endian, if so, just change mz_export to:
mpz_export(&a, NULL, 1, 4, 1, 0, i);
To compile the example, don't forget to install gmp and to add -lgmp -std=c99 on gcc command line parameters.
On Ubuntu, you can install gmp with:
sudo apt-get install libgmp-dev
And compile the example, gmp.c:
gcc gmp.c -o gmp -lgmp -std=c99
This code can be a good start for your conversions. You can also initialize i to be a fixed 128 bit number (using init functions of GMP), just in case your big number starts with zeros.

Related

Issues with sprintf

I have been trying to use sprintf to add " to the start and end of a integer, however when i use more than 10 digits the program returns the wrong number:
int data2 = 12345678910;
char data3[2];
sprintf(data3,"\"%i\"", data2);
send(data3);
The send function outputs the integer to the screen.
The result i am getting back is :
"-108508098"
The send function works as i use it elsewhere and it does what it is suppose to.
Before your edit, your issue is not only with sprintf (which BTW you should not use, prefer snprintf), it is with integral numbers in C (they have a limited amount of bits, e.g. 64 bits at most on my Linux desktop....; read wikipages on computer number format & C data types).
Your use of sprintf is completely wrong (you've got a buffer overflow, which is an undefined behavior). You should code:
char buffer[32];
snprintf(buffer, sizeof(buffer), "%i", data2);
sendsomewhere(buffer);
Notice that on POSIX send needs 4 arguments. You should rename your function to sendsomewhere
You should read more about <stdint.h> and <limits.h>
You probably want to use bignums (or at least int64_t or perhaps long long to represent numbers like 12345678910). Don't reinvent bignums (they are difficult to implement efficiently). Use some library like gmplib
If 64 bits are enough for you (so if your numbers would always be between -263 i.e. −9223372036854775808 and 263-1 i.e. 9223372036854775807), consider using long long (or unsigned long long) numbers of C99 or C11:
long long data2 = 12345678910;
char buffer[32];
snprintf(buffer, sizeof(buffer), "%lld", data2);
sendsomewhere(buffer);
If 64 bits are not enough, you should use bigints (but some recent compilers might provide some _int128_t type for 128-bits ints)
Don't forget to enable all the warnings & debug info when compiling (e.g. with gcc -Wall -Wextra -g), then learn how to use the debugger (e.g. gdb)
data2 is overflown by the value to which you have initialized it to.
data3 should be able to hold atleast 11 bytes if data2 is of int datatype (+1 for NULL termination), for which you have allocated only 2 bytes.
Here is an example code snippet:
#include <stdio.h>
int main(void)
{
unsigned long long data2 = 12345678910;
char data3[32];
snprintf(data3, sizeof(data3), "\"%llu\"", data2);
printf("%s\n", data3);
return 0;
}

why pointer variable not showing 100 digits?

aim: i had a requirement for accuracy i need 100 digits to be displayed or atleast 50 digits
try 1: first i had used integer variable then it displayed only 10 digits
try 2: with the help of my friend i used pointers concept it successfully had input 50 to 100 digits but pointer variable display only 10 digits
the program i had written was
#include <stdio.h>
#include <string.h>
main()
{
int *p;
p=(int*)malloc(100*sizeof(int));
*p=1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890;
printf("%d",*p);
}
on executing the above procedure i'm getting a garbage value
thanks in advance
You need to use a bignum (arbitrary precision big numbers) library, since native int or long have a precision limited by the C implementation - ie the hardware (often 32 or 64 bits; see also <stdint.h> header and int32_t & int64_t types). I suggest using GMPlib; you need to be fluent in C to use such libraries. Read documentation of GMLib.
Don't try to code bignumber arithmetic yourself. You'll use inefficient algorithms. Efficient algorithms for bignums are difficult to understand and to invent. You can still get a PhD on that. So use some existing bignum library.
So you might code something like the following to multiply your bignum by 137 and print the result
mpz_t bign;
mpz_t bigr;
// initialize bign from a literal string
mpz_init_set_str (bign,
"12345678901234567890123456789012345678901234567890"
"12345678901234567890123456789012345678901234567890",
10);
// initialize bigr
mpz_init(bigr);
/// compute bigr = bign * 137 (137 is a long, not a bignum)
mpz_mul_si(bigr, bign, 137L);
/// print bigr on stdout in base 10
mpz_out_str (stdout, 10, bigr);
/// clear all the numbers
mpz_clear(bign);
mpz_clear(bigr);
On a Linux system with GMP installed, you could compile such a code (in yoursource.c) using:
gcc -Wall -Wextra -g yoursource.c -lgmp -o yourprog
On other systems you might need some -I and -L arguments to gcc. When you have debugged your program, ask the compiler to optimize it with -O2
Notice that some languages (Common Lisp, Scheme, Python) have built-in bignums.
BTW, your main function is incorrectly defined. It should be defined as int main(int argc, char**argv) ...
To answer the first part, a single signed integer (assuming 32 bits) can take values between -2,147,483,648 and +2,147,483,647
This is where your ten digits comes from.
Depending on your compiler, you may have unsigned long long available (64 bits) but that still only offers you a maximum or 0..18,446,744,073,709,551,615 (20 digits)
To handle 100-digit numbers will require some jiggery-pokery!
int * p = malloc(100*sizeof(int));
Allocates memory for an array of 100 int.
*p= ....
In fact is the same as
p[0]=...
So this
*p=1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890;
assigns to an int.
An int may hold not more then a 32 bits (less on some platforms). The largest 32bit (positive) integer is 2147483647.
C is a language close to the hardware. So you need to understand the storage capabilities and limitations of its data types.
An int on a PC is only able to store 32 bit or 64 bit values, depending on your hardware and OS version.
Yes, you can implement routines for handling larger value, and using a linked list of digits is one way do it.
You can't store such a long digit in an int variable or a pointer which is pointing to type int.
If int is of 32 bit, the range is [−2147483647,+2147483647]. C data types
To store the large value you can use a char pointer and initialized it with the string constant.
For example:
#include <stdio.h>
#include <stdlib.h>
main()
{
char *p = "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890";
printf("%s\n",p);
}

why pointer variable not showing 100 digits? [duplicate]

aim: i had a requirement for accuracy i need 100 digits to be displayed or atleast 50 digits
try 1: first i had used integer variable then it displayed only 10 digits
try 2: with the help of my friend i used pointers concept it successfully had input 50 to 100 digits but pointer variable display only 10 digits
the program i had written was
#include <stdio.h>
#include <string.h>
main()
{
int *p;
p=(int*)malloc(100*sizeof(int));
*p=1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890;
printf("%d",*p);
}
on executing the above procedure i'm getting a garbage value
thanks in advance
You need to use a bignum (arbitrary precision big numbers) library, since native int or long have a precision limited by the C implementation - ie the hardware (often 32 or 64 bits; see also <stdint.h> header and int32_t & int64_t types). I suggest using GMPlib; you need to be fluent in C to use such libraries. Read documentation of GMLib.
Don't try to code bignumber arithmetic yourself. You'll use inefficient algorithms. Efficient algorithms for bignums are difficult to understand and to invent. You can still get a PhD on that. So use some existing bignum library.
So you might code something like the following to multiply your bignum by 137 and print the result
mpz_t bign;
mpz_t bigr;
// initialize bign from a literal string
mpz_init_set_str (bign,
"12345678901234567890123456789012345678901234567890"
"12345678901234567890123456789012345678901234567890",
10);
// initialize bigr
mpz_init(bigr);
/// compute bigr = bign * 137 (137 is a long, not a bignum)
mpz_mul_si(bigr, bign, 137L);
/// print bigr on stdout in base 10
mpz_out_str (stdout, 10, bigr);
/// clear all the numbers
mpz_clear(bign);
mpz_clear(bigr);
On a Linux system with GMP installed, you could compile such a code (in yoursource.c) using:
gcc -Wall -Wextra -g yoursource.c -lgmp -o yourprog
On other systems you might need some -I and -L arguments to gcc. When you have debugged your program, ask the compiler to optimize it with -O2
Notice that some languages (Common Lisp, Scheme, Python) have built-in bignums.
BTW, your main function is incorrectly defined. It should be defined as int main(int argc, char**argv) ...
To answer the first part, a single signed integer (assuming 32 bits) can take values between -2,147,483,648 and +2,147,483,647
This is where your ten digits comes from.
Depending on your compiler, you may have unsigned long long available (64 bits) but that still only offers you a maximum or 0..18,446,744,073,709,551,615 (20 digits)
To handle 100-digit numbers will require some jiggery-pokery!
int * p = malloc(100*sizeof(int));
Allocates memory for an array of 100 int.
*p= ....
In fact is the same as
p[0]=...
So this
*p=1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890;
assigns to an int.
An int may hold not more then a 32 bits (less on some platforms). The largest 32bit (positive) integer is 2147483647.
C is a language close to the hardware. So you need to understand the storage capabilities and limitations of its data types.
An int on a PC is only able to store 32 bit or 64 bit values, depending on your hardware and OS version.
Yes, you can implement routines for handling larger value, and using a linked list of digits is one way do it.
You can't store such a long digit in an int variable or a pointer which is pointing to type int.
If int is of 32 bit, the range is [−2147483647,+2147483647]. C data types
To store the large value you can use a char pointer and initialized it with the string constant.
For example:
#include <stdio.h>
#include <stdlib.h>
main()
{
char *p = "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890";
printf("%s\n",p);
}

Convert Int to Hexdecimal without using 'printf' (C Programming)

Is it possible to Convert Int to Hexdecimal without using 'printf'?
Best if the all the value are placed in the variable itself and some sample code with explanation.
The decimal and hexadecimal systems are just ways of expressing the value of the int. In a way "it is already a hexadecimal".
I think you can use itoa in stdlib.h :
char * itoa ( int value, char * str, int base ); or sprintf(str,"%x",value);
The documentation : itoa documentation
Of course it is possible. Just think about how printf itself was originally implemented...
I won't give you a full solution, only hints, based on which you can experiment with the implementation in code:
An 8-bit number can be expressed as 2 hex digits, which contain the higher and lower 4 bits, respectively. To get these bits, you can use the bit-shift (>>) and mask (&) operators.
Once you have a 4-bit value, you can easily map it to the correct hex digit using a sequence of ifs, or (as a more elegant solution) by indexing into a character array.
Hexdecival vs Decimal vs Binary..etc.. are only different bases that represent the same number. printf doesn't convert your number, it generates an hexdecimal string representation of your number. If you want to implement your own study how to make a conversion between decimal and hexdecimal bases.
Yes, it is definitely possible to convert an integer to a hexadecimal string without using the "printf" family of formatting functions.
You can write such a function by converting the number from base-10 (as we think about it) to base-16 (hexadecimal) and printing the digits in that representation (0-9A-F). This will require you to think a lot about the bases we use to represent numbers.
If you are referring to displaying an int as a hexadecimal number in C, than you will have to write a function that does the same thing as printf.
If you are referring to casting or internal representation, it can't be done because hexadecimal is not a data type.
An int is stored in your computer as a binary number. In fact, since hex can be interpreted as a shorthand for writing binary, you might even say that when you print out a decimal number using printf, it has to be converted from hex to decimal.
it's an example for convert a char array to hex string format
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
unsigned char d=255;
char hex_array[16]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
char *array_to_hex_string(uint8_t data[],int size);
char test_data[3] = {'0',188,255};
int main()
{
printf("%s",array_to_hex_string(test_data,3));
return 0;
}
char *array_to_hex_string(uint8_t data[],int size){
int i,j;
char *hex_string = (char *)malloc((2*size) * sizeof(data[0]));
for(i=0;i<size;i++){
hex_string[j] = hex_array[(data[i]>>4)];
hex_string[j+1] = hex_array[(data[i] & 15)];
j +=2;
}
return (char *)hex_string;
}
cout << hex << intvar << endl;
But if you want an answer that gives you an A for your homework, you're not going to get lucky :)

C convert hex to decimal format

Compiling on linux using gcc.
I would like to convert this to hex. 10 which would be a.
I have managed to do this will the code below.
unsigned int index = 10;
char index_buff[5] = {0};
sprintf(index_buff, "0x%x", index);
data_t.un32Index = port_buff;
However, the problem is that I need to assign it to a structure
and the element I need to assign to is an unsigned int type.
This works however:
data_t.un32index = 0xa;
However, my sample code doesn't work as it thinks I am trying to convert
from an string to a unsigned int.
I have tried this, but this also failed
data_t.un32index = (unsigned int) *index_buff;
Many thanks for any advice,
Huh? The decimal/hex doesn't matter if you have the value in a variable. Just do
data_t.un32index = index;
Decimal and hex are just notation when printing numbers so humans can read them.
For a C (or C++, or Java, or any of a number of languages where these types are "primitives" with semantics closely matching those of machine registers) integer variable, the value it holds can never be said to "be in hex".
The value is held in binary (in all typical modern electronic computers, which are digital and binary in nature) in the memory or register backing the variable, and you can then generate various string representations, which is when you need to pick a base to use.
I agree with the previous answers, but I thought I'd share code that actually converts a hex string to an unsigned integer just to show how it's done:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
char *hex_value_string = "deadbeef";
unsigned int out;
sscanf(hex_value_string, "%x", &out);
printf("%o %o\n", out, 0xdeadbeef);
printf("%x %x\n", out, 0xdeadbeef);
return 0;
}
Gives this when executed:
emil#lanfear /home/emil/dev $ ./hex
33653337357 33653337357
deadbeef deadbeef
However, my sample code doesn't work as it thinks I am trying to convert from an string to a unsigned int.
This is because when you write the following:
data_t.un32index = index_buff;
you do have a type mismatch. You are trying to assign a character array index_buff to an unsigned int i.e. data_t.un32index.
You should be able to assign the index as suggested directly to data_t.un32index.

Resources