Multiply two arbitrary numbers in a string - c

I have made the following code to perform multiplication between 2 arbitrary number stored in char * in C :
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
void mult(char *n1, char *n2)
{
char *res;
int mul, i, j;
res = malloc(sizeof(*res) * (strlen(n1) + strlen(n2) + 1));
memset(res, '0', strlen(n1) + strlen(n2));
res[strlen(n1) + strlen(n2)] = 0;
for (i = strlen(n1) - 1; i >= 0; i--)
{
for (j = strlen(n2) - 1; j >= 0; j--)
{
mul = (n1[i] - '0') * (n2[j] - '0');
res[i + j] += ((res[i + j + 1] + mul - '0') / 10);
res[i + j + 1] = ((res[i + j + 1] + mul - '0') % 10) + '0';
}
}
printf("%s\n", res);
free(res);
}
I compiled it with -O3 flag but it takes about 30 seconds for big numbers with 86 k digits.
How I can make it faster?

Summing up comments:
Try to avoid integer division. E.g. with lookup table. Product of two digits mean a maximum of 9^2. Use result of /10 or %10 for the other.
Make sure the strlen() calls are stored, explicitly dedicate variables for them.
Perform the +/-'0' trafo separately.
Consider the base 10000 suggestion.
Perhaps using dedicated struct (dyn array + maintained size info) would be better than string. Length and the +/-'0' are performed only when I/O of numbers is neccessary.

The following would then be a somewhat optimized version, using many of the comments' suggestions:
void mult(char *n1, char *n2)
{
char *res, *pres, *p1, *p2;
int mul, i, j, l1= strlen(n1), l2= strlen(n2);
res = malloc(sizeof(*res) * (l1 + l2 + 1));
memset(res, 0, l1 + l2);
res[l1 + l2] = 0;
for (i=0, p1=n1; i<l1; i++) *p1++ -= '0';
for (j=0, p2=n2; j<l2; j++) *p2++ -= '0';
p1= n1+l1-1;
for (i= l1 - 1; i >= 0; i--, p1--)
{
p2= n2+l2-1;
pres= res+i;
for (j = l2 - 1; j >= 0; j--, p2--)
{
mul = *p1 * *p2;
pres[j] += ((pres[j + 1] + mul) / 10);
pres[j + 1] = ((pres[j + 1] + mul) % 10);
}
}
for (i=0, p1=res; i<l1+l2; i++) *p1++ += '0';
printf("%s\n", res);
free(res);
}

Avoid calling strlen() repeatedly. #Michael Walz as for (j = strlen(n2) ... inside the for (i ... loop.
Rather than subtract/add '0' repeated, do it once at the beginning and end. This is worthwhile for very long strings, less so for short ones. #Michael Walz #Eugene Sh.
Rather than touch 2 product elements in the inner loop (once to add to product, once for the carry), do so once and form a carry.
Take advantage of leading zeros.
Some untested code. Be sure to free the free the returned pointer. Coded for clarity vs. code-golfing.
#include <stdlib.h>
#include <string.h>
static void string_offset(char *s, size_t sz, int offset) {
while (sz > 0) {
sz--;
s[sz] += offset;
}
}
char * string_string_mult(char *a, char *b) {
while (*a == '0') a++;
size_t alen = strlen(a);
size_t asz = alen + 1;
string_offset(a, alen, -'0');
while (*b == '0') b++;
size_t blen = strlen(b);
size_t bsz = blen + 1;
if (a != b) { // TBD to fully detect a,b, overlap
string_offset(b, blen, -'0');
}
size_t psz = asz + bsz;
char *product = calloc(psz, sizeof *product); // account for potential carry and \0
if (product == NULL) return NULL;
for (size_t ai = alen; ai > 0;) {
ai--;
char *p = product + ai + blen + 1;
int acc = 0;
for (size_t bi = blen; bi > 0;) {
bi--;
acc = *p + a[ai] * b[bi] + acc;
*p = acc %= 10;
p--;
acc /= 10;
}
*p += acc;
}
string_offset(product, psz - 1, +'0');
// test for an unneeded leading zero
if (product[0] == '0' && (alen + blen > 0)) {
memmove(product, product + 1, psz - 1);
}
string_offset(a, alen, +'0');
if (a != b) { // TBD to fully detect a,b, overlap
string_offset(b, blen, +'0');
}
return product;
}
Details
a and b may point to the same string.
Memory allocation may fail.
size_t is the best type to use for array indexing.
The product may/may not form a final carry.

