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.
Related
Right now I am trying to convert an int to a char in C programming. After doing research, I found that I should be able to do it like this:
int value = 10;
char result = (char) value;
What I would like is for this to return 'A' (and for 0-9 to return '0'-'9') but this returns a new line character I think.
My whole function looks like this:
char int2char (int radix, int value) {
if (value < 0 || value >= radix) {
return '?';
}
char result = (char) value;
return result;
}
to convert int to char you do not have to do anything
char x;
int y;
/* do something */
x = y;
only one int to char value as the printable (usually ASCII) digit like in your example:
const char digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
int inttochar(int val, int base)
{
return digits[val % base];
}
if you want to convert to the string (char *) then you need to use any of the stansdard functions like sprintf, itoa, ltoa, utoa, ultoa .... or write one yourself:
char *reverse(char *str);
const char digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
char *convert(int number, char *buff, int base)
{
char *result = (buff == NULL || base > strlen(digits) || base < 2) ? NULL : buff;
char sign = 0;
if (number < 0)
{
sign = '-';
}
if (result != NULL)
{
do
{
*buff++ = digits[abs(number % (base ))];
number /= base;
} while (number);
if(sign) *buff++ = sign;
if (!*result) *buff++ = '0';
*buff = 0;
reverse(result);
}
return result;
}
A portable way of doing this would be to define a
const char* foo = "0123456789ABC...";
where ... are the rest of the characters that you want to consider.
Then and foo[value] will evaluate to a particular char. For example foo[0] will be '0', and foo[10] will be 'A'.
If you assume a particular encoding (such as the common but by no means ubiquitous ASCII) then your code is not strictly portable.
Characters use an encoding (typically ASCII) to map numbers to a particular character. The codes for the characters '0' to '9' are consecutive, so for values less than 10 you add the value to the character constant '0'. For values 10 or more, you add the value minus 10 to the character constant 'A':
char result;
if (value >= 10) {
result = 'A' + value - 10;
} else {
result = '0' + value;
}
Converting Int to Char
I take it that OP wants more that just a 1 digit conversion as radix was supplied.
To convert an int into a string, (not just 1 char) there is the sprintf(buf, "%d", value) approach.
To do so to any radix, string management becomes an issue as well as dealing the corner case of INT_MIN
The following C99 solution returns a char* whose lifetime is valid to the end of the block. It does so by providing a compound literal via the macro.
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
// Maximum buffer size needed
#define ITOA_BASE_N (sizeof(unsigned)*CHAR_BIT + 2)
char *itoa_base(char *s, int x, int base) {
s += ITOA_BASE_N - 1;
*s = '\0';
if (base >= 2 && base <= 36) {
int x0 = x;
do {
*(--s) = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[abs(x % base)];
x /= base;
} while (x);
if (x0 < 0) {
*(--s) = '-';
}
}
return s;
}
#define TO_BASE(x,b) itoa_base((char [ITOA_BASE_N]){0} , (x), (b))
Sample usage and tests
void test(int x) {
printf("base10:% 11d base2:%35s base36:%7s ", x, TO_BASE(x, 2), TO_BASE(x, 36));
printf("%ld\n", strtol(TO_BASE(x, 36), NULL, 36));
}
int main(void) {
test(0);
test(-1);
test(42);
test(INT_MAX);
test(-INT_MAX);
test(INT_MIN);
}
Output
base10: 0 base2: 0 base36: 0 0
base10: -1 base2: -1 base36: -1 -1
base10: 42 base2: 101010 base36: 16 42
base10: 2147483647 base2: 1111111111111111111111111111111 base36: ZIK0ZJ 2147483647
base10:-2147483647 base2: -1111111111111111111111111111111 base36:-ZIK0ZJ -2147483647
base10:-2147483648 base2: -10000000000000000000000000000000 base36:-ZIK0ZK -2147483648
Ref How to use compound literals to fprintf() multiple formatted numbers with arbitrary bases?
Check out the ascii table
The values stored in a char are interpreted as the characters corresponding to that table. The value of 10 is a newline
So characters in C are based on ASCII (or UTF-8 which is backwards-compatible with ascii codes). This means that under the hood, "A" is actually the number "65" (except in binary rather than decimal). All a "char" is in C is an integer with enough bytes to represent every ASCII character. If you want to convert an int to a char, you'll need to instruct the computer to interpret the bytes of an int as ASCII values - and it's been a while since I've done C, but I believe the compiler will complain since char holds fewer bytes than int. This means we need a function, as you've written. Thus,
if(value < 10) return '0'+value;
return 'A'+value-10;
will be what you want to return from your function. Keep your bounds checks with "radix" as you've done, imho that is good practice in C.
1. Converting int to char by type casting
Source File charConvertByCasting.c
#include <stdio.h>
int main(){
int i = 66; // ~~Type Casting Syntax~~
printf("%c", (char) i); // (type_name) expression
return 0;
}
Executable charConvertByCasting.exe command line output:
C:\Users\boqsc\Desktop\tcc>tcc -run charconvert.c
B
Additional resources:
https://www.tutorialspoint.com/cprogramming/c_type_casting.htm
https://www.tutorialspoint.com/cprogramming/c_data_types.htm
2. Convert int to char by assignment
Source File charConvertByAssignment.c
#include <stdio.h>
int main(){
int i = 66;
char c = i;
printf("%c", c);
return 0;
}
Executable charConvertByAssignment.exe command line output:
C:\Users\boqsc\Desktop\tcc>tcc -run charconvert.c
B
You can do
char a;
a = '0' + 5;
You will get character representation of that number.
Borrowing the idea from the existing answers, i.e. making use of array index.
Here is a "just works" simple demo for "integer to char[]" conversion in base 10, without any of <stdio.h>'s printf family interfaces.
Test:
$ cc -o testint2str testint2str.c && ./testint2str
Result: 234789
Code:
#include <stdio.h>
#include <string.h>
static char digits[] = "0123456789";
void int2str (char *buf, size_t sz, int num);
/*
Test:
cc -o testint2str testint2str.c && ./testint2str
*/
int
main ()
{
int num = 234789;
char buf[1024] = { 0 };
int2str (buf, sizeof buf, num);
printf ("Result: %s\n", buf);
}
void
int2str (char *buf, size_t sz, int num)
{
/*
Convert integer type to char*, in base-10 form.
*/
char *bufp = buf;
int i = 0;
// NOTE-1
void __reverse (char *__buf, int __start, int __end)
{
char __bufclone[__end - __start];
int i = 0;
int __nchars = sizeof __bufclone;
for (i = 0; i < __nchars; i++)
{
__bufclone[i] = __buf[__end - 1 - i];
}
memmove (__buf, __bufclone, __nchars);
}
while (num > 0)
{
bufp[i++] = digits[num % 10]; // NOTE-2
num /= 10;
}
__reverse (buf, 0, i);
// NOTE-3
bufp[i] = '\0';
}
// NOTE-1:
// "Nested function" is GNU's C Extension. Put it outside if not
// compiled by GCC.
// NOTE-2:
// 10 can be replaced by any radix, like 16 for hexidecimal outputs.
//
// NOTE-3:
// Make sure inserting trailing "null-terminator" after all things
// done.
NOTE-1:
"Nested function" is GNU's C Extension. Put it outside if not
compiled by GCC.
NOTE-2:
10 can be replaced by any radix, like 16 for hexidecimal outputs.
NOTE-3:
Make sure inserting trailing "null-terminator" after all things
done.
I'm just reading "C Interfaces and Implementations". There are some really interesting concepts described in the book. The code is quite ugly sometimes (in my opinion), but now I got a question regarding conversion of an integer/long to a string (char array). What is described in the book is:
const char *Atom_int(long n) {
char str[43];
char *s = str + sizeof str;
unsigned long m;
if (n == LONG_MIN)
m = LONG_MAX + 1UL;
else if (n < 0)
m = -n;
else
m = n;
do
*--s = m%10 + '0';
while ((m /= 10) > 0);
if (n < 0)
*--s = '-';
return Atom_new(s, str + sizeof str - s);
}
As there's no description why that function is used the way it is...I wonder why it's not just something simple like:
const char *Atom_int(long n)
{
char str[43];
char *s = str;
sprintf(str, "%ld", n);
return Atom_new(s, str + sizeof str - s);
}
Is there any difference? Anything I missed about my "simple" approach using sprintf that could cause a different result than the function from the book? I mean, if it's just to show how one could convert a long to a string not using ltoa/sprintf/..., nice. But it's unnecessary complex if that's the only reason,...
There were two major problems with the original code you posted for both functions:
The str array is not '\0' terminated, invoking undefined behavior when passed to printf.
Returning a pointer s to an array with automatic storage str is also incorrect. Dereferencing this return value will invoke undefined behavior as well.
Regarding your questions, the purpose of the first function is to show the implementation of an integer to string converter. Using sprintf defeats this purpose. Note how the author handles the subtile case of INT_MIN: computing -n would invoke undefined behavior because of the integer overflow on most systems, eventhough the result would be correct on all modern systems. But complete conformance to the Standard os a difficult art: his solution assumes 2s complement and will fail otherwise.
Here is an improved solution with the same prototype. It is more portable, does not need to special case LONG_MIN, makes fewer divisions and modulo operations.
const char *Atom_int(long n) {
char str[43];
char *s = str + sizeof str;
unsigned long m;
if (n < 0)
m = (unsigned long)-(n + 1) + 1;
else
m = n;
while (m >= 10) {
*--s = m % 10 + '0';
m /= 10;
}
*--s = m + '0';
if (n < 0)
*--s = '-';
return Atom_new(s, str + sizeof str - s);
}
Also note that your proposed alternative is incorrect: you pass the wrong length to Atom_new(). You should pass the number of bytes returned by sprintf or snprintf. Here is an improved version:
const char *Atom_int(long n) {
char str[43];
return Atom_new(str, snprintf(str, sizeof str, "%ld", n));
}
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'.
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;
}
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