In the C language, how do I convert unsigned long value to a string (char *) and keep my source code portable or just recompile it to work on other platform (without rewriting code?
For example, if I have sprintf(buffer, format, value), how do I determine the size of buffer with platform-independent manner?
const int n = snprintf(NULL, 0, "%lu", ulong_value);
assert(n > 0);
char buf[n+1];
int c = snprintf(buf, n+1, "%lu", ulong_value);
assert(buf[n] == '\0');
assert(c == n);
The standard approach is to use sprintf(buffer, "%lu", value); to write a string rep of value to buffer. However, overflow is a potential problem, as sprintf will happily (and unknowingly) write over the end of your buffer.
This is actually a big weakness of sprintf, partially fixed in C++ by using streams rather than buffers. The usual "answer" is to allocate a very generous buffer unlikely to overflow, let sprintf output to that, and then use strlen to determine the actual string length produced, calloc a buffer of (that size + 1) and copy the string to that.
This site discusses this and related problems at some length.
Some libraries offer snprintf as an alternative which lets you specify a maximum buffer size.
you can write a function which converts from unsigned long to str, similar to ltostr library function.
char *ultostr(unsigned long value, char *ptr, int base)
{
unsigned long t = 0, res = 0;
unsigned long tmp = value;
int count = 0;
if (NULL == ptr)
{
return NULL;
}
if (tmp == 0)
{
count++;
}
while(tmp > 0)
{
tmp = tmp/base;
count++;
}
ptr += count;
*ptr = '\0';
do
{
res = value - base * (t = value / base);
if (res < 10)
{
* -- ptr = '0' + res;
}
else if ((res >= 10) && (res < 16))
{
* --ptr = 'A' - 10 + res;
}
} while ((value = t) != 0);
return(ptr);
}
you can refer to my blog here which explains implementation and usage with example.
char buffer [50];
unsigned long a = 5;
int n=sprintf (buffer, "%lu", a);
Try using sprintf:
unsigned long x=1000000;
char buffer[21];
sprintf(buffer,"%lu", x);
Edit:
Notice that you have to allocate a buffer in advance, and have no idea how long the numbers will actually be when you do so. I'm assuming 32bit longs, which can produce numbers as big as 10 digits.
See Carl Smotricz's answer for a better explanation of the issues involved.
For a long value you need to add the length info 'l' and 'u' for unsigned decimal integer,
as a reference of available options see sprintf
#include <stdio.h>
int main ()
{
unsigned long lval = 123;
char buffer [50];
sprintf (buffer, "%lu" , lval );
}
... how do I determine the size of buffer with platform-independent manner?
One of the challenges of converting a unsigned long to a string is how to determine the string size that is needed.
Dynamically
Repeatedly divide the value by 10 until 0 to find size_needed.
value_copy = value;
unsigned size_needed = 1; // For the null character.
if (value_copy < 0) size_needed++; // Only needed for signed types.
do {
size_needed++; // Add 1 per digit.
value_copy /= 10;
} while (value_copy != 0);
Worse case
Find the string length of ULONG_MAX.
Start with the nifty IMAX_BITS(m) which returns the number of bits in a Mersenne Number like ULONG_MAX. (This give us the max bit width even if the type has padding.) Then scale by log102 (0.301...) to find the number of decimal digits and add 2 for rounding and the null character.
#define IMAX_BITS(m) ((m)/((m)%255+1) / 255%255*8 + 7-86/((m)%255+12))
#define LOG2_10_N 28
#define LOG2_10_D 93
#define UNSIGNED_LONG_STRING_SIZE (IMAX_BITS(ULONG_MAX)*LOG2_10_N/LOG2_10_D + 2)
// Slightly different for signed types, one more for the sign:
#define SIGNED_LONG_STRING_SIZE (IMAX_BITS( LONG_MAX)*LOG2_10_N/LOG2_10_D + 3)
Armed with the string size, there are many possible next steps. I like using C99's (and later) compound literal to form the needed space. The space is valid until the end of the block.
char *unsigned_long_to_string(char *dest, unsigned long x) {
sprintf(dest, "%lu", x);
return dest;
}
// Compound literal v-----------------------------------v
#define UNSIGNED_LONG_TO_STRING(u) unsigned_long_to_string((char [UNSIGNED_LONG_STRING_SIZE]){0}, (u))
int main(void) {
puts(UNSIGNED_LONG_TO_STRING(42));
puts(UNSIGNED_LONG_TO_STRING(ULONG_MAX));
}
Output
42
18446744073709551615 // This varies
Related
With a code where I have a struct:
struct fibo_entry { /* Definition of each table entry */
int n;
unsigned long long int lli; /* 64-bit integer */
char *str;
};
I have to solve a Fibonacci sequence where I have the following:
fibo_table = (struct fibo_entry *)malloc(sizeof(struct fibo_entry));
//fibo_table->str = (char *)malloc(1 + 8 * sizeof(char)); // !!??
for (i = 0; i <= n; i++) {
fibo_table[i].n = i;
if (i == 0) {
fibo_table[i].lli = 0;
//sprintf(fibo_table[i].str, "%llu", fibo_table[i].lli);
//fibo_table[i].str = atoi(fibo_table[i].lli);
} else if (i == 1) {
fibo_table[i].lli = 1;
} else {
fibo_table[i].lli = fibo_table[i-1].lli + fibo_table[i-2].lli;
//log10(fibo_table[i].lli);
}
}
The process to calculate Fibonacci is done, the problem that I have comes when I have to calculate the memory that I need to allocate a long long int in the string.
I know that the numbers use 64 bits each and I tried with malloc and the concept that sprintf should work to convert one in another, but I can't find a solution. Every time that I try to run the program, just fail.
If you are writing a (positive) number, n, in decimal notation (as the %llu format specifier will), then the number of digits will be (the integral part of) log10(n) + 1.
So, in order to (pre-)determine the maximum buffer size required, you can use the log10 function on the compiler-defined constant, ULLONG_MAX (this is the maximum value that an unsigned long long int can have). Note that, when allocating the character buffer, you should add 1 to the number of digits, to allow for the nul-terminator in your string.
The following short program may be helpful:
#include <stdio.h>
#include <stdint.h>
#include <math.h>
#include <limits.h>
int main()
{
size_t maxdigits = (size_t)(log10((double)(ULLONG_MAX)) + 1);
printf("Max. digits in unsigned long long = %zu!\n", maxdigits);
printf("Max. value for the type is: %llu\n", ULLONG_MAX);
return 0;
}
On most modern systems, unsigned long long int will be 64 bits, with a maximum value of 18446744073709551615 (20 digits); however, it is better to use the platform/compiler-specific ULLONG_MAX, rather than relying on any particular value being correct.
Further, rather than calculating this maxdigits value multiple times, you need only calculate a 'global' constant once, then re-use that as and when required.
size_t CountDigit(long long int num)
{
size_t count = 0;
if(num < 0)
{
count++;
}
while (num)
{
count++;
num \=10;
}
count++;\\thats for the '\0'
return (count);
}
then you can use count for malloc and after that you can use sprintf or do it yourself, to insert the right chars in it.
How to allocate enough memory to convert an unsigned long long int into string
With an n-bit unsigned integer, a buffer of log10(2^n - 1) + 1 + 1 is needed. +1 for "ceiling" and +1 for the null character.
To find this value at compiler time, could use:
#define LOG10_2_N 302
#define LOG10_2_D 1000
#define ULL_STR_SIZE1 (sizeof (unsigned long long)*CHAR_BIT * LOG10_2_N / LOG10_2_D + 2)
To find this at pre-processor time is a little trickier as we need to find the bit width via macros. This approach also takes space advantage if rare padding bits are used.
// Numbers of bits in a Mersenne Number
// https://mathworld.wolfram.com/MersenneNumber.html
// https://stackoverflow.com/a/4589384/2410359
#define IMAX_BITS(m) ((m)/((m)%255+1) / 255%255*8 + 7-86/((m)%255+12))
#define ULLONG_BIT_WIDTH IMAX_BITS(ULLONG_MAX)
// 28/93 is a tight fraction for log10(2)
#define LOG10_2_N 28
#define LOG10_2_D 93
#define ULL_STR_SIZE2 (ULLONG_BIT_WIDTH * LOG10_2_N / LOG10_2_D + 1 + 1)
ULL_STR_SIZE2 is suitable for #if ULL_STR_SIZE2 ... processing.
fibo_table[i].str = malloc(ULL_STR_SIZE2);
if (fibo_table[i].str) {
sprintf(fibo_table[i].str, "%llu", fibo_table[i].lli);
Or at run-time, to "right size", call snprintf() first and find the size needed for per each integer via the return value of *printf().
int n = snprintf(NULL, 0, "%llu", fibo_table[i].lli);
fibo_table[i].str = malloc(n + 1);
if (fibo_table[i].str) {
sprintf(fibo_table[i].str, "%llu", fibo_table[i].lli);
Or slightly more efficient, form a worst case size temporary buffer, write to it and then duplicate the string.
char tmp[ULL_STR_SIZE2];
snprintf(tmp, sizeof tmp, "%llu", fibo_table[i].lli);
fibo_table[i].str = strdup(tmp);
Alternative: change pointer char *str to an array.
struct fibo_entry {
int n;
unsigned long long int lli;
//char *str;
char *str[ULL_STR_SIZE2];
};
and use
snprintf(fibo_table[i].str, sizeof fibo_table[i].str, "%llu", fibo_table[i].lli);
Best to not assume long long is 64-bit. It is at least 64-bit.
You can calculate how many digits you need to use doing something like number_digits = (int)log10((double)num) + 1; and then reserve enough space with fibo_table[i].str = malloc(number_digits * sizeof(char)); remember you need to do this every for iteration, after those two steps you can now use the sprintf as you were sprintf(fibo_table[i].str, "%llu", fibo_table[i].lli);, code would look something like this:
int number_digits;
for (i = 0; i <= n; i++) {
if (i == 0) {
....
} else if (i == 1) {
....
} else {
....
}
number_digits = (int)log10((double)i) + 1;
fibo_table[i].str = malloc(number_digits*sizeof(char));
sprintf(fibo_table[i].str, "%llu", fibo_table[i].lli);
}
I'm running some test cases against my itoa() function but keep getting
did not allocate memory for the int min value
I'm doing the check but it's something I'm missing here, what is it?
char *ft_itoa(int x) {
char *s;
size_t len;
long int n;
n = x;
if (x == -2147483648)
return (ft_strdup("-2147483648"));
len = ft_intlen(n) + 1;
if (!(s = (char*)malloc(sizeof(char) * len)))
return (NULL);
if (n == 0)
s[0] = '0';
if (n < 0) {
s[0] = '-';
n = -n;
}
s[len - 1] = '\0';
while (n) {
len--;
s[len - 1] = (n % 10) + '0';
n /= 10;
}
return (s);
}
This line:
if (x == -2147483648)
does not do what you think it does. C does not have negative integer constants. This is an unsigned int constant with the value 2^31, that you apply the unary minus operator on. This means that the expression x == -21... will depend on the C standard your compiler uses.
If you use C99 or C11, you'll be fine. There is a signed type that is big enough - long long is guaranteed to be big enough for this number, so both x and -21... will be converted into long long and then compared. But if you're using a C89 compiler and your machine doesn't have a long enough type, you're hitting implementation-defined behavior here:
When an integer is demoted to a signed integer with smaller size, or an unsigned integer is converted to its corresponding signed integer, if the value cannot be represented the result is implementation-defined.
This is why people are saying to use limits.h. Not because they are being pedantic, but because this is dangerous territory. If you look closely at what limits.h contains, you'll most likely find a line like this:
#define INT_MIN (- INT_MAX - 1)
This expression actually has the correct type and value.
Other than that I can't see any errors in the code you posted. If this is not the problem either ft_intlen or ft_strdup are wrong. Or you're calling your function in testing wrong (the same problems apply to -21... when calling tests).
Status: RESOLVED INVALID
Reason: WORKS_FOR_ME
Anyways, I improved on some points.
sizeof(char) is always 1, no need for it.
don't cast malloc
if you handle special case 0, then just handle it in one go.
-2147483648 is very very bad. That's what INT_MIN is for.
return is not a function, don't return (value), just return value.
don't s[len - 1] all the time, better decrements len prior to entering the loop. Or, since you need len + 1 only in the malloc call, just have len as intlen returns it and call malloc using len + 1
ft_itoa.c
#include <stdbool.h>
#include <limits.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <btstr.h>
int ft_intlen(int n) {
char buffer[8192];
return snprintf(buffer, sizeof buffer, "%i", n);
}
char * ft_itoa(int n) {
char * s;
size_t l, len;
bool fix_int_min = false;
if (!n) {
return mstrcpy("0");
}
if (-INT_MAX != INT_MIN && n == INT_MIN) {
++n;
fix_int_min = true;
}
len = ft_intlen(n);
if (!(s = malloc(len + 1))) {
return NULL;
}
if (n < 0) {
s[0] = '-';
n = -n;
}
s[l = len] = '\0';
while (n) {
s[--len] = (n % 10) + '0';
n /= 10;
}
if (fix_int_min) {
--l;
while (s[l] == '9') {
s[l++] = 0;
}
if (s[l] == '-') {
// realloc +1 and write "-1[0....0]\0"
} else {
++s[l];
}
}
return s;
}
main.c
#include <limits.h>
#include <stdio.h>
char * ft_itoa(int n);
void check(int n) {
printf("%i = %s\n", n, ft_itoa(n));
}
int main() {
check(0);
check(-1);
check(1);
check(23);
check(42);
check(4711);
check(1000);
check(INT_MAX);
check(1+INT_MIN);
check(INT_MIN);
}
Result
$ gcc -W -Wall -Wextra -lBtLinuxLibrary ft_itoa.c main.c -o ft_itoa && ./ft_itoa
0 = 0
-1 = -1
1 = 1
23 = 23
42 = 42
4711 = 4711
1000 = 1000
2147483647 = 2147483647
-2147483647 = -2147483647
-2147483648 = -2147483648
You don't need that check. Instead convert it to unsigned, that will fit the absolute value :
size_t ft_uintlen(unsigned n)
{
size_t len = 0;
do {
++len;
n /= 10;
} while(n);
return len;
}
char *ft_itoa(int x)
{
char *s;
size_t len;
unsigned n;
int negative;
negative = x < 0;
n = negative ? 0-(unsigned)x : (unsigned)x;
len = ft_uintlen(n) + negative + 1;
if (!(s = (char*)malloc(len)))
return (NULL);
s[--len] = '\0';
if (negative)
s[0] = '-';
do {
s[--len] = (n % 10) + '0';
n /= 10;
} while(n);
return (s);
}
Note that this uses a new size_t ft_uintlen(unsigned) function that works on unsigned arguments.
Probably problem in your overflow prevention mechanism. You try to assign x of type int to n with type long int. But specification doesn't guarantee that type long int can handle value range large then int. More info can be found "Long Vs. Int".
Use long long int type for n if your compiler supports it. Update your ft_intlen function to int ft_intlen(long long int n). In this case you will be able to handle the whole int type value range and remove the following lines:
if (x == -2147483648)
return (ft_strdup("-2147483648"));
Also error message did not allocate memory for the int min value is not one of the system error numbers. You need to add more logging into your application, especially if it's not possible to debug it for some reason. Check errno for each system function call, e.g.:
char* errmsg;
// Other code skipped here
if (!(s = (char*)malloc(sizeof(char) * len)))
{
errmsg = strerror(errno); // Use strerror_s if possible
printf("Malloc error: %s\n", errmsg);
return (NULL);
}
Potential code failures, in order of suspicion:
ft_strdup() as that code is called with "int min value" and error occurs.
Prototypes lacking for various functions. Especially ft_strdup()/strdup().
Calling/test code is faulty.
"int min value" is larger than -2147483648. (Better to use INT_MIN.)
ft_intlen(n) is coded incorrectly and returns INT_MAX, then code tries malloc(INT_MIN).
int/long both 64-bit. This messes the first s[len - 1] = (n % 10) + '0'; with INT_MIN.
Otherwise, if INT_MIN has the value -2147483648, ft_itoa(int x) is fine.
OP asserts "... strdup just allocates the string, ft_intlen just returns length of string, both pass the test cases – franklinexpress Oct 8 at 7:52"
Passing test cases does not mean it worked without invoking undefined behavior. Best to post ft_intlen(), ft_strdup() and test harness for review.
Candidate portable implementation. No dependency on int/long size or 2's complement. No need for <limits.h> aside from CHAR_BIT which code could assume is 8 without sacrificing too much potability. Works with C89/99/11.
// Buffer size needed to decimal print any `int`
// '-' + Ceiling(value bit size * log10(2)) + \0
#define INT_STR_SIZE (1 + ((CHAR_BIT*sizeof(int) - 1)/3 + 1) + 1)
char *ft_itoa(int x) {
char buf[INT_STR_SIZE];
char *s = buf + sizeof buf - 1; // Set to end of buffer
*s = '\0';
int n = x; // no need for wider types like long
if (n > 0) {
// fold positive numbers to negative ones
// This avoids the special code for `INT_MIN` and need for wider types
n = -n;
}
// Using a do loop avoids special code for `x==0`
do {
// Use `div()` rather than / % in case we are using C89.
// / % has implementation defined results for negative arguments.
div_t qr = div(n, 10);
*--s = (char) ('0' - qr.rem); // Form digit from negative .rem
n = qr.quot;
} while (n);
if (x < 0) {
*--s = '-';
}
// Double check ft_strdup() is coded correctly
// Insure calling code frees the buffer when done.
return ft_strdup(s);
}
The piece of code you gave compile and works on OsX, but with my own ft_stdup and ft_intlen. So you can either show us the code or check them for errors.
I made some tests (including 2147483647, -2147483648). It works nicely.
Anyway, the lines:
if (x == -2147483648)
return (ft_strdup("-2147483648"));
Are useless as long as you copy your x value into a long long variable (Art) before doing any kind of operation it. So you don't need including types.h (notorious moulinette will not give you -42).
It happens that on OsX it works also on long values, but this is non portable safe.
Just use:
INT_MIN
instead of:
-2147483648
in your test:
if (x == INT_MIN)
return (ft_strdup("-2147483648"));
The reason for this is that some compilers could have problems understanding that number.
The standard C library limits.h usually define it as:
#define INT_MIN (-INT_MAX - 1)
to avoid this problem.
I'm new to C.
I'm looking for an example where I could call a function to convert int to string. I found itoabut this is not part of standard C.
I also found sprintf(str, "%d", aInt); but the problem is that I don't know the size of the required str. Hence, how could I pass the right size for the output string
There are optimal ways ways to appropriately size the array to account for variations in sizeof(int), but multiplying by 4 is sufficient for base 10. +1 is needed for the edge case of sizeof(int)==1.
int x; // assign a value to x
char buffer[sizeof(int) * 4 + 1];
sprintf(buffer, "%d", x);
If you need to return the pointer to the string from the function, you should allocate the buffer instead of using stack memory:
char* integer_to_string(int x)
{
char* buffer = malloc(sizeof(char) * sizeof(int) * 4 + 1);
if (buffer)
{
sprintf(buffer, "%d", x);
}
return buffer; // caller is expected to invoke free() on this buffer to release memory
}
In portable C, it's easiest to use snprintf to calculate the size of the array required, and then sprintf for the actual conversion. For example:
char buffer[snprintf(NULL, 0, "%d", x) + 1];
sprintf(buffer, "%d", x);
It's worthwhile noting that this won't work prior to C99, and there's also a neater alternative which works prior to C99 and is type-generic for all integers. That's described in another answer to this question using the multiplication trick, however I noticed the trick proposed there isn't strictly portable either. In environments where CHAR_BIT isn't 8 (for example, some DSPs use 16- or 32- bit bytes), you'll need to change the multiplier.
I presented a similar trick in response to a different question. That code used CHAR_BIT to ensure portability, even when CHAR_BIT changes. It's presented as a macro, and so it's internally documenting; it tells you what the high-level description is, which a multiplication alone can't do.
#include <limits.h>
#include <stddef.h>
#include <stdio.h>
#define digit_count(num) (1 /* sign */ \
+ sizeof (num) * CHAR_BIT / 3 /* digits */ \
+ (sizeof (num) * CHAR_BIT % 3 > 0)/* remaining digit */ \
+ 1) /* NUL terminator */
int main(void) {
short short_number = -32767;
int int_number = 32767;
char short_buffer[digit_count(short_number)] = { 0 };
char int_buffer[digit_count(int_number)];
sprintf(short_buffer, "%d", short_number);
sprintf(int_buffer, "%d", int_number);
}
Use C99 snprintf(). It calculates how much space would be needed
int needed = snprintf(NULL, 0, "%s", value);
if (needed < 1) /* error */;
char *representation = malloc(needed + 1); // add 1 for '\0'
if (!representation) /* error */;
sprintf(representation, "%d", value);
// ... use representation ...
free(representation);
There is a way to do it without any functions, for example this(it can be a little primitive, but still):
char dec_rev[255];
dec_rev[0] = '\0';
int i = 0;
while (val != 0) {
int temp = val % 10;
dec_rev[i] = temp + '0';
//printf("%c\n", dec_rev[i]);
val /= 10;
if (val == 0) {
dec_rev[i + 1] = '\0';
break;
}
i++;
}
char dec[255];
i = 0;
for (int j = strlen(dec_rev) - 1; j != -1; j--) {
dec[i] = dec_rev[j];
i++;
}
After all we get our int stored inside dec[255].
strange that this is not mentioned, but the size of the representation of an int in base 10 is ceil(log10(value)); (or log10 integer version if you want to write it)
thus ceil(log10(5)) => 1
and ceil(log10(555)) => 3
ceil(log10(1000000000)) => 9
obviously you need an extra room for the sign if you need it and another for the '\0'.
Is is possible to convert int to "string" in C just using casting? Without any functions like atoi() or sprintf()?
What I want would be like this:
int main(int argc, char *argv[]) {
int i = 500;
char c[4];
c = (char)i;
i = 0;
i = (int)c;
}
The reason is that I need to generate two random ints (0 to 500) and send both as one string in a message queue to another process. The other process receives the message and do the LCM.
I know how to do with atoi() and itoa(). But my teachers wants just using cast.
Also, why isn't the following possible to compile?
typedef struct
{
int x;
int y;
} int_t;
typedef struct
{
char x[sizeof(int)];
char y[sizeof(int)];
} char_t;
int main(int argc, char *argv[])
{
int_t rand_int;
char_t rand_char;
rand_int.x = (rand() % 501);
rand_int.y = (rand() % 501);
rand_char = (char_t)rand_int;
}
Of course it's not possible, because an array is an object and needs storage. Casts result in values, not objects. Some would say the whole point/power of C is that you have control over the storage and lifetime of objects.
The proper way to generate a string containing a decimal representation of an integer is to create storage for it yourself and use snprintf:
char buf[sizeof(int)*3+2];
snprintf(buf, sizeof buf, "%d", n);
You have to convert 500 to "500".
"500" is the same as '5' then '0' then '0' then 0. The last element 0 is the null terminator of a string.
500 is equal to 5 * 100 + 0 * 10 + 0 * 1. You have to do some math here. Basically you have to use the / operator.
Then this could be also useful: '5' is the same as '0' + 5.
Without giving away an exact coded answer, what you'll want to do is loop through each digit of the integer (by computing its remainder modulo 10 via the % operator), and then add its value to the ASCII value of '0', casting the result back to a char, and placing that result in a null-terminated string.
An example which pretends like implicit casts don't exist might look like this:
char c = (char) ( ((int) '0') + 5 ); // c should now be '5'.
You can determine the length of the resulting string by computing the log base 10 of the number, or by simply allocating it dynamically as you go using realloc().
Casting is a horrible way to do this due to endianness, but here is an example anyhow - there are some occasions where it is useful (unions work better these days though, due to compiler handling of these types of casts).
#include <stdio.h> //for printf
#define INT(x) ((int*)(x)) //these are not endian-safe methods
#define CHAR(x) ((char*)(x))
int main(void)
{
int *x=INT(&"HI !");
printf("%X\n",*x); //look up the ascii and note the order
printf("%s\n",CHAR(x));
return 0;
}
For an int with a value <500, if the most significant byte comes first, then you get a "string" (pointer to a char array) of "" (or {0}) but if the endianness is LSB first (x86 is little endian) then you would get a usable 3 byte "string" char* (not necessarily human readable characters) but there is no guarantee that there will be a zero byte in an integer and since all you have is a pointer to the address where the int was stored, if you were to run normal string functions on it, they would go past the end of the original int into no-mans-land (in small test programs it will often be environment variables) ... anyhow for more portability you can use network byte order (which for little endian is a no-op):
#include <arpa/inet.h>
uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);
These functions just byteswap as necessary to get network byte order. On your x86 they will be optimized away, so you might as well use them for portability.
Just because it is not listed yet: Here a way to convert int to char array with variable size allocation by using snprintf:
int value = 5
// this will just output the length which is to expect
int length = snprintf( NULL, 0, "%d", value );
char* valueAsString = malloc( length + 1 );// one more for 0-terminator
snprintf( valueAsString, length + 1, "%d", value );
get the number of divisions then add one by one to your buffer
char *int2str(int nb) {
int i = 0;
int div = 1;
int cmp = nb;
char *nbr = malloc(sizeof(char) * 12);
if (!nbr)
return (NULL);
if (nb < 0)
nbr[i++] = '-';
while ((cmp /= 10) != 0)
div = div * 10;
while (div > 0) {
nbr[i++] = abs(nb / div) + 48;
nb = nb % div;
div /= 10;
}
nbr[i] = '\0';
return (nbr);
}
Even more compact:
char *lotaa(long long nb) {
int size = (nb ? floor(log10(llabs(nb))) : 0) + (nb >= 0 ? 1 : 2);
char *str = malloc(size + 1);
str[0] = '-';
str[size] = 0;
for(nb = llabs(nb); nb > 0 || (size > 0 && str[1] == 0); nb /= 10)
str[--size] = '0' + nb % 10;
return (str);
}
I was wondering if my implementation of an "itoa" function is correct. Maybe you can help me getting it a bit more "correct", I'm pretty sure I'm missing something. (Maybe there is already a library doing the conversion the way I want it to do, but... couldn't find any)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
char * itoa(int i) {
char * res = malloc(8*sizeof(int));
sprintf(res, "%d", i);
return res;
}
int main(int argc, char *argv[]) {
...
// Yet, another good itoa implementation
// returns: the length of the number string
int itoa(int value, char *sp, int radix)
{
char tmp[16];// be careful with the length of the buffer
char *tp = tmp;
int i;
unsigned v;
int sign = (radix == 10 && value < 0);
if (sign)
v = -value;
else
v = (unsigned)value;
while (v || tp == tmp)
{
i = v % radix;
v /= radix;
if (i < 10)
*tp++ = i+'0';
else
*tp++ = i + 'a' - 10;
}
int len = tp - tmp;
if (sign)
{
*sp++ = '-';
len++;
}
while (tp > tmp)
*sp++ = *--tp;
return len;
}
// Usage Example:
char int_str[15]; // be careful with the length of the buffer
int n = 56789;
int len = itoa(n,int_str,10);
The only actual error is that you don't check the return value of malloc for null.
The name itoa is kind of already taken for a function that's non-standard, but not that uncommon. It doesn't allocate memory, rather it writes to a buffer provided by the caller:
char *itoa(int value, char * str, int base);
If you don't want to rely on your platform having that, I would still advise following the pattern. String-handling functions which return newly allocated memory in C are generally more trouble than they're worth in the long run, because most of the time you end up doing further manipulation, and so you have to free lots of intermediate results. For example, compare:
void delete_temp_files() {
char filename[20];
strcpy(filename, "tmp_");
char *endptr = filename + strlen(filename);
for (int i = 0; i < 10; ++i) {
itoa(endptr, i, 10); // itoa doesn't allocate memory
unlink(filename);
}
}
vs.
void delete_temp_files() {
char filename[20];
strcpy(filename, "tmp_");
char *endptr = filename + strlen(filename);
for (int i = 0; i < 10; ++i) {
char *number = itoa(i, 10); // itoa allocates memory
strcpy(endptr, number);
free(number);
unlink(filename);
}
}
If you had reason to be especially concerned about performance (for instance if you're implementing a stdlib-style library including itoa), or if you were implementing bases that sprintf doesn't support, then you might consider not calling sprintf. But if you want a base 10 string, then your first instinct was right. There's absolutely nothing "incorrect" about the %d format specifier.
Here's a possible implementation of itoa, for base 10 only:
char *itobase10(char *buf, int value) {
sprintf(buf, "%d", value);
return buf;
}
Here's one which incorporates the snprintf-style approach to buffer lengths:
int itobase10n(char *buf, size_t sz, int value) {
return snprintf(buf, sz, "%d", value);
}
A good int to string or itoa() has these properties;
Works for all [INT_MIN...INT_MAX], base [2...36] without buffer overflow.
Does not assume int size.
Does not require 2's complement.
Does not require unsigned to have a greater positive range than int. In other words, does not use unsigned.
Allows use of '-' for negative numbers, even when base != 10.
Tailor the error handling as needed. (needs C99 or later):
char* itostr(char *dest, size_t size, int a, int base) {
// Max text needs occur with itostr(dest, size, INT_MIN, 2)
char buffer[sizeof a * CHAR_BIT + 1 + 1];
static const char digits[36] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
if (base < 2 || base > 36) {
fprintf(stderr, "Invalid base");
return NULL;
}
// Start filling from the end
char* p = &buffer[sizeof buffer - 1];
*p = '\0';
// Work with negative `int`
int an = a < 0 ? a : -a;
do {
*(--p) = digits[-(an % base)];
an /= base;
} while (an);
if (a < 0) {
*(--p) = '-';
}
size_t size_used = &buffer[sizeof(buffer)] - p;
if (size_used > size) {
fprintf(stderr, "Scant buffer %zu > %zu", size_used , size);
return NULL;
}
return memcpy(dest, p, size_used);
}
I think you are allocating perhaps too much memory. malloc(8*sizeof(int)) will give you 32 bytes on most machines, which is probably excessive for a text representation of an int.
i found an interesting resource dealing with several different issues with the itoa implementation
you might wanna look it up too
itoa() implementations with performance tests
I'm not quite sure where you get 8*sizeof(int) as the maximum possible number of characters -- ceil(8 / (log(10) / log(2))) yields a multiplier of 3*. Additionally, under C99 and some older POSIX platforms you can create an accurately-allocating version with sprintf():
char *
itoa(int i)
{
int n = snprintf(NULL, 0, "%d", i) + 1;
char *s = malloc(n);
if (s != NULL)
snprintf(s, n, "%d", i);
return s;
}
HTH
You should use a function in the printf family for this purpose. If you'll be writing the result to stdout or a file, use printf/fprintf. Otherwise, use snprintf with a buffer big enough to hold 3*sizeof(type)+2 bytes or more.
sprintf is quite slow, if performance matters it is probably not the best solution.
if the base argument is a power of 2 the conversion can be done with a shift and masking, and one can avoid reversing the string by recording the digits from the highest positions. For instance, something like this for base=16
int num_iter = sizeof(int) / 4;
const char digits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
/* skip zeros in the highest positions */
int i = num_iter;
for (; i >= 0; i--)
{
int digit = (value >> (bits_per_digit*i)) & 15;
if ( digit > 0 ) break;
}
for (; i >= 0; i--)
{
int digit = (value >> (bits_per_digit*i)) & 15;
result[len++] = digits[digit];
}
For decimals there is a nice idea to use a static array big enough to record the numbers in the reversed order, see here
Integer-to-ASCII needs to convert data from a standard integer type
into an ASCII string.
All operations need to be performed using pointer arithmetic, not array indexing.
The number you wish to convert is passed in as a signed 32-bit integer.
You should be able to support bases 2 to 16 by specifying the integer value of the base you wish to convert to (base).
Copy the converted character string to the uint8_t* pointer passed in as a parameter (ptr).
The signed 32-bit number will have a maximum string size (Hint: Think base 2).
You must place a null terminator at the end of the converted c-string Function should return the length of the converted data (including a negative sign).
Example my_itoa(ptr, 1234, 10) should return an ASCII string length of 5 (including the null terminator).
This function needs to handle signed data.
You may not use any string functions or libraries.
.
uint8_t my_itoa(int32_t data, uint8_t *ptr, uint32_t base){
uint8_t cnt=0,sgnd=0;
uint8_t *tmp=calloc(32,sizeof(*tmp));
if(!tmp){exit(1);}
else{
for(int i=0;i<32;i++){
if(data<0){data=-data;sgnd=1;}
if(data!=0){
if(data%base<10){
*(tmp+i)=(data%base)+48;
data/=base;
}
else{
*(tmp+i)=(data%base)+55;
data/=base;
}
cnt++;
}
}
if(sgnd){*(tmp+cnt)=45;++cnt;}
}
my_reverse(tmp, cnt);
my_memcopy(tmp,ptr,cnt);
return ++cnt;
}
ASCII-to-Integer needs to convert data back from an ASCII represented string into an integer type.
All operations need to be performed using pointer arithmetic, not array indexing
The character string to convert is passed in as a uint8_t * pointer (ptr).
The number of digits in your character set is passed in as a uint8_t integer (digits).
You should be able to support bases 2 to 16.
The converted 32-bit signed integer should be returned.
This function needs to handle signed data.
You may not use any string functions or libraries.
.
int32_t my_atoi(uint8_t *ptr, uint8_t digits, uint32_t base){
int32_t sgnd=0, rslt=0;
for(int i=0; i<digits; i++){
if(*(ptr)=='-'){*ptr='0';sgnd=1;}
else if(*(ptr+i)>'9'){rslt+=(*(ptr+i)-'7');}
else{rslt+=(*(ptr+i)-'0');}
if(!*(ptr+i+1)){break;}
rslt*=base;
}
if(sgnd){rslt=-rslt;}
return rslt;
}
I don't know about good, but this is my implementation that I did while learning C
static int ft_getintlen(int value)
{
int l;
int neg;
l = 1;
neg = 1;
if (value < 0)
{
value *= -1;
neg = -1;
}
while (value > 9)
{
l++;
value /= 10;
}
if (neg == -1)
{
return (l + 1);
}
return (l);
}
static int ft_isneg(int n)
{
if (n < 0)
return (-1);
return (1);
}
static char *ft_strcpy(char *dest, const char *src)
{
unsigned int i;
i = 0;
while (src[i] != '\0')
{
dest[i] = src[i];
i++;
}
dest[i] = src[i];
return (dest);
}
char *ft_itoa(int n)
{
size_t len;
char *instr;
int neg;
neg = ft_isneg(n);
len = ft_getintlen(n);
instr = (char *)malloc((sizeof(char) * len) + 1);
if (n == -2147483648)
return (ft_strcpy(instr, "-2147483648"));
if (!instr)
return (NULL);
if (neg == -1)
n *= -1;
instr[len--] = 0;
if (n == 0)
instr[len--] = 48;
while (n)
{
instr[len--] = ((n % 10) + 48);
n /= 10;
}
if (neg == -1)
instr[len] = '-';
return (instr);
}
This should work:
#include <string.h>
#include <stdlib.h>
#include <math.h>
char * itoa_alloc(int x) {
int s = x<=0 ? 1 ? 0; // either space for a - or for a 0
size_t len = (size_t) ceil( log10( abs(x) ) );
char * str = malloc(len+s + 1);
sprintf(str, "%i", x);
return str;
}
If you don't want to have to use the math/floating point functions (and have to link in the math libraries) you should be able to find non-floating point versions of log10 by searching the Web and do:
size_t len = my_log10( abs(x) ) + 1;
That might give you 1 more byte than you needed, but you'd have enough.
There a couple of suggestions I might make. You can use a static buffer and strdup to avoid repeatedly allocating too much memory on subsequent calls. I would also add some error checking.
char *itoa(int i)
{
static char buffer[12];
if (snprintf(buffer, sizeof(buffer), "%d", i) < 0)
return NULL;
return strdup(buffer);
}
If this will be called in a multithreaded environment, remove "static" from the buffer declaration.
This is chux's code without safety checks and the ifs. Try it online:
char* itostr(char * const dest, size_t const sz, int a, int const base) {
bool posa = a >= 0;
char buffer[sizeof a * CHAR_BIT + 1];
static const char digits[36] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
char* p = &buffer[sizeof buffer - 1];
do {
*(p--) = digits[abs(a % base)];
a /= base;
} while (a);
*p = '-';
p += posa;
size_t s = &buffer[sizeof(buffer)] - p;
memcpy(dest, p, s);
dest[s] = '\0';
return dest;
}
main()
{
int i=1234;
char stmp[10];
#if _MSC_VER
puts(_itoa(i,stmp,10));
#else
puts((sprintf(stmp,"%d",i),stmp));
#endif
return 0;
}