views:

341

answers:

8

Hi All,

How can I in C language format a number from 1123456789 to 1,123,456,789? I tried using printf("%'10d\n", 1123456789); but that doesn't work.

Could you advice anything? The simpler the solution the better.

Thanks, goe

A: 

There is no such functionality in the standard library. You'll have to use an external library or program it yourself.

dmckee
+5  A: 

Check this FAQ it explains exactly how to solve your problem.

Konstantinos
You might want to summarize here.
dmckee
i rather forward the people to the kind ones that wrote the FAQ
Konstantinos
I'm not a big fan of link-only answers since SO should be useful even if every other page on the net disappears. I'm all for acknowledging and linking to the pages but I believe the answer should be able to stand alone.
paxdiablo
So I fixed it for you :-)
paxdiablo
i respect your opinion, but ... rollback :)
Konstantinos
That's fine - but now I have to downvote since I don't consider it useful (my opinion, of course, others may disagree). I'll be happy to reverse that if it becomes so.
paxdiablo
I'm with Pax.
Graeme Perrow
@Pax: I think the best thing is if you post what you wrote in the edit as a new answer. Obviously it's then in competition with your first answer as well as this one, but that's just all the more upvotes for you ;-)
Steve Jessop
All in all, i am in for full fledged no-external-link answers in SO. But, i appreciate and practice giving credit and traffic to the authors of already written good-external articles. IMHO as always.
Konstantinos
@Konstantinos, I might have been unclear in my comment. I don't mind links (especially for attribution), it's answers that are *only* links that I'm not that fond of.
paxdiablo
+3  A: 

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;
}
Greg Hewgill
A: 

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
Brian R. Bondy
A: 

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);
}
yjerem
+7  A: 

You can do it recursively as follows (beware INT_MIN, 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 MIN_INT).
  • 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.

paxdiablo
+1 for a recursive implementation! Well tought!
Vargas
+1, very sweet indeed
Johannes Schaub - litb
I think this should rather be solved iteratively, as the problem is more naturally iterative ("seperate every third digit") than recursive ("seperate the third digit from the rest, then repeat this on the rest").
Joren
Suggested fix for MIN_INT: change printfcomma2 to take an unsigned int. That's it. Not very much "extra code" :-)
Steve Jessop
@Joren: I have added an iterative solution, and to some extent it shows why the recursive solution has merit. Although in many cases avoidance of recursion is a coding standards issue.
Clifford
A: 

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.

Clifford
A: 

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);
  }
}
Johannes Schaub - litb
I am intrigued by the expression used to determine the dimension of the array!? Is there at mathematical justification for that?
Clifford
ld(10) bits for each decimal digit. Round down to 3. we could divide 3 again (to account for the fact that we store up to 3 digit at once). But i wanted to keep it at an upper limit.
Johannes Schaub - litb