I checked most of the suggested optimizations (except LutzL's base 10000 scheme which has promise) and they don't make a significant difference. Since you've already identified bc as having the right stuff, why not simply use it instead of trying to reimplement it:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define BUFFER_SIZE 1024
void mult(const char *n1, const char *n2) {
FILE *pipe = popen("/usr/bin/bc", "r+");
fprintf(pipe, "%s * %s\nquit\n", n1, n2);
if (ferror(pipe)) {
fprintf(stderr, "Output to pipe failed.\n");
exit(EXIT_FAILURE);
}
char *buffer = malloc(BUFFER_SIZE); // bc long lines are limited to 70 characters
char *result = fgets(buffer, BUFFER_SIZE, pipe);
while (result != NULL) {
char *s = rindex(buffer, '\\'); // find and remove line continuation marker
if (s != NULL) {
*s = '\0';
}
fputs(buffer, stdout);
result = fgets(buffer, BUFFER_SIZE, pipe);
}
(void) pclose(pipe);
}
On my system this multiplied two 86K digit numbers in under a second.
Note that my system (OSX) has bidirectional popen() which is unidirectional on many system so you'll need to use the recommended work around for your system for bidirectional communication.
The above code could use more error checking and you could play with the bc environment variable BC_LINE_LENGTH to generate longer lines for efficiency, and on some systems set it to zero to avoid line breaks.

Related

Segfault 11 on long string, PRIOR to accessing string, only when string > 14

ANSI c on OSX 10.13.6
Apple LLVM version 9.1.0 (clang-902.0.39.2)
Target: x86_64-apple-darwin17.7.0
Thread model: posix
I'm learning c
This is a function that manually (character-by-character) adds two character strings representing large numbers (that exceed the unsigned long long or double size).
It functions fine with any two strings 14 or less characters long, but segmentation fault 11 with any strings greater than 14 chars.
Changing the string's memory allocation method seems to have no effect (I.e. from char[15] addend1; // not a ptr to char *addend1 = (char *) malloc(sizeof(char) * (16) ); // pointer
One things that's curious, is that it seems to segfault on the ...
for (int j = maxlength - 1 ; j >= 0; j--)
... prior to accessing either of addend1 or addend2, but I'm not able to find an error there or change it to prevent the segfault.
Am I misreading where the error arises, or could it be related to the for loop?
Successful run (less than 15 chars)
maxlength = 14
char *sum = (char *) malloc(sizeof(char) * (maxlength + 1) ) ... DONE
for (int i = 0; i < (maxlength); i++) { sum[i] = '0'; } ... DONE
Start adding individual ints from end (right side) ...
13 ...12 ...11 ...10 ...9 ...8 ...7 ...6 ...5 ...4 ...3 ...2 ...1 ...0 ...main.sum = 28147497671064
UNSuccessful run (15 chars)
maxlength = 15
char *sum = (char *) malloc(sizeof(char) * (maxlength + 1) ) ... DONE
for (int i = 0; i < (maxlength); i++) { sum[i] = '0'; } ... DONE
Start adding individual ints from end (right side) ...
Segmentation fault: 11
MAIN.c
#include <stdio.h>
#include <stdlib.h>
#include "../../c-library/include/addViaStrings.h"
int main(void) {
// s[0] = 72; s[1] = 101; s[2] = 108; s[3] = 108; s[4] = 111; s[5] = 32; s[6] = 87; s[7] = 111; s[8] = 114; s[9] = 108; s[10] = 100; s[11] = 0;
// WORKS
// char s1[] = "14073748835532";
// char s2[] = "14073748835532";
// FAILS
char s1[] = "140737488355328";
char s2[] = "140737488355328";
char *sum = addNumericStrings(&s1, &s2);
printf("main.sum = %s\n", sum);
}
addViaStrings.h
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
char* addNumericStrings(char *s1, char *s2);
char leftPad(char *result, char *s, int maxlength);
int findMaxLength(char *s1, char *s2);
char* addNumericStrings(char *s1, char *s2){
// Find the length of the greater of the two
int maxlength = findMaxLength(s1, s2);
printf("maxlength = %d\n", maxlength); //333
///////////////////////////////////////////////
// Using malloc instead of char[maxlength] seems to have NO EFFECT on the issue
// char addend1[maxlength]; // not a pointer
char *addend1 = (char *) malloc(sizeof(char) * (maxlength + 1) );
addend1[maxlength + 1] = 0; // end flag
// char addend2[maxlength]; // not a pointer
char *addend2 = (char *) malloc(sizeof(char) * (maxlength + 1) );
addend2[maxlength + 1] = 0; // end flag
// Allocate sum pointer
printf("char *sum = (char *) malloc(sizeof(char) * (maxlength + 1) ) ... "); //333
char *sum = (char *) malloc(sizeof(char) * (maxlength + 1) );
printf("DONE\n"); //333
// General use vars
int a1, a2, total;
int carry = 0;
// Prepare the strings for manual addition. Pad the left with char 0s
leftPad(addend1, s1, maxlength);
leftPad(addend2, s2, maxlength);
// Buffer sum with zeros
sum[maxlength + 1] = 0; // end flag
printf("for (int i = 0; i < (maxlength); i++) { sum[i] = '0'; } ... "); //333
for (int i = 0; i < (maxlength); i++) { sum[i] = '0'; } // Fill w/ 0s
printf("DONE\n"); //333
// Run the manual addition
// Start adding individual ints from end (right side)
printf("Start adding individual ints from end (right side) ...\n"); //333
// maxlength -1 because(I think) the termination char takes 2 bytes
// If I use (maxlength) instead of (maxlength -1) I get a weird
// question mark char at the end of returnsum
for (int j = maxlength - 1 ; j >= 0; j--) {
///////////////////////////////////////////
// The segfault seems to happen BEFORE accessing addend1 or addend2
printf("%d ...", j); // 333 This DOES NOT print
///////////////////////////////////////////
a1 = addend1[j] - '0'; // Convert to int
a2 = addend2[j] - '0'; // Convert to int
total = (a1 + a2 + carry);
carry = 0;
if ( total >= 10){
carry += 1;
total -= 10;
}
sum[j + 1] = '0'+total; // convert to ascii value for numbers (adding 48)
}
sum[0] = '0' + carry; // add last carry to start of num always, even if 0
// Before returning, truncate leading zeros
char *returnsum = (char *) malloc(sizeof(char) * (strlen(sum) + 1) );
int sum_i = 0;
int returnsm_i = 0;
// bool truncate = true; // Find out why this wont compile
int truncate = 1; // true
while (1){
// if order is important here
if (sum[sum_i] == '\0') { break; } // we're done
if (sum[sum_i] == '0' && truncate == 1) { sum_i += 1; continue; } // 1 is true
// if a num, Stop truncating 0s but DO continue adding numbers
if (sum[sum_i] != '0') { truncate = 0; } // 0 is false
returnsum[returnsm_i] = sum[sum_i];
returnsm_i += 1;
sum_i += 1;
}
return returnsum;
}
char leftPad(char *result, char *s, int maxlength){
int slength = strlen(s);
// buffer with zeros, not '\0's
for (int i = (maxlength); i >= 0; i--){ result[i] = '0'; }
// right fill result with s
for (int j = 0; j <= slength; j++){
int index = ((maxlength - slength) + j);
result[index] = s[j];
}
result[maxlength + 1] = 0;
}
int findMaxLength(char *s1, char *s2){
// int length1 = findEndLength(s1);
// int length2 = findEndLength(s2);
int length1 = strlen(s1);
int length2 = strlen(s2);
int maxlength;
(length1 > length2) ? (maxlength = length1) : (maxlength = length2);
return maxlength;
}
The issue was I was trying to access the sum string as if it was one position longer than the addends strings, but I had declared it as the same length (I.e. maxlength + 1). So I was attempting to access one position past the actual sum array.
This was a somewhat hidden problem, because it was not until the length of sum needed to be greater than 15, that this access error stepped into disallowed memory space, resulting in a segfault.
Details
Because the sum of two addends could conceivably require at least one additional position in the array if the sums carried over a one (I.e. 999 + 999 = 1998), the sum string needs to be one array position longer than the addends.
If the addends were 3 digits long (length of array = 4) then the sum needed to be 4 digits long (array length = 5).
// Correct code if "maxlength" (number of actual digits in string) = 14
char *addend1 = (char *) malloc(sizeof(char) * (maxlength + 1) ); // +1 To include termination byte
char *addend2 = (char *) malloc(sizeof(char) * (maxlength + 1) ); // +1 To include termination byte
char *sum = (char *) malloc(sizeof(char) * (maxlength + 2) ); // +2 To include termination byte, AND an extra char at the front
...so that the final actual digit character of sum is accessed via maxlength + 1
CORRECTED CODE
NOTE: Because calculating against maxlength as the number of digits (versus the length of the entire array including terminator) was confusing - as well as considered bad form, I have since learned - the following final code has been simplified to use more intuitive variables.
#include <stdio.h>
#include <stdlib.h>
char* addIntsAsStrings(char *s1, char *s2);
char* addIntsAsStrings(char *s1, char *s2){
// Find the length of the greater of the two
int length1 = strlen(s1);
int length2 = strlen(s2);
int addendDigits;
(length1 > length2) ? (addendDigits = length1) : (addendDigits = length2);
// We need separate strings of so they can be buffered with zeros
// Create the string for the addends and buffer with zeros.
char addend1[addendDigits + 1];
char addend2[addendDigits + 1];
for (int i = 0; i < (addendDigits) ; i++){ // "<" not "<="
addend1[i] = '0'; // buffer w/ 0s
addend2[i] = '0'; // buffer w/ 0s
} // buffer w/ 0s
addend1[addendDigits] = '\0'; // terminate
// put s1 and s2 into buffered addends strings
int s1_index = (strlen(s1) - 1);
int s2_index = (strlen(s2) - 1);
for (int i = (addendDigits - 1); i >= 0; i--){ //Start at back of addend
if ( s1_index >= 0) { addend1[i] = s1[s1_index]; }
if ( s2_index >= 0) { addend2[i] = s2[s2_index]; }
s1_index -= 1;
s2_index -= 1;
}
// Allocate sum pointer. The sum pointer needs to be ONE char
// longer than the addends, in the event that the addends need
// to carry a final one to the front. I.e. 999 + 999 = 1998
int sumDigits = addendDigits + 1;
char *sum = (char *) malloc(sizeof(char) * (sumDigits + 1) ); // +1 To include termination byte, AND an extra char at the front
for (int i = 0; i < (sumDigits) ; i++){ // "<" not "<="
sum[i] = '0'; // buffer w/ 0s
}
sum[sumDigits] = '\0';
// Manual addition vars
int a1, a2, total;
int carry = 0;
// Run the manual addition
// Start adding individual ints from end (right side)
for (int j = addendDigits - 1; j >= 0; j--) {
a1 = addend1[j] - '0'; // Convert to int
a2 = addend2[j] - '0'; // Convert to int
total = (a1 + a2 + carry);
carry = 0;
if ( total >= 10){
carry += 1;
total -= 10;
}
// convert to ascii value for numbers (adding 48)
sum[j + 1] = '0'+total; // sum[j + 1] because `sum`is always one index larger than the addends
}
sum[0] = '0' + carry; // add last carry to start of num always, even if 0
// Before returning, truncate leading zeros
char *returnsum = (char *) malloc(sizeof(char) * (strlen(sum) + 1) );
int sum_i = 0;
int returnsm_i = 0;
int truncate = 1; // true
while (1){
// if order is important here
if (sum[sum_i] == '\0') { break; } // we're done
if (sum[sum_i] == '0' && truncate == 1) { sum_i += 1; continue; } // 1 is true
// if a num, Stop truncating 0s but DO continue adding numbers
if (sum[sum_i] != '0') { truncate = 0; } // 0 is false
returnsum[returnsm_i] = sum[sum_i];
returnsm_i += 1;
sum_i += 1;
}
return returnsum;
}

How to format number adding points between each 3 numbers [duplicate]

In C, how can I format a large number from e.g. 1123456789 to 1,123,456,789?
I tried using printf("%'10d\n", 1123456789), but that doesn't work.
Could you advise anything? The simpler the solution the better.
If your printf supports the ' flag (as required by POSIX 2008 printf()), you can probably do it just by setting your locale appropriately. Example:
#include <stdio.h>
#include <locale.h>
int main(void)
{
setlocale(LC_NUMERIC, "");
printf("%'d\n", 1123456789);
return 0;
}
And build & run:
$ ./example
1,123,456,789
Tested on Mac OS X & Linux (Ubuntu 10.10).
You can do it recursively as follows (beware INT_MIN if you're using two's complement, you'll need extra code to manage that):
void printfcomma2 (int n) {
if (n < 1000) {
printf ("%d", n);
return;
}
printfcomma2 (n/1000);
printf (",%03d", n%1000);
}
void printfcomma (int n) {
if (n < 0) {
printf ("-");
n = -n;
}
printfcomma2 (n);
}
A summmary:
User calls printfcomma with an integer, the special case of negative numbers is handled by simply printing "-" and making the number positive (this is the bit that won't work with INT_MIN).
When you enter printfcomma2, a number less than 1,000 will just print and return.
Otherwise the recursion will be called on the next level up (so 1,234,567 will be called with 1,234, then 1) until a number less than 1,000 is found.
Then that number will be printed and we'll walk back up the recursion tree, printing a comma and the next number as we go.
There is also the more succinct version though it does unnecessary processing in checking for negative numbers at every level (not that this will matter given the limited number of recursion levels). This one is a complete program for testing:
#include <stdio.h>
void printfcomma (int n) {
if (n < 0) {
printf ("-");
printfcomma (-n);
return;
}
if (n < 1000) {
printf ("%d", n);
return;
}
printfcomma (n/1000);
printf (",%03d", n%1000);
}
int main (void) {
int x[] = {-1234567890, -123456, -12345, -1000, -999, -1,
0, 1, 999, 1000, 12345, 123456, 1234567890};
int *px = x;
while (px != &(x[sizeof(x)/sizeof(*x)])) {
printf ("%-15d: ", *px);
printfcomma (*px);
printf ("\n");
px++;
}
return 0;
}
and the output is:
-1234567890 : -1,234,567,890
-123456 : -123,456
-12345 : -12,345
-1000 : -1,000
-999 : -999
-1 : -1
0 : 0
1 : 1
999 : 999
1000 : 1,000
12345 : 12,345
123456 : 123,456
1234567890 : 1,234,567,890
An iterative solution for those who don't trust recursion (although the only problem with recursion tends to be stack space which will not be an issue here since it'll only be a few levels deep even for a 64-bit integer):
void printfcomma (int n) {
int n2 = 0;
int scale = 1;
if (n < 0) {
printf ("-");
n = -n;
}
while (n >= 1000) {
n2 = n2 + scale * (n % 1000);
n /= 1000;
scale *= 1000;
}
printf ("%d", n);
while (scale != 1) {
scale /= 1000;
n = n2 / scale;
n2 = n2 % scale;
printf (",%03d", n);
}
}
Both of these generate 2,147,483,647 for INT_MAX.
All the code above is for comma-separating three-digit groups but you can use other characters as well, such as a space:
void printfspace2 (int n) {
if (n < 1000) {
printf ("%d", n);
return;
}
printfspace2 (n/1000);
printf (" %03d", n%1000);
}
void printfspace (int n) {
if (n < 0) {
printf ("-");
n = -n;
}
printfspace2 (n);
}
Here's a very simple implementation. This function contains no error checking, buffer sizes must be verified by the caller. It also does not work for negative numbers. Such improvements are left as an exercise for the reader.
void format_commas(int n, char *out)
{
int c;
char buf[20];
char *p;
sprintf(buf, "%d", n);
c = 2 - strlen(buf) % 3;
for (p = buf; *p != 0; p++) {
*out++ = *p;
if (c == 1) {
*out++ = ',';
}
c = (c + 1) % 3;
}
*--out = 0;
}
Egads! I do this all the time, using gcc/g++ and glibc on linux and yes, the ' operator may be non-standard, but I like the simplicity of it.
#include <stdio.h>
#include <locale.h>
int main()
{
int bignum=12345678;
setlocale(LC_ALL,"");
printf("Big number: %'d\n",bignum);
return 0;
}
Gives output of:
Big number: 12,345,678
Just have to remember the 'setlocale' call in there, otherwise it won't format anything.
Perhaps a locale-aware version would be interesting.
#include <stdlib.h>
#include <locale.h>
#include <string.h>
#include <limits.h>
static int next_group(char const **grouping) {
if ((*grouping)[1] == CHAR_MAX)
return 0;
if ((*grouping)[1] != '\0')
++*grouping;
return **grouping;
}
size_t commafmt(char *buf, /* Buffer for formatted string */
int bufsize, /* Size of buffer */
long N) /* Number to convert */
{
int i;
int len = 1;
int posn = 1;
int sign = 1;
char *ptr = buf + bufsize - 1;
struct lconv *fmt_info = localeconv();
char const *tsep = fmt_info->thousands_sep;
char const *group = fmt_info->grouping;
char const *neg = fmt_info->negative_sign;
size_t sep_len = strlen(tsep);
size_t group_len = strlen(group);
size_t neg_len = strlen(neg);
int places = (int)*group;
if (bufsize < 2)
{
ABORT:
*buf = '\0';
return 0;
}
*ptr-- = '\0';
--bufsize;
if (N < 0L)
{
sign = -1;
N = -N;
}
for ( ; len <= bufsize; ++len, ++posn)
{
*ptr-- = (char)((N % 10L) + '0');
if (0L == (N /= 10L))
break;
if (places && (0 == (posn % places)))
{
places = next_group(&group);
for (int i=sep_len; i>0; i--) {
*ptr-- = tsep[i-1];
if (++len >= bufsize)
goto ABORT;
}
}
if (len >= bufsize)
goto ABORT;
}
if (sign < 0)
{
if (len >= bufsize)
goto ABORT;
for (int i=neg_len; i>0; i--) {
*ptr-- = neg[i-1];
if (++len >= bufsize)
goto ABORT;
}
}
memmove(buf, ++ptr, len + 1);
return (size_t)len;
}
#ifdef TEST
#include <stdio.h>
#define elements(x) (sizeof(x)/sizeof(x[0]))
void show(long i) {
char buffer[32];
commafmt(buffer, sizeof(buffer), i);
printf("%s\n", buffer);
commafmt(buffer, sizeof(buffer), -i);
printf("%s\n", buffer);
}
int main() {
long inputs[] = {1, 12, 123, 1234, 12345, 123456, 1234567, 12345678 };
for (int i=0; i<elements(inputs); i++) {
setlocale(LC_ALL, "");
show(inputs[i]);
}
return 0;
}
#endif
This does have a bug (but one I'd consider fairly minor). On two's complement hardware, it won't convert the most-negative number correctly, because it attempts to convert a negative number to its equivalent positive number with N = -N; In two's complement, the maximally negative number doesn't have a corresponding positive number, unless you promote it to a larger type. One way to get around this is by promoting the number the corresponding unsigned type (but it's is somewhat non-trivial).
Without recursion or string handling, a mathematical approach:
#include <stdio.h>
#include <math.h>
void print_number( int n )
{
int order_of_magnitude = (n == 0) ? 1 : (int)pow( 10, ((int)floor(log10(abs(n))) / 3) * 3 ) ;
printf( "%d", n / order_of_magnitude ) ;
for( n = abs( n ) % order_of_magnitude, order_of_magnitude /= 1000;
order_of_magnitude > 0;
n %= order_of_magnitude, order_of_magnitude /= 1000 )
{
printf( ",%03d", abs(n / order_of_magnitude) ) ;
}
}
Similar in principle to Pax's recursive solution, but by calculating the order of magnitude in advance, recursion is avoided (at some considerable expense perhaps).
Note also that the actual character used to separate thousands is locale specific.
Edit:See #Chux's comments below for improvements.
Based on #Greg Hewgill's, but takes negative numbers into account and returns the string size.
size_t str_format_int_grouped(char dst[16], int num)
{
char src[16];
char *p_src = src;
char *p_dst = dst;
const char separator = ',';
int num_len, commas;
num_len = sprintf(src, "%d", num);
if (*p_src == '-') {
*p_dst++ = *p_src++;
num_len--;
}
for (commas = 2 - num_len % 3;
*p_src;
commas = (commas + 1) % 3)
{
*p_dst++ = *p_src++;
if (commas == 1) {
*p_dst++ = separator;
}
}
*--p_dst = '\0';
return (size_t)(p_dst - dst);
}
Needed to do something similar myself but rather than printing directly, needed to go to a buffer. Here's what I came up with. Works backwards.
unsigned int IntegerToCommaString(char *String, unsigned long long Integer)
{
unsigned int Digits = 0, Offset, Loop;
unsigned long long Copy = Integer;
do {
Digits++;
Copy /= 10;
} while (Copy);
Digits = Offset = ((Digits - 1) / 3) + Digits;
String[Offset--] = '\0';
Copy = Integer;
Loop = 0;
do {
String[Offset] = '0' + (Copy % 10);
if (!Offset--)
break;
if (Loop++ % 3 == 2)
String[Offset--] = ',';
Copy /= 10;
} while (1);
return Digits;
}
Be aware that it's only designed for unsigned integers and you must ensure that the buffer is large enough.
There's no real simple way to do this in C. I would just modify an int-to-string function to do it:
void format_number(int n, char * out) {
int i;
int digit;
int out_index = 0;
for (i = n; i != 0; i /= 10) {
digit = i % 10;
if ((out_index + 1) % 4 == 0) {
out[out_index++] = ',';
}
out[out_index++] = digit + '0';
}
out[out_index] = '\0';
// then you reverse the out string as it was converted backwards (it's easier that way).
// I'll let you figure that one out.
strrev(out);
}
My answer does not format the result exactly like the illustration in the question, but may fulfill the actual need in some cases with a simple one-liner or macro. One can extend it to generate more thousand-groups as necessary.
The result will look for example as follows:
Value: 0'000'012'345
The code:
printf("Value: %llu'%03lu'%03lu'%03lu\n", (value / 1000 / 1000 / 1000), (value / 1000 / 1000) % 1000, (value / 1000) % 1000, value % 1000);
#include <stdio.h>
void punt(long long n){
char s[28];
int i = 27;
if(n<0){n=-n; putchar('-');}
do{
s[i--] = n%10 + '0';
if(!(i%4) && n>9)s[i--]='.';
n /= 10;
}while(n);
puts(&s[++i]);
}
int main(){
punt(2134567890);
punt(987);
punt(9876);
punt(-987);
punt(-9876);
punt(-654321);
punt(0);
punt(1000000000);
punt(0x7FFFFFFFFFFFFFFF);
punt(0x8000000000000001); // -max + 1 ...
}
My solution uses a . instead of a ,
It is left to the reader to change this.
This is old and there are plenty of answers but the question was not "how can I write a routine to add commas" but "how can it be done in C"? The comments pointed to this direction but on my Linux system with GCC, this works for me:
#include <stdio.h>
#include <stdlib.h>
#include <locale.h>
int main()
{
unsetenv("LC_ALL");
setlocale(LC_NUMERIC, "");
printf("%'lld\n", 3141592653589);
}
When this is run, I get:
$ cc -g comma.c -o comma && ./comma
3,141,592,653,589
If I unset the LC_ALL variable before running the program the unsetenv is not necessary.
Another solution, by saving the result into an int array, maximum size of 7 because the long long int type can handle numbers in the range 9,223,372,036,854,775,807 to -9,223,372,036,854,775,807. (Note it is not an unsigned value).
Non-recursive printing function
static void printNumber (int numbers[8], int loc, int negative)
{
if (negative)
{
printf("-");
}
if (numbers[1]==-1)//one number
{
printf("%d ", numbers[0]);
}
else
{
printf("%d,", numbers[loc]);
while(loc--)
{
if(loc==0)
{// last number
printf("%03d ", numbers[loc]);
break;
}
else
{ // number in between
printf("%03d,", numbers[loc]);
}
}
}
}
main function call
static void getNumWcommas (long long int n, int numbers[8])
{
int i;
int negative=0;
if (n < 0)
{
negative = 1;
n = -n;
}
for(i = 0; i < 7; i++)
{
if (n < 1000)
{
numbers[i] = n;
numbers[i+1] = -1;
break;
}
numbers[i] = n%1000;
n/=1000;
}
printNumber(numbers, i, negative);// non recursive print
}
testing output
-9223372036854775807: -9,223,372,036,854,775,807
-1234567890 : -1,234,567,890
-123456 : -123,456
-12345 : -12,345
-1000 : -1,000
-999 : -999
-1 : -1
0 : 0
1 : 1
999 : 999
1000 : 1,000
12345 : 12,345
123456 : 123,456
1234567890 : 1,234,567,890
9223372036854775807 : 9,223,372,036,854,775,807
In main() function:
int numberSeparated[8];
long long int number = 1234567890LL;
getNumWcommas(number, numberSeparated);
If printing is all that's needed then move int numberSeparated[8]; inside the function getNumWcommas and call it this way getNumWcommas(number).
Another iterative function
int p(int n) {
if(n < 0) {
printf("-");
n = -n;
}
int a[sizeof(int) * CHAR_BIT / 3] = { 0 };
int *pa = a;
while(n > 0) {
*++pa = n % 1000;
n /= 1000;
}
printf("%d", *pa);
while(pa > a + 1) {
printf(",%03d", *--pa);
}
}
Here is the slimiest, size and speed efficient implementation of this kind of decimal digit formating:
const char *formatNumber (
int value,
char *endOfbuffer,
bool plus)
{
int savedValue;
int charCount;
savedValue = value;
if (unlikely (value < 0))
value = - value;
*--endOfbuffer = 0;
charCount = -1;
do
{
if (unlikely (++charCount == 3))
{
charCount = 0;
*--endOfbuffer = ',';
}
*--endOfbuffer = (char) (value % 10 + '0');
}
while ((value /= 10) != 0);
if (unlikely (savedValue < 0))
*--endOfbuffer = '-';
else if (unlikely (plus))
*--endOfbuffer = '+';
return endOfbuffer;
}
Use as following:
char buffer[16];
fprintf (stderr, "test : %s.", formatNumber (1234567890, buffer + 16, true));
Output:
test : +1,234,567,890.
Some advantages:
Function taking end of string buffer because of reverse ordered formatting. Finally, where is no need in revering generated string (strrev).
This function produces one string that can be used in any algo after. It not depends nor require multiple printf/sprintf calls, which is terrible slow and always context specific.
Minimum number of divide operators (/, %).
Secure format_commas, with negative numbers:
Because VS < 2015 doesn't implement snprintf, you need to do this
#if defined(_WIN32)
#define snprintf(buf,len, format,...) _snprintf_s(buf, len,len, format, __VA_ARGS__)
#endif
And then
char* format_commas(int n, char *out)
{
int c;
char buf[100];
char *p;
char* q = out; // Backup pointer for return...
if (n < 0)
{
*out++ = '-';
n = abs(n);
}
snprintf(buf, 100, "%d", n);
c = 2 - strlen(buf) % 3;
for (p = buf; *p != 0; p++) {
*out++ = *p;
if (c == 1) {
*out++ = '\'';
}
c = (c + 1) % 3;
}
*--out = 0;
return q;
}
Example usage:
size_t currentSize = getCurrentRSS();
size_t peakSize = getPeakRSS();
printf("Current size: %d\n", currentSize);
printf("Peak size: %d\n\n\n", peakSize);
char* szcurrentSize = (char*)malloc(100 * sizeof(char));
char* szpeakSize = (char*)malloc(100 * sizeof(char));
printf("Current size (f): %s\n", format_commas((int)currentSize, szcurrentSize));
printf("Peak size (f): %s\n", format_commas((int)currentSize, szpeakSize));
free(szcurrentSize);
free(szpeakSize);
A modified version of #paxdiablo solution, but using WCHAR and wsprinf:
static WCHAR buffer[10];
static int pos = 0;
void printfcomma(const int &n) {
if (n < 0) {
wsprintf(buffer + pos, TEXT("-"));
pos = lstrlen(buffer);
printfcomma(-n);
return;
}
if (n < 1000) {
wsprintf(buffer + pos, TEXT("%d"), n);
pos = lstrlen(buffer);
return;
}
printfcomma(n / 1000);
wsprintf(buffer + pos, TEXT(",%03d"), n % 1000);
pos = lstrlen(buffer);
}
void my_sprintf(const int &n)
{
pos = 0;
printfcomma(n);
}
I'm new in C programming. Here is my simple code.
int main()
{
// 1223 => 1,223
int n;
int a[10];
printf(" n: ");
scanf_s("%d", &n);
int i = 0;
while (n > 0)
{
int temp = n % 1000;
a[i] = temp;
n /= 1000;
i++;
}
for (int j = i - 1; j >= 0; j--)
{
if (j == 0)
{
printf("%d.", a[j]);
}
else printf("%d,",a[j]);
}
getch();
return 0;
}
Require: <stdio.h> + <string.h>.
Advantage: short, readable, based on the format of scanf-family. And assume no comma on the right of decimal point.
void add_commas(char *in, char *out) {
int len_in = strlen(in);
int len_int = -1; /* len_int(123.4) = 3 */
for (int i = 0; i < len_in; ++i) if (in[i] == '.') len_int = i;
int pos = 0;
for (int i = 0; i < len_in; ++i) {
if (i>0 && i<len_int && (len_int-i)%3==0)
out[pos++] = ',';
out[pos++] = in[i];
}
out[pos] = 0; /* Append the '\0' */
}
Example, to print a formatted double:
#include <stdio.h>
#include <string.h>
#define COUNT_DIGIT_MAX 100
int main() {
double sum = 30678.7414;
char input[COUNT_DIGIT_MAX+1] = { 0 }, output[COUNT_DIGIT_MAX+1] = { 0 };
snprintf(input, COUNT_DIGIT_MAX, "%.2f", sum/12);
add_commas(input, output);
printf("%s\n", output);
}
Output:
2,556.56
Using C++'s std::string as return value with possibly the least overhead and not using any std library functions (sprintf, to_string, etc.).
string group_digs_c(int num)
{
const unsigned int BUF_SIZE = 128;
char buf[BUF_SIZE] = { 0 }, * pbuf = &buf[BUF_SIZE - 1];
int k = 0, neg = 0;
if (num < 0) { neg = 1; num = num * -1; };
while(num)
{
if (k > 0 && k % 3 == 0)
*pbuf-- = ',';
*pbuf-- = (num % 10) + '0';
num /= 10;
++k;
}
if (neg)
*pbuf = '-';
else
++pbuf;
int cc = buf + BUF_SIZE - pbuf;
memmove(buf, pbuf, cc);
buf[cc] = 0;
string rv = buf;
return rv;
}
Here is a simple portable solution relying on sprintf:
#include <stdio.h>
// assuming out points to an array of sufficient size
char *format_commas(char *out, int n, int min_digits) {
int len = sprintf(out, "%.*d", min_digits, n);
int i = (*out == '-'), j = len, k = (j - i - 1) / 3;
out[j + k] = '\0';
while (k-- > 0) {
j -= 3;
out[j + k + 3] = out[j + 2];
out[j + k + 2] = out[j + 1];
out[j + k + 1] = out[j + 0];
out[j + k + 0] = ',';
}
return out;
}
The code is easy to adapt for other integer types.
There are many interesting contributions here. Some covered all cases, some did not. I picked four of the contributions to test, found some failure cases during testing and then added a solution of my own.
I tested all methods for both accuracy and speed. Even though the OP only requested a solution for one positive number, I upgraded the contributions that didn't cover all possible numbers (so the code below may be slightly different from the original postings). The cases that weren't covered include: 0, negative numbers and the minimum number (INT_MIN).
I changed the declared type from "int" to "long long" since it's more general and all ints will get promoted to long long. I also standardized the call interface to include the number as well as a buffer to contain the formatted string (like some of the contributions) and returned a pointer to the buffer:
char* funcName(long long number_to_format, char* string_buffer);
Including a buffer parameter is considered by some to be "better" than having the function: 1) contain a static buffer (would not be re-entrant) or 2) allocate space for the buffer (would require caller to de-allocate the memory) or 3) print the result directly to stdout (would not be as generally useful since the output may be targeted for a GUI widget, file, pty, pipe, etc.).
I tried to use the same function names as the original contributions to make it easier to refer back to the originals. Contributed functions were modified as needed to pass the accuracy test so that the speed test would be meaningful. The results are included here in case you would like to test more of the contributed techniques for comparison. All code and test code used to generate the results are shown below.
So, here are the results:
Accuracy Test (test cases: LLONG_MIN, -999, -99, 0, 99, 999, LLONG_MAX):
----------------------------------------------------
print_number:
-9,223,372,036,854,775,808, -999, -99, 0, 99, 999, 9,223,372,036,854,775,807
fmtLocale:
-9,223,372,036,854,775,808, -999, -99, 0, 99, 999, 9,223,372,036,854,775,807
fmtCommas:
-9,223,372,036,854,775,808, -999, -99, 0, 99, 999, 9,223,372,036,854,775,807
format_number:
-9,223,372,036,854,775,808, -999, -99, 0, 99, 999, 9,223,372,036,854,775,807
itoa_commas:
-9,223,372,036,854,775,808, -999, -99, 0, 99, 999, 9,223,372,036,854,775,807
Speed Test: (1 million calls, values reflect average time per call)
----------------------------------------------------
print_number: 0.747 us (microsec) per call
fmtLocale: 0.222 us (microsec) per call
fmtCommas: 0.212 us (microsec) per call
format_number: 0.124 us (microsec) per call
itoa_commas: 0.085 us (microsec) per call
Since all contributed techniques are fast (< 1 microsecond on my laptop), unless you need to format millions of numbers, any of the techniques should be acceptable. It's probably best to choose the technique that is most readable to you.
Here is the code:
#line 2 "comma.c"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <math.h>
#include <locale.h>
#include <limits.h>
// ----------------------------------------------------------
char* print_number( long long n, char buf[32] ) {
long long order_of_magnitude = (n == 0) ? 1
: (long long)pow( 10, ((long long)floor(log10(fabs(n))) / 3) * 3 ) ;
char *ptr = buf;
sprintf(ptr, "%d", n / order_of_magnitude ) ;
for( n %= order_of_magnitude, order_of_magnitude /= 1000;
order_of_magnitude > 0;
n %= order_of_magnitude, order_of_magnitude /= 1000 )
{
ptr += strlen(ptr);
sprintf(ptr, ",%03d", abs(n / order_of_magnitude) );
}
return buf;
}
// ----------------------------------------------------------
char* fmtLocale(long long i, char buf[32]) {
sprintf(buf, "%'lld", i); // requires setLocale in main
return buf;
}
// ----------------------------------------------------------
char* fmtCommas(long long num, char dst[32]) {
char src[27];
char *p_src = src;
char *p_dst = dst;
const char separator = ',';
int num_len, commas;
num_len = sprintf(src, "%lld", num);
if (*p_src == '-') {
*p_dst++ = *p_src++;
num_len--;
}
for (commas = 2 - num_len % 3;
*p_src;
commas = (commas + 1) % 3)
{
*p_dst++ = *p_src++;
if (commas == 1) {
*p_dst++ = separator;
}
}
*--p_dst = '\0';
return dst;
}
// ----------------------------------------------------------
char* format_number(long long n, char out[32]) {
int digit;
int out_index = 0;
long long i = (n < 0) ? -n : n;
if (i == LLONG_MIN) i = LLONG_MAX; // handle MIN, offset by 1
if (i == 0) { out[out_index++] = '0'; } // handle 0
for ( ; i != 0; i /= 10) {
digit = i % 10;
if ((out_index + 1) % 4 == 0) {
out[out_index++] = ',';
}
out[out_index++] = digit + '0';
}
if (n == LLONG_MIN) { out[0]++; } // correct for offset
if (n < 0) { out[out_index++] = '-'; }
out[out_index] = '\0';
// then you reverse the out string
for (int i=0, j = strlen(out) - 1; i<=j; ++i, --j) {
char tmp = out[i];
out[i] = out[j];
out[j] = tmp;
}
return out;
}
// ----------------------------------------------------------
char* itoa_commas(long long i, char buf[32]) {
char* p = buf + 31;
*p = '\0'; // terminate string
if (i == 0) { *(--p) = '0'; return p; } // handle 0
long long n = (i < 0) ? -i : i;
if (n == LLONG_MIN) n = LLONG_MAX; // handle MIN, offset by 1
for (int j=0; 1; ++j) {
*--p = '0' + n % 10; // insert digit
if ((n /= 10) <= 0) break;
if (j % 3 == 2) *--p = ','; // insert a comma
}
if (i == LLONG_MIN) { p[24]++; } // correct for offset
if (i < 0) { *--p = '-'; }
return p;
}
// ----------------------------------------------------------
// Test Accuracy
// ----------------------------------------------------------
void test_accuracy(char* name, char* (*func)(long long n, char* buf)) {
char sbuf[32]; // string buffer
long long nbuf[] = { LLONG_MIN, -999, -99, 0, 99, 999, LLONG_MAX };
printf("%s:\n", name);
printf(" %s", func(nbuf[0], sbuf));
for (int i=1; i < sizeof(nbuf) / sizeof(long long int); ++i) {
printf(", %s", func(nbuf[i], sbuf));
}
printf("\n");
}
// ----------------------------------------------------------
// Test Speed
// ----------------------------------------------------------
void test_speed(char* name, char* (*func)(long long n, char* buf)) {
int cycleCount = 1000000;
//int cycleCount = 1;
clock_t start;
double elapsed;
char sbuf[32]; // string buffer
start = clock();
for (int i=0; i < cycleCount; ++i) {
char* s = func(LLONG_MAX, sbuf);
}
elapsed = (double)(clock() - start) / (CLOCKS_PER_SEC / 1000000.0);
printf("%14s: %7.3f us (microsec) per call\n", name, elapsed / cycleCount);
}
// ----------------------------------------------------------
int main(int argc, char* argv[]){
setlocale(LC_ALL, "");
printf("\nAccuracy Test: (LLONG_MIN, -999, 0, 99, LLONG_MAX)\n");
printf("----------------------------------------------------\n");
test_accuracy("print_number", print_number);
test_accuracy("fmtLocale", fmtLocale);
test_accuracy("fmtCommas", fmtCommas);
test_accuracy("format_number", format_number);
test_accuracy("itoa_commas", itoa_commas);
printf("\nSpeed Test: 1 million calls\n\n");
printf("----------------------------------------------------\n");
test_speed("print_number", print_number);
test_speed("fmtLocale", fmtLocale);
test_speed("fmtCommas", fmtCommas);
test_speed("format_number", format_number);
test_speed("itoa_commas", itoa_commas);
return 0;
}
Can be done pretty easily...
//Make sure output buffer is big enough and that input is a valid null terminated string
void pretty_number(const char* input, char * output)
{
int iInputLen = strlen(input);
int iOutputBufferPos = 0;
for(int i = 0; i < iInputLen; i++)
{
if((iInputLen-i) % 3 == 0 && i != 0)
{
output[iOutputBufferPos++] = ',';
}
output[iOutputBufferPos++] = input[i];
}
output[iOutputBufferPos] = '\0';
}
Example call:
char szBuffer[512];
pretty_number("1234567", szBuffer);
//strcmp(szBuffer, "1,234,567") == 0
void printfcomma ( long long unsigned int n)
{
char nstring[100];
int m;
int ptr;
int i,j;
sprintf(nstring,"%llu",n);
m=strlen(nstring);
ptr=m%3;
if (ptr)
{ for (i=0;i<ptr;i++) // print first digits before comma
printf("%c", nstring[i]);
printf(",");
}
j=0;
for (i=ptr;i<m;i++) // print the rest inserting commas
{
printf("%c",nstring[i]);
j++;
if (j%3==0)
if(i<(m-1)) printf(",");
}
}
// separate thousands
int digit;
int idx = 0;
static char buffer[32];
char* p = &buffer[32];
*--p = '\0';
for (int i = fCounter; i != 0; i /= 10)
{
digit = i % 10;
if ((p - buffer) % 4 == 0)
*--p = ' ';
*--p = digit + '0';
}

Bus error when printing to output file [duplicate]

itoa() is a really handy function to convert a number to a string. Linux does not seem to have itoa(), is there an equivalent function or do I have to use sprintf(str, "%d", num)?
EDIT: Sorry, I should have remembered that this machine is decidedly non-standard, having plugged in various non-standard libc implementations for academic purposes ;-)
As itoa() is indeed non-standard, as mentioned by several helpful commenters, it is best to use sprintf(target_string,"%d",source_int) or (better yet, because it's safe from buffer overflows) snprintf(target_string, size_of_target_string_in_bytes, "%d", source_int). I know it's not quite as concise or cool as itoa(), but at least you can Write Once, Run Everywhere (tm) ;-)
Here's the old (edited) answer
You are correct in stating that the default gcc libc does not include itoa(), like several other platforms, due to it not technically being a part of the standard. See here for a little more info. Note that you have to
#include <stdlib.h>
Of course you already know this, because you wanted to use itoa() on Linux after presumably using it on another platform, but... the code (stolen from the link above) would look like:
Example
/* itoa example */
#include <stdio.h>
#include <stdlib.h>
int main ()
{
int i;
char buffer [33];
printf ("Enter a number: ");
scanf ("%d",&i);
itoa (i,buffer,10);
printf ("decimal: %s\n",buffer);
itoa (i,buffer,16);
printf ("hexadecimal: %s\n",buffer);
itoa (i,buffer,2);
printf ("binary: %s\n",buffer);
return 0;
}
Output:
Enter a number: 1750
decimal: 1750
hexadecimal: 6d6
binary: 11011010110
itoa is not a standard C function. You can implement your own. It appeared in the first edition of Kernighan and Ritchie's The C Programming Language, on page 60. The second edition of The C Programming Language ("K&R2") contains the following implementation of itoa, on page 64. The book notes several issues with this implementation, including the fact that it does not correctly handle the most negative number
/* itoa: convert n to characters in s */
void itoa(int n, char s[])
{
int i, sign;
if ((sign = n) < 0) /* record sign */
n = -n; /* make n positive */
i = 0;
do { /* generate digits in reverse order */
s[i++] = n % 10 + '0'; /* get next digit */
} while ((n /= 10) > 0); /* delete it */
if (sign < 0)
s[i++] = '-';
s[i] = '\0';
reverse(s);
}
The function reverse used above is implemented two pages earlier:
#include <string.h>
/* reverse: reverse string s in place */
void reverse(char s[])
{
int i, j;
char c;
for (i = 0, j = strlen(s)-1; i<j; i++, j--) {
c = s[i];
s[i] = s[j];
s[j] = c;
}
}
If you are calling it a lot, the advice of "just use snprintf" can be annoying. So here's what you probably want:
const char *my_itoa_buf(char *buf, size_t len, int num)
{
static char loc_buf[sizeof(int) * CHAR_BITS]; /* not thread safe */
if (!buf)
{
buf = loc_buf;
len = sizeof(loc_buf);
}
if (snprintf(buf, len, "%d", num) == -1)
return ""; /* or whatever */
return buf;
}
const char *my_itoa(int num)
{ return my_itoa_buf(NULL, 0, num); }
Edit: I just found out about std::to_string which is identical in operation to my own function below. It was introduced in C++11 and is available in recent versions of gcc, at least as early as 4.5 if you enable the c++0x extensions.
Not only is itoa missing from gcc, it's not the handiest function to use since you need to feed it a buffer. I needed something that could be used in an expression so I came up with this:
std::string itos(int n)
{
const int max_size = std::numeric_limits<int>::digits10 + 1 /*sign*/ + 1 /*0-terminator*/;
char buffer[max_size] = {0};
sprintf(buffer, "%d", n);
return std::string(buffer);
}
Ordinarily it would be safer to use snprintf instead of sprintf but the buffer is carefully sized to be immune to overrun.
See an example: http://ideone.com/mKmZVE
As Matt J wrote, there is itoa, but it's not standard. Your code will be more portable if you use snprintf.
Following function allocates just enough memory to keep string representation of the given number and then writes the string representation into this area using standard sprintf method.
char *itoa(long n)
{
int len = n==0 ? 1 : floor(log10l(labs(n)))+1;
if (n<0) len++; // room for negative sign '-'
char *buf = calloc(sizeof(char), len+1); // +1 for null
snprintf(buf, len+1, "%ld", n);
return buf;
}
Don't forget to free up allocated memory when out of need:
char *num_str = itoa(123456789L);
// ...
free(num_str);
N.B. As snprintf copies n-1 bytes, we have to call snprintf(buf, len+1, "%ld", n) (not just snprintf(buf, len, "%ld", n))
Where is the itoa function in Linux?
There is no such function in Linux. I use this code instead.
/*
=============
itoa
Convert integer to string
PARAMS:
- value A 64-bit number to convert
- str Destination buffer; should be 66 characters long for radix2, 24 - radix8, 22 - radix10, 18 - radix16.
- radix Radix must be in range -36 .. 36. Negative values used for signed numbers.
=============
*/
char* itoa (unsigned long long value, char str[], int radix)
{
char buf [66];
char* dest = buf + sizeof(buf);
boolean sign = false;
if (value == 0) {
memcpy (str, "0", 2);
return str;
}
if (radix < 0) {
radix = -radix;
if ( (long long) value < 0) {
value = -value;
sign = true;
}
}
*--dest = '\0';
switch (radix)
{
case 16:
while (value) {
* --dest = '0' + (value & 0xF);
if (*dest > '9') *dest += 'A' - '9' - 1;
value >>= 4;
}
break;
case 10:
while (value) {
*--dest = '0' + (value % 10);
value /= 10;
}
break;
case 8:
while (value) {
*--dest = '0' + (value & 7);
value >>= 3;
}
break;
case 2:
while (value) {
*--dest = '0' + (value & 1);
value >>= 1;
}
break;
default: // The slow version, but universal
while (value) {
*--dest = '0' + (value % radix);
if (*dest > '9') *dest += 'A' - '9' - 1;
value /= radix;
}
break;
}
if (sign) *--dest = '-';
memcpy (str, dest, buf +sizeof(buf) - dest);
return str;
}
Reading the code of guys who do it for a living will get you a LONG WAY.
Check out how guys from MySQL did it. The source is VERY WELL COMMENTED and will teach you much more than hacked up solutions found all over the place.
MySQL's implementation of int2str
I provide the mentioned implementation here; the link is here for reference and should be used to read the full implementation.
char *
int2str(long int val, char *dst, int radix,
int upcase)
{
char buffer[65];
char *p;
long int new_val;
char *dig_vec= upcase ? _dig_vec_upper : _dig_vec_lower;
ulong uval= (ulong) val;
if (radix < 0)
{
if (radix < -36 || radix > -2)
return NullS;
if (val < 0)
{
*dst++ = '-';
/* Avoid integer overflow in (-val) for LLONG_MIN (BUG#31799). */
uval = (ulong)0 - uval;
}
radix = -radix;
}
else if (radix > 36 || radix < 2)
return NullS;
/*
The slightly contorted code which follows is due to the fact that
few machines directly support unsigned long / and %. Certainly
the VAX C compiler generates a subroutine call. In the interests
of efficiency (hollow laugh) I let this happen for the first digit
only; after that "val" will be in range so that signed integer
division will do. Sorry 'bout that. CHECK THE CODE PRODUCED BY
YOUR C COMPILER. The first % and / should be unsigned, the second
% and / signed, but C compilers tend to be extraordinarily
sensitive to minor details of style. This works on a VAX, that's
all I claim for it.
*/
p = &buffer[sizeof(buffer)-1];
*p = '\0';
new_val= uval / (ulong) radix;
*--p = dig_vec[(uchar) (uval- (ulong) new_val*(ulong) radix)];
val = new_val;
while (val != 0)
{
ldiv_t res;
res=ldiv(val,radix);
*--p = dig_vec[res.rem];
val= res.quot;
}
while ((*dst++ = *p++) != 0) ;
return dst-1;
}
i tried my own implementation of itoa(), it seem's work in binary, octal, decimal and hex
#define INT_LEN (10)
#define HEX_LEN (8)
#define BIN_LEN (32)
#define OCT_LEN (11)
static char * my_itoa ( int value, char * str, int base )
{
int i,n =2,tmp;
char buf[BIN_LEN+1];
switch(base)
{
case 16:
for(i = 0;i<HEX_LEN;++i)
{
if(value/base>0)
{
n++;
}
}
snprintf(str, n, "%x" ,value);
break;
case 10:
for(i = 0;i<INT_LEN;++i)
{
if(value/base>0)
{
n++;
}
}
snprintf(str, n, "%d" ,value);
break;
case 8:
for(i = 0;i<OCT_LEN;++i)
{
if(value/base>0)
{
n++;
}
}
snprintf(str, n, "%o" ,value);
break;
case 2:
for(i = 0,tmp = value;i<BIN_LEN;++i)
{
if(tmp/base>0)
{
n++;
}
tmp/=base;
}
for(i = 1 ,tmp = value; i<n;++i)
{
if(tmp%2 != 0)
{
buf[n-i-1] ='1';
}
else
{
buf[n-i-1] ='0';
}
tmp/=base;
}
buf[n-1] = '\0';
strcpy(str,buf);
break;
default:
return NULL;
}
return str;
}
direct copy to buffer : 64 bit integer itoa hex :
char* itoah(long num, char* s, int len)
{
long n, m = 16;
int i = 16+2;
int shift = 'a'- ('9'+1);
if(!s || len < 1)
return 0;
n = num < 0 ? -1 : 1;
n = n * num;
len = len > i ? i : len;
i = len < i ? len : i;
s[i-1] = 0;
i--;
if(!num)
{
if(len < 2)
return &s[i];
s[i-1]='0';
return &s[i-1];
}
while(i && n)
{
s[i-1] = n % m + '0';
if (s[i-1] > '9')
s[i-1] += shift ;
n = n/m;
i--;
}
if(num < 0)
{
if(i)
{
s[i-1] = '-';
i--;
}
}
return &s[i];
}
note: change long to long long for 32 bit machine. long to int in case for 32 bit integer. m is the radix. When decreasing radix, increase number of characters (variable i). When increasing radix, decrease number of characters (better). In case of unsigned data type, i just becomes 16 + 1.
Here is a much improved version of Archana's solution. It works for any radix 1-16, and numbers <= 0, and it shouldn't clobber memory.
static char _numberSystem[] = "0123456789ABCDEF";
static char _twosComp[] = "FEDCBA9876543210";
static void safestrrev(char *buffer, const int bufferSize, const int strlen)
{
int len = strlen;
if (len > bufferSize)
{
len = bufferSize;
}
for (int index = 0; index < (len / 2); index++)
{
char ch = buffer[index];
buffer[index] = buffer[len - index - 1];
buffer[len - index - 1] = ch;
}
}
static int negateBuffer(char *buffer, const int bufferSize, const int strlen, const int radix)
{
int len = strlen;
if (len > bufferSize)
{
len = bufferSize;
}
if (radix == 10)
{
if (len < (bufferSize - 1))
{
buffer[len++] = '-';
buffer[len] = '\0';
}
}
else
{
int twosCompIndex = 0;
for (int index = 0; index < len; index++)
{
if ((buffer[index] >= '0') && (buffer[index] <= '9'))
{
twosCompIndex = buffer[index] - '0';
}
else if ((buffer[index] >= 'A') && (buffer[index] <= 'F'))
{
twosCompIndex = buffer[index] - 'A' + 10;
}
else if ((buffer[index] >= 'a') && (buffer[index] <= 'f'))
{
twosCompIndex = buffer[index] - 'a' + 10;
}
twosCompIndex += (16 - radix);
buffer[index] = _twosComp[twosCompIndex];
}
if (len < (bufferSize - 1))
{
buffer[len++] = _numberSystem[radix - 1];
buffer[len] = 0;
}
}
return len;
}
static int twosNegation(const int x, const int radix)
{
int n = x;
if (x < 0)
{
if (radix == 10)
{
n = -x;
}
else
{
n = ~x;
}
}
return n;
}
static char *safeitoa(const int x, char *buffer, const int bufferSize, const int radix)
{
int strlen = 0;
int n = twosNegation(x, radix);
int nuberSystemIndex = 0;
if (radix <= 16)
{
do
{
if (strlen < (bufferSize - 1))
{
nuberSystemIndex = (n % radix);
buffer[strlen++] = _numberSystem[nuberSystemIndex];
buffer[strlen] = '\0';
n = n / radix;
}
else
{
break;
}
} while (n != 0);
if (x < 0)
{
strlen = negateBuffer(buffer, bufferSize, strlen, radix);
}
safestrrev(buffer, bufferSize, strlen);
return buffer;
}
return NULL;
}
Where is the itoa function in Linux?
As itoa() is not standard in C, various versions with various function signatures exists.
char *itoa(int value, char *str, int base); is common in *nix.
Should it be missing from Linux or if code does not want to limit portability, code could make it own.
Below is a version that does not have trouble with INT_MIN and handles problem buffers: NULL or an insufficient buffer returns NULL.
#include <stdlib.h>
#include <limits.h>
#include <string.h>
// Buffer sized for a decimal string of a `signed int`, 28/93 > log10(2)
#define SIGNED_PRINT_SIZE(object) ((sizeof(object) * CHAR_BIT - 1)* 28 / 93 + 3)
char *itoa_x(int number, char *dest, size_t dest_size) {
if (dest == NULL) {
return NULL;
}
char buf[SIGNED_PRINT_SIZE(number)];
char *p = &buf[sizeof buf - 1];
// Work with negative absolute value
int neg_num = number < 0 ? number : -number;
// Form string
*p = '\0';
do {
*--p = (char) ('0' - neg_num % 10);
neg_num /= 10;
} while (neg_num);
if (number < 0) {
*--p = '-';
}
// Copy string
size_t src_size = (size_t) (&buf[sizeof buf] - p);
if (src_size > dest_size) {
// Not enough room
return NULL;
}
return memcpy(dest, p, src_size);
}
Below is a C99 or later version that handles any base [2...36]
char *itoa_x(int number, char *dest, size_t dest_size, int base) {
if (dest == NULL || base < 2 || base > 36) {
return NULL;
}
char buf[sizeof number * CHAR_BIT + 2]; // worst case: itoa(INT_MIN,,,2)
char *p = &buf[sizeof buf - 1];
// Work with negative absolute value to avoid UB of `abs(INT_MIN)`
int neg_num = number < 0 ? number : -number;
// Form string
*p = '\0';
do {
*--p = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[-(neg_num % base)];
neg_num /= base;
} while (neg_num);
if (number < 0) {
*--p = '-';
}
// Copy string
size_t src_size = (size_t) (&buf[sizeof buf] - p);
if (src_size > dest_size) {
// Not enough room
return NULL;
}
return memcpy(dest, p, src_size);
}
For a C89 and onward compliant code, replace inner loop with
div_t qr;
do {
qr = div(neg_num, base);
*--p = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[-qr.rem];
neg_num = qr.quot;
} while (neg_num);
glibc internal implementation
glibc 2.28 has an internal implementation:
stdio-common/_itoa.c
sysdeps/generic/_itoa.h
which is used in several places internally, but I could not find if it can be exposed or how.
At least that should be a robust implementation if you are willing to extract it.
This question asks how to roll your own: How to convert an int to string in C?
I would prefer this: https://github.com/wsq003/itoa_for_linux
It should be the fastest itoa() ever. We use itoa() instead of sprintf() for performance reason, so a fastest itoa() with limited feature is reasonable and worthwhile.
If you just want to print them:
void binary(unsigned int n)
{
for(int shift=sizeof(int)*8-1;shift>=0;shift--)
{
if (n >> shift & 1)
printf("1");
else
printf("0");
}
printf("\n");
}
The replacement with snprintf is NOT complete!
It covers only bases: 2, 8, 10, 16, whereas itoa works for bases between 2 and 36.
Since I was searching a replacement for base 32, I guess I'll have to code my own!
I have used _itoa(...) on RedHat 6 and GCC compiler. It works.
You can use this program instead of sprintf.
void itochar(int x, char *buffer, int radix);
int main()
{
char buffer[10];
itochar(725, buffer, 10);
printf ("\n %s \n", buffer);
return 0;
}
void itochar(int x, char *buffer, int radix)
{
int i = 0 , n,s;
n = s;
while (n > 0)
{
s = n%radix;
n = n/radix;
buffer[i++] = '0' + s;
}
buffer[i] = '\0';
strrev(buffer);
}

int to string in C? [duplicate]

itoa() is a really handy function to convert a number to a string. Linux does not seem to have itoa(), is there an equivalent function or do I have to use sprintf(str, "%d", num)?
EDIT: Sorry, I should have remembered that this machine is decidedly non-standard, having plugged in various non-standard libc implementations for academic purposes ;-)
As itoa() is indeed non-standard, as mentioned by several helpful commenters, it is best to use sprintf(target_string,"%d",source_int) or (better yet, because it's safe from buffer overflows) snprintf(target_string, size_of_target_string_in_bytes, "%d", source_int). I know it's not quite as concise or cool as itoa(), but at least you can Write Once, Run Everywhere (tm) ;-)
Here's the old (edited) answer
You are correct in stating that the default gcc libc does not include itoa(), like several other platforms, due to it not technically being a part of the standard. See here for a little more info. Note that you have to
#include <stdlib.h>
Of course you already know this, because you wanted to use itoa() on Linux after presumably using it on another platform, but... the code (stolen from the link above) would look like:
Example
/* itoa example */
#include <stdio.h>
#include <stdlib.h>
int main ()
{
int i;
char buffer [33];
printf ("Enter a number: ");
scanf ("%d",&i);
itoa (i,buffer,10);
printf ("decimal: %s\n",buffer);
itoa (i,buffer,16);
printf ("hexadecimal: %s\n",buffer);
itoa (i,buffer,2);
printf ("binary: %s\n",buffer);
return 0;
}
Output:
Enter a number: 1750
decimal: 1750
hexadecimal: 6d6
binary: 11011010110
itoa is not a standard C function. You can implement your own. It appeared in the first edition of Kernighan and Ritchie's The C Programming Language, on page 60. The second edition of The C Programming Language ("K&R2") contains the following implementation of itoa, on page 64. The book notes several issues with this implementation, including the fact that it does not correctly handle the most negative number
/* itoa: convert n to characters in s */
void itoa(int n, char s[])
{
int i, sign;
if ((sign = n) < 0) /* record sign */
n = -n; /* make n positive */
i = 0;
do { /* generate digits in reverse order */
s[i++] = n % 10 + '0'; /* get next digit */
} while ((n /= 10) > 0); /* delete it */
if (sign < 0)
s[i++] = '-';
s[i] = '\0';
reverse(s);
}
The function reverse used above is implemented two pages earlier:
#include <string.h>
/* reverse: reverse string s in place */
void reverse(char s[])
{
int i, j;
char c;
for (i = 0, j = strlen(s)-1; i<j; i++, j--) {
c = s[i];
s[i] = s[j];
s[j] = c;
}
}
If you are calling it a lot, the advice of "just use snprintf" can be annoying. So here's what you probably want:
const char *my_itoa_buf(char *buf, size_t len, int num)
{
static char loc_buf[sizeof(int) * CHAR_BITS]; /* not thread safe */
if (!buf)
{
buf = loc_buf;
len = sizeof(loc_buf);
}
if (snprintf(buf, len, "%d", num) == -1)
return ""; /* or whatever */
return buf;
}
const char *my_itoa(int num)
{ return my_itoa_buf(NULL, 0, num); }
Edit: I just found out about std::to_string which is identical in operation to my own function below. It was introduced in C++11 and is available in recent versions of gcc, at least as early as 4.5 if you enable the c++0x extensions.
Not only is itoa missing from gcc, it's not the handiest function to use since you need to feed it a buffer. I needed something that could be used in an expression so I came up with this:
std::string itos(int n)
{
const int max_size = std::numeric_limits<int>::digits10 + 1 /*sign*/ + 1 /*0-terminator*/;
char buffer[max_size] = {0};
sprintf(buffer, "%d", n);
return std::string(buffer);
}
Ordinarily it would be safer to use snprintf instead of sprintf but the buffer is carefully sized to be immune to overrun.
See an example: http://ideone.com/mKmZVE
As Matt J wrote, there is itoa, but it's not standard. Your code will be more portable if you use snprintf.
Following function allocates just enough memory to keep string representation of the given number and then writes the string representation into this area using standard sprintf method.
char *itoa(long n)
{
int len = n==0 ? 1 : floor(log10l(labs(n)))+1;
if (n<0) len++; // room for negative sign '-'
char *buf = calloc(sizeof(char), len+1); // +1 for null
snprintf(buf, len+1, "%ld", n);
return buf;
}
Don't forget to free up allocated memory when out of need:
char *num_str = itoa(123456789L);
// ...
free(num_str);
N.B. As snprintf copies n-1 bytes, we have to call snprintf(buf, len+1, "%ld", n) (not just snprintf(buf, len, "%ld", n))
Where is the itoa function in Linux?
There is no such function in Linux. I use this code instead.
/*
=============
itoa
Convert integer to string
PARAMS:
- value A 64-bit number to convert
- str Destination buffer; should be 66 characters long for radix2, 24 - radix8, 22 - radix10, 18 - radix16.
- radix Radix must be in range -36 .. 36. Negative values used for signed numbers.
=============
*/
char* itoa (unsigned long long value, char str[], int radix)
{
char buf [66];
char* dest = buf + sizeof(buf);
boolean sign = false;
if (value == 0) {
memcpy (str, "0", 2);
return str;
}
if (radix < 0) {
radix = -radix;
if ( (long long) value < 0) {
value = -value;
sign = true;
}
}
*--dest = '\0';
switch (radix)
{
case 16:
while (value) {
* --dest = '0' + (value & 0xF);
if (*dest > '9') *dest += 'A' - '9' - 1;
value >>= 4;
}
break;
case 10:
while (value) {
*--dest = '0' + (value % 10);
value /= 10;
}
break;
case 8:
while (value) {
*--dest = '0' + (value & 7);
value >>= 3;
}
break;
case 2:
while (value) {
*--dest = '0' + (value & 1);
value >>= 1;
}
break;
default: // The slow version, but universal
while (value) {
*--dest = '0' + (value % radix);
if (*dest > '9') *dest += 'A' - '9' - 1;
value /= radix;
}
break;
}
if (sign) *--dest = '-';
memcpy (str, dest, buf +sizeof(buf) - dest);
return str;
}
Reading the code of guys who do it for a living will get you a LONG WAY.
Check out how guys from MySQL did it. The source is VERY WELL COMMENTED and will teach you much more than hacked up solutions found all over the place.
MySQL's implementation of int2str
I provide the mentioned implementation here; the link is here for reference and should be used to read the full implementation.
char *
int2str(long int val, char *dst, int radix,
int upcase)
{
char buffer[65];
char *p;
long int new_val;
char *dig_vec= upcase ? _dig_vec_upper : _dig_vec_lower;
ulong uval= (ulong) val;
if (radix < 0)
{
if (radix < -36 || radix > -2)
return NullS;
if (val < 0)
{
*dst++ = '-';
/* Avoid integer overflow in (-val) for LLONG_MIN (BUG#31799). */
uval = (ulong)0 - uval;
}
radix = -radix;
}
else if (radix > 36 || radix < 2)
return NullS;
/*
The slightly contorted code which follows is due to the fact that
few machines directly support unsigned long / and %. Certainly
the VAX C compiler generates a subroutine call. In the interests
of efficiency (hollow laugh) I let this happen for the first digit
only; after that "val" will be in range so that signed integer
division will do. Sorry 'bout that. CHECK THE CODE PRODUCED BY
YOUR C COMPILER. The first % and / should be unsigned, the second
% and / signed, but C compilers tend to be extraordinarily
sensitive to minor details of style. This works on a VAX, that's
all I claim for it.
*/
p = &buffer[sizeof(buffer)-1];
*p = '\0';
new_val= uval / (ulong) radix;
*--p = dig_vec[(uchar) (uval- (ulong) new_val*(ulong) radix)];
val = new_val;
while (val != 0)
{
ldiv_t res;
res=ldiv(val,radix);
*--p = dig_vec[res.rem];
val= res.quot;
}
while ((*dst++ = *p++) != 0) ;
return dst-1;
}
i tried my own implementation of itoa(), it seem's work in binary, octal, decimal and hex
#define INT_LEN (10)
#define HEX_LEN (8)
#define BIN_LEN (32)
#define OCT_LEN (11)
static char * my_itoa ( int value, char * str, int base )
{
int i,n =2,tmp;
char buf[BIN_LEN+1];
switch(base)
{
case 16:
for(i = 0;i<HEX_LEN;++i)
{
if(value/base>0)
{
n++;
}
}
snprintf(str, n, "%x" ,value);
break;
case 10:
for(i = 0;i<INT_LEN;++i)
{
if(value/base>0)
{
n++;
}
}
snprintf(str, n, "%d" ,value);
break;
case 8:
for(i = 0;i<OCT_LEN;++i)
{
if(value/base>0)
{
n++;
}
}
snprintf(str, n, "%o" ,value);
break;
case 2:
for(i = 0,tmp = value;i<BIN_LEN;++i)
{
if(tmp/base>0)
{
n++;
}
tmp/=base;
}
for(i = 1 ,tmp = value; i<n;++i)
{
if(tmp%2 != 0)
{
buf[n-i-1] ='1';
}
else
{
buf[n-i-1] ='0';
}
tmp/=base;
}
buf[n-1] = '\0';
strcpy(str,buf);
break;
default:
return NULL;
}
return str;
}
direct copy to buffer : 64 bit integer itoa hex :
char* itoah(long num, char* s, int len)
{
long n, m = 16;
int i = 16+2;
int shift = 'a'- ('9'+1);
if(!s || len < 1)
return 0;
n = num < 0 ? -1 : 1;
n = n * num;
len = len > i ? i : len;
i = len < i ? len : i;
s[i-1] = 0;
i--;
if(!num)
{
if(len < 2)
return &s[i];
s[i-1]='0';
return &s[i-1];
}
while(i && n)
{
s[i-1] = n % m + '0';
if (s[i-1] > '9')
s[i-1] += shift ;
n = n/m;
i--;
}
if(num < 0)
{
if(i)
{
s[i-1] = '-';
i--;
}
}
return &s[i];
}
note: change long to long long for 32 bit machine. long to int in case for 32 bit integer. m is the radix. When decreasing radix, increase number of characters (variable i). When increasing radix, decrease number of characters (better). In case of unsigned data type, i just becomes 16 + 1.
Here is a much improved version of Archana's solution. It works for any radix 1-16, and numbers <= 0, and it shouldn't clobber memory.
static char _numberSystem[] = "0123456789ABCDEF";
static char _twosComp[] = "FEDCBA9876543210";
static void safestrrev(char *buffer, const int bufferSize, const int strlen)
{
int len = strlen;
if (len > bufferSize)
{
len = bufferSize;
}
for (int index = 0; index < (len / 2); index++)
{
char ch = buffer[index];
buffer[index] = buffer[len - index - 1];
buffer[len - index - 1] = ch;
}
}
static int negateBuffer(char *buffer, const int bufferSize, const int strlen, const int radix)
{
int len = strlen;
if (len > bufferSize)
{
len = bufferSize;
}
if (radix == 10)
{
if (len < (bufferSize - 1))
{
buffer[len++] = '-';
buffer[len] = '\0';
}
}
else
{
int twosCompIndex = 0;
for (int index = 0; index < len; index++)
{
if ((buffer[index] >= '0') && (buffer[index] <= '9'))
{
twosCompIndex = buffer[index] - '0';
}
else if ((buffer[index] >= 'A') && (buffer[index] <= 'F'))
{
twosCompIndex = buffer[index] - 'A' + 10;
}
else if ((buffer[index] >= 'a') && (buffer[index] <= 'f'))
{
twosCompIndex = buffer[index] - 'a' + 10;
}
twosCompIndex += (16 - radix);
buffer[index] = _twosComp[twosCompIndex];
}
if (len < (bufferSize - 1))
{
buffer[len++] = _numberSystem[radix - 1];
buffer[len] = 0;
}
}
return len;
}
static int twosNegation(const int x, const int radix)
{
int n = x;
if (x < 0)
{
if (radix == 10)
{
n = -x;
}
else
{
n = ~x;
}
}
return n;
}
static char *safeitoa(const int x, char *buffer, const int bufferSize, const int radix)
{
int strlen = 0;
int n = twosNegation(x, radix);
int nuberSystemIndex = 0;
if (radix <= 16)
{
do
{
if (strlen < (bufferSize - 1))
{
nuberSystemIndex = (n % radix);
buffer[strlen++] = _numberSystem[nuberSystemIndex];
buffer[strlen] = '\0';
n = n / radix;
}
else
{
break;
}
} while (n != 0);
if (x < 0)
{
strlen = negateBuffer(buffer, bufferSize, strlen, radix);
}
safestrrev(buffer, bufferSize, strlen);
return buffer;
}
return NULL;
}
Where is the itoa function in Linux?
As itoa() is not standard in C, various versions with various function signatures exists.
char *itoa(int value, char *str, int base); is common in *nix.
Should it be missing from Linux or if code does not want to limit portability, code could make it own.
Below is a version that does not have trouble with INT_MIN and handles problem buffers: NULL or an insufficient buffer returns NULL.
#include <stdlib.h>
#include <limits.h>
#include <string.h>
// Buffer sized for a decimal string of a `signed int`, 28/93 > log10(2)
#define SIGNED_PRINT_SIZE(object) ((sizeof(object) * CHAR_BIT - 1)* 28 / 93 + 3)
char *itoa_x(int number, char *dest, size_t dest_size) {
if (dest == NULL) {
return NULL;
}
char buf[SIGNED_PRINT_SIZE(number)];
char *p = &buf[sizeof buf - 1];
// Work with negative absolute value
int neg_num = number < 0 ? number : -number;
// Form string
*p = '\0';
do {
*--p = (char) ('0' - neg_num % 10);
neg_num /= 10;
} while (neg_num);
if (number < 0) {
*--p = '-';
}
// Copy string
size_t src_size = (size_t) (&buf[sizeof buf] - p);
if (src_size > dest_size) {
// Not enough room
return NULL;
}
return memcpy(dest, p, src_size);
}
Below is a C99 or later version that handles any base [2...36]
char *itoa_x(int number, char *dest, size_t dest_size, int base) {
if (dest == NULL || base < 2 || base > 36) {
return NULL;
}
char buf[sizeof number * CHAR_BIT + 2]; // worst case: itoa(INT_MIN,,,2)
char *p = &buf[sizeof buf - 1];
// Work with negative absolute value to avoid UB of `abs(INT_MIN)`
int neg_num = number < 0 ? number : -number;
// Form string
*p = '\0';
do {
*--p = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[-(neg_num % base)];
neg_num /= base;
} while (neg_num);
if (number < 0) {
*--p = '-';
}
// Copy string
size_t src_size = (size_t) (&buf[sizeof buf] - p);
if (src_size > dest_size) {
// Not enough room
return NULL;
}
return memcpy(dest, p, src_size);
}
For a C89 and onward compliant code, replace inner loop with
div_t qr;
do {
qr = div(neg_num, base);
*--p = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[-qr.rem];
neg_num = qr.quot;
} while (neg_num);
glibc internal implementation
glibc 2.28 has an internal implementation:
stdio-common/_itoa.c
sysdeps/generic/_itoa.h
which is used in several places internally, but I could not find if it can be exposed or how.
At least that should be a robust implementation if you are willing to extract it.
This question asks how to roll your own: How to convert an int to string in C?
I would prefer this: https://github.com/wsq003/itoa_for_linux
It should be the fastest itoa() ever. We use itoa() instead of sprintf() for performance reason, so a fastest itoa() with limited feature is reasonable and worthwhile.
If you just want to print them:
void binary(unsigned int n)
{
for(int shift=sizeof(int)*8-1;shift>=0;shift--)
{
if (n >> shift & 1)
printf("1");
else
printf("0");
}
printf("\n");
}
The replacement with snprintf is NOT complete!
It covers only bases: 2, 8, 10, 16, whereas itoa works for bases between 2 and 36.
Since I was searching a replacement for base 32, I guess I'll have to code my own!
I have used _itoa(...) on RedHat 6 and GCC compiler. It works.
You can use this program instead of sprintf.
void itochar(int x, char *buffer, int radix);
int main()
{
char buffer[10];
itochar(725, buffer, 10);
printf ("\n %s \n", buffer);
return 0;
}
void itochar(int x, char *buffer, int radix)
{
int i = 0 , n,s;
n = s;
while (n > 0)
{
s = n%radix;
n = n/radix;
buffer[i++] = '0' + s;
}
buffer[i] = '\0';
strrev(buffer);
}

How to format a number using comma as thousands separator in C?

In C, how can I format a large number from e.g. 1123456789 to 1,123,456,789?
I tried using printf("%'10d\n", 1123456789), but that doesn't work.
Could you advise anything? The simpler the solution the better.
If your printf supports the ' flag (as required by POSIX 2008 printf()), you can probably do it just by setting your locale appropriately. Example:
#include <stdio.h>
#include <locale.h>
int main(void)
{
setlocale(LC_NUMERIC, "");
printf("%'d\n", 1123456789);
return 0;
}
And build & run:
$ ./example
1,123,456,789
Tested on Mac OS X & Linux (Ubuntu 10.10).
You can do it recursively as follows (beware INT_MIN if you're using two's complement, you'll need extra code to manage that):
void printfcomma2 (int n) {
if (n < 1000) {
printf ("%d", n);
return;
}
printfcomma2 (n/1000);
printf (",%03d", n%1000);
}
void printfcomma (int n) {
if (n < 0) {
printf ("-");
n = -n;
}
printfcomma2 (n);
}
A summmary:
User calls printfcomma with an integer, the special case of negative numbers is handled by simply printing "-" and making the number positive (this is the bit that won't work with INT_MIN).
When you enter printfcomma2, a number less than 1,000 will just print and return.
Otherwise the recursion will be called on the next level up (so 1,234,567 will be called with 1,234, then 1) until a number less than 1,000 is found.
Then that number will be printed and we'll walk back up the recursion tree, printing a comma and the next number as we go.
There is also the more succinct version though it does unnecessary processing in checking for negative numbers at every level (not that this will matter given the limited number of recursion levels). This one is a complete program for testing:
#include <stdio.h>
void printfcomma (int n) {
if (n < 0) {
printf ("-");
printfcomma (-n);
return;
}
if (n < 1000) {
printf ("%d", n);
return;
}
printfcomma (n/1000);
printf (",%03d", n%1000);
}
int main (void) {
int x[] = {-1234567890, -123456, -12345, -1000, -999, -1,
0, 1, 999, 1000, 12345, 123456, 1234567890};
int *px = x;
while (px != &(x[sizeof(x)/sizeof(*x)])) {
printf ("%-15d: ", *px);
printfcomma (*px);
printf ("\n");
px++;
}
return 0;
}
and the output is:
-1234567890 : -1,234,567,890
-123456 : -123,456
-12345 : -12,345
-1000 : -1,000
-999 : -999
-1 : -1
0 : 0
1 : 1
999 : 999
1000 : 1,000
12345 : 12,345
123456 : 123,456
1234567890 : 1,234,567,890
An iterative solution for those who don't trust recursion (although the only problem with recursion tends to be stack space which will not be an issue here since it'll only be a few levels deep even for a 64-bit integer):
void printfcomma (int n) {
int n2 = 0;
int scale = 1;
if (n < 0) {
printf ("-");
n = -n;
}
while (n >= 1000) {
n2 = n2 + scale * (n % 1000);
n /= 1000;
scale *= 1000;
}
printf ("%d", n);
while (scale != 1) {
scale /= 1000;
n = n2 / scale;
n2 = n2 % scale;
printf (",%03d", n);
}
}
Both of these generate 2,147,483,647 for INT_MAX.
All the code above is for comma-separating three-digit groups but you can use other characters as well, such as a space:
void printfspace2 (int n) {
if (n < 1000) {
printf ("%d", n);
return;
}
printfspace2 (n/1000);
printf (" %03d", n%1000);
}
void printfspace (int n) {
if (n < 0) {
printf ("-");
n = -n;
}
printfspace2 (n);
}
Here's a very simple implementation. This function contains no error checking, buffer sizes must be verified by the caller. It also does not work for negative numbers. Such improvements are left as an exercise for the reader.
void format_commas(int n, char *out)
{
int c;
char buf[20];
char *p;
sprintf(buf, "%d", n);
c = 2 - strlen(buf) % 3;
for (p = buf; *p != 0; p++) {
*out++ = *p;
if (c == 1) {
*out++ = ',';
}
c = (c + 1) % 3;
}
*--out = 0;
}
Egads! I do this all the time, using gcc/g++ and glibc on linux and yes, the ' operator may be non-standard, but I like the simplicity of it.
#include <stdio.h>
#include <locale.h>
int main()
{
int bignum=12345678;
setlocale(LC_ALL,"");
printf("Big number: %'d\n",bignum);
return 0;
}
Gives output of:
Big number: 12,345,678
Just have to remember the 'setlocale' call in there, otherwise it won't format anything.
Perhaps a locale-aware version would be interesting.
#include <stdlib.h>
#include <locale.h>
#include <string.h>
#include <limits.h>
static int next_group(char const **grouping) {
if ((*grouping)[1] == CHAR_MAX)
return 0;
if ((*grouping)[1] != '\0')
++*grouping;
return **grouping;
}
size_t commafmt(char *buf, /* Buffer for formatted string */
int bufsize, /* Size of buffer */
long N) /* Number to convert */
{
int i;
int len = 1;
int posn = 1;
int sign = 1;
char *ptr = buf + bufsize - 1;
struct lconv *fmt_info = localeconv();
char const *tsep = fmt_info->thousands_sep;
char const *group = fmt_info->grouping;
char const *neg = fmt_info->negative_sign;
size_t sep_len = strlen(tsep);
size_t group_len = strlen(group);
size_t neg_len = strlen(neg);
int places = (int)*group;
if (bufsize < 2)
{
ABORT:
*buf = '\0';
return 0;
}
*ptr-- = '\0';
--bufsize;
if (N < 0L)
{
sign = -1;
N = -N;
}
for ( ; len <= bufsize; ++len, ++posn)
{
*ptr-- = (char)((N % 10L) + '0');
if (0L == (N /= 10L))
break;
if (places && (0 == (posn % places)))
{
places = next_group(&group);
for (int i=sep_len; i>0; i--) {
*ptr-- = tsep[i-1];
if (++len >= bufsize)
goto ABORT;
}
}
if (len >= bufsize)
goto ABORT;
}
if (sign < 0)
{
if (len >= bufsize)
goto ABORT;
for (int i=neg_len; i>0; i--) {
*ptr-- = neg[i-1];
if (++len >= bufsize)
goto ABORT;
}
}
memmove(buf, ++ptr, len + 1);
return (size_t)len;
}
#ifdef TEST
#include <stdio.h>
#define elements(x) (sizeof(x)/sizeof(x[0]))
void show(long i) {
char buffer[32];
commafmt(buffer, sizeof(buffer), i);
printf("%s\n", buffer);
commafmt(buffer, sizeof(buffer), -i);
printf("%s\n", buffer);
}
int main() {
long inputs[] = {1, 12, 123, 1234, 12345, 123456, 1234567, 12345678 };
for (int i=0; i<elements(inputs); i++) {
setlocale(LC_ALL, "");
show(inputs[i]);
}
return 0;
}
#endif
This does have a bug (but one I'd consider fairly minor). On two's complement hardware, it won't convert the most-negative number correctly, because it attempts to convert a negative number to its equivalent positive number with N = -N; In two's complement, the maximally negative number doesn't have a corresponding positive number, unless you promote it to a larger type. One way to get around this is by promoting the number the corresponding unsigned type (but it's is somewhat non-trivial).
Without recursion or string handling, a mathematical approach:
#include <stdio.h>
#include <math.h>
void print_number( int n )
{
int order_of_magnitude = (n == 0) ? 1 : (int)pow( 10, ((int)floor(log10(abs(n))) / 3) * 3 ) ;
printf( "%d", n / order_of_magnitude ) ;
for( n = abs( n ) % order_of_magnitude, order_of_magnitude /= 1000;
order_of_magnitude > 0;
n %= order_of_magnitude, order_of_magnitude /= 1000 )
{
printf( ",%03d", abs(n / order_of_magnitude) ) ;
}
}
Similar in principle to Pax's recursive solution, but by calculating the order of magnitude in advance, recursion is avoided (at some considerable expense perhaps).
Note also that the actual character used to separate thousands is locale specific.
Edit:See #Chux's comments below for improvements.
Based on #Greg Hewgill's, but takes negative numbers into account and returns the string size.
size_t str_format_int_grouped(char dst[16], int num)
{
char src[16];
char *p_src = src;
char *p_dst = dst;
const char separator = ',';
int num_len, commas;
num_len = sprintf(src, "%d", num);
if (*p_src == '-') {
*p_dst++ = *p_src++;
num_len--;
}
for (commas = 2 - num_len % 3;
*p_src;
commas = (commas + 1) % 3)
{
*p_dst++ = *p_src++;
if (commas == 1) {
*p_dst++ = separator;
}
}
*--p_dst = '\0';
return (size_t)(p_dst - dst);
}
Needed to do something similar myself but rather than printing directly, needed to go to a buffer. Here's what I came up with. Works backwards.
unsigned int IntegerToCommaString(char *String, unsigned long long Integer)
{
unsigned int Digits = 0, Offset, Loop;
unsigned long long Copy = Integer;
do {
Digits++;
Copy /= 10;
} while (Copy);
Digits = Offset = ((Digits - 1) / 3) + Digits;
String[Offset--] = '\0';
Copy = Integer;
Loop = 0;
do {
String[Offset] = '0' + (Copy % 10);
if (!Offset--)
break;
if (Loop++ % 3 == 2)
String[Offset--] = ',';
Copy /= 10;
} while (1);
return Digits;
}
Be aware that it's only designed for unsigned integers and you must ensure that the buffer is large enough.
There's no real simple way to do this in C. I would just modify an int-to-string function to do it:
void format_number(int n, char * out) {
int i;
int digit;
int out_index = 0;
for (i = n; i != 0; i /= 10) {
digit = i % 10;
if ((out_index + 1) % 4 == 0) {
out[out_index++] = ',';
}
out[out_index++] = digit + '0';
}
out[out_index] = '\0';
// then you reverse the out string as it was converted backwards (it's easier that way).
// I'll let you figure that one out.
strrev(out);
}
My answer does not format the result exactly like the illustration in the question, but may fulfill the actual need in some cases with a simple one-liner or macro. One can extend it to generate more thousand-groups as necessary.
The result will look for example as follows:
Value: 0'000'012'345
The code:
printf("Value: %llu'%03lu'%03lu'%03lu\n", (value / 1000 / 1000 / 1000), (value / 1000 / 1000) % 1000, (value / 1000) % 1000, value % 1000);
#include <stdio.h>
void punt(long long n){
char s[28];
int i = 27;
if(n<0){n=-n; putchar('-');}
do{
s[i--] = n%10 + '0';
if(!(i%4) && n>9)s[i--]='.';
n /= 10;
}while(n);
puts(&s[++i]);
}
int main(){
punt(2134567890);
punt(987);
punt(9876);
punt(-987);
punt(-9876);
punt(-654321);
punt(0);
punt(1000000000);
punt(0x7FFFFFFFFFFFFFFF);
punt(0x8000000000000001); // -max + 1 ...
}
My solution uses a . instead of a ,
It is left to the reader to change this.
This is old and there are plenty of answers but the question was not "how can I write a routine to add commas" but "how can it be done in C"? The comments pointed to this direction but on my Linux system with GCC, this works for me:
#include <stdio.h>
#include <stdlib.h>
#include <locale.h>
int main()
{
unsetenv("LC_ALL");
setlocale(LC_NUMERIC, "");
printf("%'lld\n", 3141592653589);
}
When this is run, I get:
$ cc -g comma.c -o comma && ./comma
3,141,592,653,589
If I unset the LC_ALL variable before running the program the unsetenv is not necessary.
Another solution, by saving the result into an int array, maximum size of 7 because the long long int type can handle numbers in the range 9,223,372,036,854,775,807 to -9,223,372,036,854,775,807. (Note it is not an unsigned value).
Non-recursive printing function
static void printNumber (int numbers[8], int loc, int negative)
{
if (negative)
{
printf("-");
}
if (numbers[1]==-1)//one number
{
printf("%d ", numbers[0]);
}
else
{
printf("%d,", numbers[loc]);
while(loc--)
{
if(loc==0)
{// last number
printf("%03d ", numbers[loc]);
break;
}
else
{ // number in between
printf("%03d,", numbers[loc]);
}
}
}
}
main function call
static void getNumWcommas (long long int n, int numbers[8])
{
int i;
int negative=0;
if (n < 0)
{
negative = 1;
n = -n;
}
for(i = 0; i < 7; i++)
{
if (n < 1000)
{
numbers[i] = n;
numbers[i+1] = -1;
break;
}
numbers[i] = n%1000;
n/=1000;
}
printNumber(numbers, i, negative);// non recursive print
}
testing output
-9223372036854775807: -9,223,372,036,854,775,807
-1234567890 : -1,234,567,890
-123456 : -123,456
-12345 : -12,345
-1000 : -1,000
-999 : -999
-1 : -1
0 : 0
1 : 1
999 : 999
1000 : 1,000
12345 : 12,345
123456 : 123,456
1234567890 : 1,234,567,890
9223372036854775807 : 9,223,372,036,854,775,807
In main() function:
int numberSeparated[8];
long long int number = 1234567890LL;
getNumWcommas(number, numberSeparated);
If printing is all that's needed then move int numberSeparated[8]; inside the function getNumWcommas and call it this way getNumWcommas(number).
Another iterative function
int p(int n) {
if(n < 0) {
printf("-");
n = -n;
}
int a[sizeof(int) * CHAR_BIT / 3] = { 0 };
int *pa = a;
while(n > 0) {
*++pa = n % 1000;
n /= 1000;
}
printf("%d", *pa);
while(pa > a + 1) {
printf(",%03d", *--pa);
}
}
Here is the slimiest, size and speed efficient implementation of this kind of decimal digit formating:
const char *formatNumber (
int value,
char *endOfbuffer,
bool plus)
{
int savedValue;
int charCount;
savedValue = value;
if (unlikely (value < 0))
value = - value;
*--endOfbuffer = 0;
charCount = -1;
do
{
if (unlikely (++charCount == 3))
{
charCount = 0;
*--endOfbuffer = ',';
}
*--endOfbuffer = (char) (value % 10 + '0');
}
while ((value /= 10) != 0);
if (unlikely (savedValue < 0))
*--endOfbuffer = '-';
else if (unlikely (plus))
*--endOfbuffer = '+';
return endOfbuffer;
}
Use as following:
char buffer[16];
fprintf (stderr, "test : %s.", formatNumber (1234567890, buffer + 16, true));
Output:
test : +1,234,567,890.
Some advantages:
Function taking end of string buffer because of reverse ordered formatting. Finally, where is no need in revering generated string (strrev).
This function produces one string that can be used in any algo after. It not depends nor require multiple printf/sprintf calls, which is terrible slow and always context specific.
Minimum number of divide operators (/, %).
Secure format_commas, with negative numbers:
Because VS < 2015 doesn't implement snprintf, you need to do this
#if defined(_WIN32)
#define snprintf(buf,len, format,...) _snprintf_s(buf, len,len, format, __VA_ARGS__)
#endif
And then
char* format_commas(int n, char *out)
{
int c;
char buf[100];
char *p;
char* q = out; // Backup pointer for return...
if (n < 0)
{
*out++ = '-';
n = abs(n);
}
snprintf(buf, 100, "%d", n);
c = 2 - strlen(buf) % 3;
for (p = buf; *p != 0; p++) {
*out++ = *p;
if (c == 1) {
*out++ = '\'';
}
c = (c + 1) % 3;
}
*--out = 0;
return q;
}
Example usage:
size_t currentSize = getCurrentRSS();
size_t peakSize = getPeakRSS();
printf("Current size: %d\n", currentSize);
printf("Peak size: %d\n\n\n", peakSize);
char* szcurrentSize = (char*)malloc(100 * sizeof(char));
char* szpeakSize = (char*)malloc(100 * sizeof(char));
printf("Current size (f): %s\n", format_commas((int)currentSize, szcurrentSize));
printf("Peak size (f): %s\n", format_commas((int)currentSize, szpeakSize));
free(szcurrentSize);
free(szpeakSize);
A modified version of #paxdiablo solution, but using WCHAR and wsprinf:
static WCHAR buffer[10];
static int pos = 0;
void printfcomma(const int &n) {
if (n < 0) {
wsprintf(buffer + pos, TEXT("-"));
pos = lstrlen(buffer);
printfcomma(-n);
return;
}
if (n < 1000) {
wsprintf(buffer + pos, TEXT("%d"), n);
pos = lstrlen(buffer);
return;
}
printfcomma(n / 1000);
wsprintf(buffer + pos, TEXT(",%03d"), n % 1000);
pos = lstrlen(buffer);
}
void my_sprintf(const int &n)
{
pos = 0;
printfcomma(n);
}
I'm new in C programming. Here is my simple code.
int main()
{
// 1223 => 1,223
int n;
int a[10];
printf(" n: ");
scanf_s("%d", &n);
int i = 0;
while (n > 0)
{
int temp = n % 1000;
a[i] = temp;
n /= 1000;
i++;
}
for (int j = i - 1; j >= 0; j--)
{
if (j == 0)
{
printf("%d.", a[j]);
}
else printf("%d,",a[j]);
}
getch();
return 0;
}
Require: <stdio.h> + <string.h>.
Advantage: short, readable, based on the format of scanf-family. And assume no comma on the right of decimal point.
void add_commas(char *in, char *out) {
int len_in = strlen(in);
int len_int = -1; /* len_int(123.4) = 3 */
for (int i = 0; i < len_in; ++i) if (in[i] == '.') len_int = i;
int pos = 0;
for (int i = 0; i < len_in; ++i) {
if (i>0 && i<len_int && (len_int-i)%3==0)
out[pos++] = ',';
out[pos++] = in[i];
}
out[pos] = 0; /* Append the '\0' */
}
Example, to print a formatted double:
#include <stdio.h>
#include <string.h>
#define COUNT_DIGIT_MAX 100
int main() {
double sum = 30678.7414;
char input[COUNT_DIGIT_MAX+1] = { 0 }, output[COUNT_DIGIT_MAX+1] = { 0 };
snprintf(input, COUNT_DIGIT_MAX, "%.2f", sum/12);
add_commas(input, output);
printf("%s\n", output);
}
Output:
2,556.56
Using C++'s std::string as return value with possibly the least overhead and not using any std library functions (sprintf, to_string, etc.).
string group_digs_c(int num)
{
const unsigned int BUF_SIZE = 128;
char buf[BUF_SIZE] = { 0 }, * pbuf = &buf[BUF_SIZE - 1];
int k = 0, neg = 0;
if (num < 0) { neg = 1; num = num * -1; };
while(num)
{
if (k > 0 && k % 3 == 0)
*pbuf-- = ',';
*pbuf-- = (num % 10) + '0';
num /= 10;
++k;
}
if (neg)
*pbuf = '-';
else
++pbuf;
int cc = buf + BUF_SIZE - pbuf;
memmove(buf, pbuf, cc);
buf[cc] = 0;
string rv = buf;
return rv;
}
Here is a simple portable solution relying on sprintf:
#include <stdio.h>
// assuming out points to an array of sufficient size
char *format_commas(char *out, int n, int min_digits) {
int len = sprintf(out, "%.*d", min_digits, n);
int i = (*out == '-'), j = len, k = (j - i - 1) / 3;
out[j + k] = '\0';
while (k-- > 0) {
j -= 3;
out[j + k + 3] = out[j + 2];
out[j + k + 2] = out[j + 1];
out[j + k + 1] = out[j + 0];
out[j + k + 0] = ',';
}
return out;
}
The code is easy to adapt for other integer types.
There are many interesting contributions here. Some covered all cases, some did not. I picked four of the contributions to test, found some failure cases during testing and then added a solution of my own.
I tested all methods for both accuracy and speed. Even though the OP only requested a solution for one positive number, I upgraded the contributions that didn't cover all possible numbers (so the code below may be slightly different from the original postings). The cases that weren't covered include: 0, negative numbers and the minimum number (INT_MIN).
I changed the declared type from "int" to "long long" since it's more general and all ints will get promoted to long long. I also standardized the call interface to include the number as well as a buffer to contain the formatted string (like some of the contributions) and returned a pointer to the buffer:
char* funcName(long long number_to_format, char* string_buffer);
Including a buffer parameter is considered by some to be "better" than having the function: 1) contain a static buffer (would not be re-entrant) or 2) allocate space for the buffer (would require caller to de-allocate the memory) or 3) print the result directly to stdout (would not be as generally useful since the output may be targeted for a GUI widget, file, pty, pipe, etc.).
I tried to use the same function names as the original contributions to make it easier to refer back to the originals. Contributed functions were modified as needed to pass the accuracy test so that the speed test would be meaningful. The results are included here in case you would like to test more of the contributed techniques for comparison. All code and test code used to generate the results are shown below.
So, here are the results:
Accuracy Test (test cases: LLONG_MIN, -999, -99, 0, 99, 999, LLONG_MAX):
----------------------------------------------------
print_number:
-9,223,372,036,854,775,808, -999, -99, 0, 99, 999, 9,223,372,036,854,775,807
fmtLocale:
-9,223,372,036,854,775,808, -999, -99, 0, 99, 999, 9,223,372,036,854,775,807
fmtCommas:
-9,223,372,036,854,775,808, -999, -99, 0, 99, 999, 9,223,372,036,854,775,807
format_number:
-9,223,372,036,854,775,808, -999, -99, 0, 99, 999, 9,223,372,036,854,775,807
itoa_commas:
-9,223,372,036,854,775,808, -999, -99, 0, 99, 999, 9,223,372,036,854,775,807
Speed Test: (1 million calls, values reflect average time per call)
----------------------------------------------------
print_number: 0.747 us (microsec) per call
fmtLocale: 0.222 us (microsec) per call
fmtCommas: 0.212 us (microsec) per call
format_number: 0.124 us (microsec) per call
itoa_commas: 0.085 us (microsec) per call
Since all contributed techniques are fast (< 1 microsecond on my laptop), unless you need to format millions of numbers, any of the techniques should be acceptable. It's probably best to choose the technique that is most readable to you.
Here is the code:
#line 2 "comma.c"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <math.h>
#include <locale.h>
#include <limits.h>
// ----------------------------------------------------------
char* print_number( long long n, char buf[32] ) {
long long order_of_magnitude = (n == 0) ? 1
: (long long)pow( 10, ((long long)floor(log10(fabs(n))) / 3) * 3 ) ;
char *ptr = buf;
sprintf(ptr, "%d", n / order_of_magnitude ) ;
for( n %= order_of_magnitude, order_of_magnitude /= 1000;
order_of_magnitude > 0;
n %= order_of_magnitude, order_of_magnitude /= 1000 )
{
ptr += strlen(ptr);
sprintf(ptr, ",%03d", abs(n / order_of_magnitude) );
}
return buf;
}
// ----------------------------------------------------------
char* fmtLocale(long long i, char buf[32]) {
sprintf(buf, "%'lld", i); // requires setLocale in main
return buf;
}
// ----------------------------------------------------------
char* fmtCommas(long long num, char dst[32]) {
char src[27];
char *p_src = src;
char *p_dst = dst;
const char separator = ',';
int num_len, commas;
num_len = sprintf(src, "%lld", num);
if (*p_src == '-') {
*p_dst++ = *p_src++;
num_len--;
}
for (commas = 2 - num_len % 3;
*p_src;
commas = (commas + 1) % 3)
{
*p_dst++ = *p_src++;
if (commas == 1) {
*p_dst++ = separator;
}
}
*--p_dst = '\0';
return dst;
}
// ----------------------------------------------------------
char* format_number(long long n, char out[32]) {
int digit;
int out_index = 0;
long long i = (n < 0) ? -n : n;
if (i == LLONG_MIN) i = LLONG_MAX; // handle MIN, offset by 1
if (i == 0) { out[out_index++] = '0'; } // handle 0
for ( ; i != 0; i /= 10) {
digit = i % 10;
if ((out_index + 1) % 4 == 0) {
out[out_index++] = ',';
}
out[out_index++] = digit + '0';
}
if (n == LLONG_MIN) { out[0]++; } // correct for offset
if (n < 0) { out[out_index++] = '-'; }
out[out_index] = '\0';
// then you reverse the out string
for (int i=0, j = strlen(out) - 1; i<=j; ++i, --j) {
char tmp = out[i];
out[i] = out[j];
out[j] = tmp;
}
return out;
}
// ----------------------------------------------------------
char* itoa_commas(long long i, char buf[32]) {
char* p = buf + 31;
*p = '\0'; // terminate string
if (i == 0) { *(--p) = '0'; return p; } // handle 0
long long n = (i < 0) ? -i : i;
if (n == LLONG_MIN) n = LLONG_MAX; // handle MIN, offset by 1
for (int j=0; 1; ++j) {
*--p = '0' + n % 10; // insert digit
if ((n /= 10) <= 0) break;
if (j % 3 == 2) *--p = ','; // insert a comma
}
if (i == LLONG_MIN) { p[24]++; } // correct for offset
if (i < 0) { *--p = '-'; }
return p;
}
// ----------------------------------------------------------
// Test Accuracy
// ----------------------------------------------------------
void test_accuracy(char* name, char* (*func)(long long n, char* buf)) {
char sbuf[32]; // string buffer
long long nbuf[] = { LLONG_MIN, -999, -99, 0, 99, 999, LLONG_MAX };
printf("%s:\n", name);
printf(" %s", func(nbuf[0], sbuf));
for (int i=1; i < sizeof(nbuf) / sizeof(long long int); ++i) {
printf(", %s", func(nbuf[i], sbuf));
}
printf("\n");
}
// ----------------------------------------------------------
// Test Speed
// ----------------------------------------------------------
void test_speed(char* name, char* (*func)(long long n, char* buf)) {
int cycleCount = 1000000;
//int cycleCount = 1;
clock_t start;
double elapsed;
char sbuf[32]; // string buffer
start = clock();
for (int i=0; i < cycleCount; ++i) {
char* s = func(LLONG_MAX, sbuf);
}
elapsed = (double)(clock() - start) / (CLOCKS_PER_SEC / 1000000.0);
printf("%14s: %7.3f us (microsec) per call\n", name, elapsed / cycleCount);
}
// ----------------------------------------------------------
int main(int argc, char* argv[]){
setlocale(LC_ALL, "");
printf("\nAccuracy Test: (LLONG_MIN, -999, 0, 99, LLONG_MAX)\n");
printf("----------------------------------------------------\n");
test_accuracy("print_number", print_number);
test_accuracy("fmtLocale", fmtLocale);
test_accuracy("fmtCommas", fmtCommas);
test_accuracy("format_number", format_number);
test_accuracy("itoa_commas", itoa_commas);
printf("\nSpeed Test: 1 million calls\n\n");
printf("----------------------------------------------------\n");
test_speed("print_number", print_number);
test_speed("fmtLocale", fmtLocale);
test_speed("fmtCommas", fmtCommas);
test_speed("format_number", format_number);
test_speed("itoa_commas", itoa_commas);
return 0;
}
Can be done pretty easily...
//Make sure output buffer is big enough and that input is a valid null terminated string
void pretty_number(const char* input, char * output)
{
int iInputLen = strlen(input);
int iOutputBufferPos = 0;
for(int i = 0; i < iInputLen; i++)
{
if((iInputLen-i) % 3 == 0 && i != 0)
{
output[iOutputBufferPos++] = ',';
}
output[iOutputBufferPos++] = input[i];
}
output[iOutputBufferPos] = '\0';
}
Example call:
char szBuffer[512];
pretty_number("1234567", szBuffer);
//strcmp(szBuffer, "1,234,567") == 0
void printfcomma ( long long unsigned int n)
{
char nstring[100];
int m;
int ptr;
int i,j;
sprintf(nstring,"%llu",n);
m=strlen(nstring);
ptr=m%3;
if (ptr)
{ for (i=0;i<ptr;i++) // print first digits before comma
printf("%c", nstring[i]);
printf(",");
}
j=0;
for (i=ptr;i<m;i++) // print the rest inserting commas
{
printf("%c",nstring[i]);
j++;
if (j%3==0)
if(i<(m-1)) printf(",");
}
}
// separate thousands
int digit;
int idx = 0;
static char buffer[32];
char* p = &buffer[32];
*--p = '\0';
for (int i = fCounter; i != 0; i /= 10)
{
digit = i % 10;
if ((p - buffer) % 4 == 0)
*--p = ' ';
*--p = digit + '0';
}

Resources