Làm thế nào để định dạng một số từ 1123456789 đến 1,123,456,789 trong C?


83

Làm thế nào tôi có thể ở định dạng ngôn ngữ C một số từ 1123456789đến 1,123,456,789? Tôi đã thử sử dụng printf("%'10d\n", 1123456789);nhưng điều đó không hoạt động.

Bạn có thể tư vấn bất cứ điều gì? Giải pháp càng đơn giản càng tốt.


1
Chỉ là FYI: cờ 'dấu phân cách hàng nghìn' cho nhóm printf()hàm IO được định dạng (ký tự dấu nháy đơn: ') là cờ không chuẩn chỉ được hỗ trợ trong một số triển khai thư viện. Thật tệ là nó không chuẩn.
Michael Burr

1
Nó phụ thuộc vào ngôn ngữ. Theo trang người dùng Linux , nó có vẻ LC_NUMERIC. Tuy nhiên, tôi không biết ngôn ngữ nào hỗ trợ điều này.
Joey Adams

1
@Joey, cài đặt LC_NUMERICngôn ngữ thành hiện tại sẽ ""làm cho 'hoạt động trên máy Mac của tôi và trên máy linux mà tôi vừa kiểm tra.
Carl Norum

Lưu ý rằng phiên bản POSIX 2008 (2013) của printf()họ hàm tiêu chuẩn hóa việc sử dụng 'ký tự (dấu nháy đơn hoặc dấu nháy đơn) với đặc điểm kỹ thuật chuyển đổi định dạng số thập phân để chỉ định rằng số phải được định dạng bằng dấu phân cách hàng nghìn.
Jonathan Leffler

2
Cũng lưu ý rằng trong "C"ngôn ngữ mặc định , dấu phân tách hàng nghìn phi tiền tệ không được xác định, do đó, "%'d"dấu phẩy sẽ không tạo ra dấu phẩy trong "C"ngôn ngữ. Bạn cần đặt ngôn ngữ với dấu phân tách nghìn không phải tiền tệ thích hợp. Thông thường, setlocale(LC_ALL, "");sẽ thực hiện công việc - các giá trị khác cho tên miền (ngoài chuỗi trống) được xác định thực thi.
Jonathan Leffler

Câu trả lời:


83

Nếu printf của bạn hỗ trợ 'cờ (theo yêu cầu của POSIX 2008 printf()), bạn có thể làm điều đó chỉ bằng cách đặt ngôn ngữ của mình một cách thích hợp. Thí dụ:

#include <stdio.h>
#include <locale.h>

int main(void)
{
    setlocale(LC_NUMERIC, "");
    printf("%'d\n", 1123456789);
    return 0;
}

Và xây dựng và chạy:

$ ./example 
1,123,456,789

Đã thử nghiệm trên Mac OS X & Linux (Ubuntu 10.10).


1
Tôi đã thử nghiệm điều này sprintf()trong một hệ thống nhúng và nó không hoạt động (rõ ràng, vì như bạn nói, nó sẽ không hỗ trợ 'cờ.
gbmhunter

Tôi chắc rằng bạn có thể tìm thấy một thư viện C hỗ trợ nó mà không gặp quá nhiều khó khăn.
Carl Norum

Tôi đã xem xét nhanh, không tìm thấy bất kỳ điều gì phù hợp, và thực hiện của riêng tôi bằng cách sử dụng một số ý tưởng ở trên. Sẽ thật tuyệt nếu bạn tìm thấy một thư viện thực tế, để bạn có thể sử dụng nó trên phao và chuỗi có chữ số thập phân.
gbmhunter

1
Hệ thống nhúng của FWIW AtmelStudio printf () có vẻ như không hỗ trợ công cụ 'sửa đổi. Từ tiêu đề: Copyright ... 2007 Joerg Wunsch ... 1993 Regents of the University of Californiatức là một dẫn xuất BSD.
Bob Stein

2
Mặc dù điều này rất tiện lợi - bạn không nhất thiết phải thay đổi trạng thái cho chức năng này (setlocale).
ideaman42.

46

Bạn có thể làm điều đó một cách đệ quy như sau (hãy cẩn thận INT_MINnếu bạn đang sử dụng phần bổ sung của hai, bạn sẽ cần thêm mã để quản lý điều đó):

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);
}

Một bản tóm tắt:

  • Người dùng gọi printfcommavới một số nguyên, trường hợp đặc biệt của số âm được xử lý bằng cách chỉ cần in "-" và tạo số dương (đây là bit sẽ không hoạt động với INT_MIN).
  • Khi bạn nhập printfcomma2, một số nhỏ hơn 1.000 sẽ chỉ in và trả lại.
  • Nếu không thì đệ quy sẽ được gọi ở cấp độ tiếp theo (vì vậy 1.234.567 sẽ được gọi với 1.234, sau đó là 1) cho đến khi một số nhỏ hơn 1.000 được tìm thấy.
  • Sau đó, số đó sẽ được in và chúng ta sẽ đi ngược lại cây đệ quy, in dấu phẩy và số tiếp theo khi chúng ta tiếp tục.

Ngoài ra còn có phiên bản ngắn gọn hơn mặc dù nó xử lý không cần thiết trong việc kiểm tra các số âm ở mọi cấp (không phải là điều này sẽ quan trọng với số lượng giới hạn của cấp đệ quy). Đây là một chương trình hoàn chỉnh để thử nghiệm:

#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;
}

và đầu ra là:

-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

Một giải pháp lặp lại cho những người không tin tưởng đệ quy (mặc dù vấn đề duy nhất với đệ quy có xu hướng là không gian ngăn xếp sẽ không phải là vấn đề ở đây vì nó sẽ chỉ sâu một vài cấp ngay cả đối với số nguyên 64 bit):

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);
    }
}

Cả hai đều tạo ra 2,147,483,647cho INT_MAX.


Tôi nghĩ rằng điều này nên được giải quyết theo cách lặp đi lặp lại, vì vấn đề là lặp lại tự nhiên hơn ("tách riêng từng chữ số thứ ba") hơn là đệ quy ("tách chữ số thứ ba khỏi phần còn lại, sau đó lặp lại điều này trên phần còn lại").
Joren 20/09/09

Bản sửa lỗi được đề xuất cho MIN_INT: thay đổi printfcomma2 để lấy một int không dấu. Đó là nó. Không có nhiều "mã bổ sung" :-)
Steve Jessop 20/09/09

@Joren: Tôi đã thêm một giải pháp lặp lại và ở một mức độ nào đó, nó cho thấy lý do tại sao giải pháp đệ quy có giá trị. Mặc dù trong nhiều trường hợp, việc tránh đệ quy là một vấn đề tiêu chuẩn mã hóa.
Clifford vào

@Steve: Chỉ cần thay đổi kiểu lập luận không sửa chữa nó vì UB đã được gọi ngay sau khi bạn phủ nhận ntrong printfcomma. Bạn cần buộc chuyển đổi thành không dấu trước khi phủ định nó.
R .. GitHub DỪNG TRỢ GIÚP LÚC NỮA,

1
@Nehal, nó không bắt đầu lại theo nghĩa là tất cả tiến trình hiện tại bị mất. Nó gọi chính nó một cách đệ quy và sau đó quay trở lại câu lệnh tiếp theo printf,.
paxdiablo

11

Đây là một cách thực hiện rất đơn giản. Chức năng này không chứa kiểm tra lỗi, kích thước bộ đệm phải được xác nhận bởi người gọi. Nó cũng không hoạt động đối với số âm. Những cải tiến như vậy để lại như một bài tập cho người đọc.

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;
}

Tôi thích cái này, nó sử dụng sprintf thay vì printf, rất hữu ích cho các hệ thống nhúng.
gbmhunter

1
Khá đẹp, nhưng cần một số chỉnh sửa nhỏ để hoạt động đối với các số âm.
ideaman42

(phiên bản đã sửa đổi để hỗ trợ số âm stackoverflow.com/a/24795133/432509 )
ideasman42

5

Egads! Tôi làm điều này mọi lúc, sử dụng gcc / g ++ và glibc trên linux và vâng, toán tử 'có thể không chuẩn, nhưng tôi thích sự đơn giản của nó.

#include <stdio.h>
#include <locale.h>

int main()
{
    int bignum=12345678;

    setlocale(LC_ALL,"");

    printf("Big number: %'d\n",bignum);

    return 0;
}

Cung cấp đầu ra của:

Con số lớn: 12.345.678

Chỉ cần nhớ lệnh gọi 'setlocale' trong đó, nếu không nó sẽ không định dạng bất kỳ thứ gì.


2
Đáng buồn thay, điều này dường như không hoạt động trong Windows / gcc 4.9.2.
rdtsc

Chà Drat! Tôi đã nhận ra rằng gcc trên bất kỳ nền tảng nào sẽ cho kết quả tương tự bất kể hệ điều hành nào. Thật tốt khi biết rằng tôi cho rằng, hãy tự hỏi tại sao.
Hmmmmm

Lưu ý rằng nếu thư viện C đang sử dụng không hỗ trợ 'cờ, thì bạn sẽ không nhận được đầu ra mong muốn - và điều đó độc lập với trình biên dịch. Trình biên dịch đảm bảo hàm thư viện cho printf()được gọi với chuỗi định dạng; nó phụ thuộc vào chức năng thư viện để giải thích nó. Trên Windows, hoàn toàn có thể là thư viện CRT không cung cấp hỗ trợ bạn cần - và vấn đề không quan trọng là bạn sử dụng trình biên dịch nào.
Jonathan Leffler

3

Có lẽ một phiên bản nhận biết ngôn ngữ sẽ rất thú vị.

#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

Điều này không có một lỗi (nhưng một trong những tôi sẽ coi là khá nhỏ). Trên phần cứng bổ sung của Two, nó sẽ không chuyển đổi số âm nhất một cách chính xác, bởi vì nó cố gắng chuyển đổi một số âm thành số dương tương đương của nó với N = -N;phần bù của Hai, số âm cực đại không có số dương tương ứng, trừ khi bạn quảng bá nó lên một loại lớn hơn. Một cách để giải quyết vấn đề này là quảng bá số thành kiểu không dấu tương ứng (nhưng nó hơi không tầm thường).


Tôi đã hỏi một câu hỏi hướng nhiều hơn đến việc triển khai nền tảng chéo của định dạng '-flag tại đây: stackoverflow.com/q/44523855/2642059 Tôi nghĩ câu trả lời này giải quyết hoàn hảo vấn đề đó, hiện đang thực hiện thêm thử nghiệm. Nếu vậy tôi đoán tôi nên đánh dấu câu hỏi đó là một bản dupe hả?
Jonathan Mee

OK, điều đầu tiên tôi đã nhận ra, nó không điều chỉnh khi ngôn ngữ điều chỉnh. Tại sao duy trì, tsep, place_str, và neg_strở tất cả? Tại sao không chỉ sử dụng trực tiếp fmt_infocác thành viên của?
Jonathan Mee

Được rồi, số thứ 2, mã này không thể xử lý các số âm ... và tôi không biết chính xác nó có thể như thế nào, while (*ptr-- = *neg_str++)không có ý nghĩa gì đối với tôi. Bạn đang chèn các ký tự chuỗi phủ định theo thứ tự ngược lại.
Jonathan Mee

Vì vậy, ... Tôi đã loại bỏ lỗi rò rỉ bộ nhớ và sửa lỗi với số âm: ideone.com/gTv8Z4 Rất tiếc vẫn có sự cố với nhiều dấu phân tách ký tự hoặc nhiều ký hiệu âm nhiều ký tự được ghi ngược vào chuỗi. Tôi sẽ cố gắng để giải quyết đó ở bên cạnh ...
Jonathan Mee

@JonathanMee: Tôi đã cập nhật mã (và thêm ít nhất một vài trường hợp thử nghiệm nữa, bao gồm cả số âm).
Jerry Coffin

2

Không cần đệ quy hoặc xử lý chuỗi, một cách tiếp cận toán học:

#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) ) ;
    }
}

Về nguyên tắc tương tự như giải pháp đệ quy của Pax, nhưng bằng cách tính toán thứ tự độ lớn trước, đệ quy sẽ tránh được (có lẽ với một số chi phí đáng kể).

Cũng lưu ý rằng ký tự thực tế được sử dụng để phân tách hàng nghìn là đặc trưng theo ngôn ngữ.

Chỉnh sửa : Xem nhận xét của @ Chux bên dưới để cải thiện.


1
Thay đổi abs(n)để fabs(n)tránh lỗi khen của 2 khi biểu diễn print_number(INT_MIN).
chux - Phục hồi Monica

@chux: Điểm tốt, nhưng trong biểu thức%, LHS sẽ được chuyển trở lại int và nó vẫn sẽ bị hỏng. Có lẽ đơn giản hơn là chỉ cần chấp nhận phạm vi đầu vào có thể chấp nhận được nhỏ hơn một chút hoặc thêm kiểm tra và đầu ra "-2,147,483,647" trực tiếp cho INT_MIN (hoặc bất kỳ INT_MIN nào trên nền tảng được đề cập - trong đó có một hộp sâu khác.
Clifford

Tôi đã thử nghiệm nó thành công trước khi đề xuất. Hừ! Tôi thấy ý tưởng của tôi chỉ có ý nghĩa với log10(abs(n))chứ không phải nơi nào khác. Thật thú vị, giải pháp của bạn hoạt động với một thay đổi duy nhất đối với log10(fabs(n))print_number(INT_MIN)printf(..., abs(n / order_of_magnitude))điều đó có nghĩa n = abs(INT_MIN) % order_of_magnitudelà tiêu cực là OK. Nếu chúng tôi từ bỏ INT_MIN, printf(..., abs(n / order_of_magnitude))có thể trở thành printf(..., n / order_of_magnitude). Nhưng tôi cho rằng làm việc với con sâu có tên "abs (INT_MIN)" đó thường là một điều tồi tệ .
Chux - Khôi phục Monica

Suy nghĩ mới: đề xuất 3 thay đổi log10(fabs(n)), n = abs(n% order_of_magnitude)printf(",%03d", n/order_of_magnitude). BTW: Tôi sẽ không tốn công sức này trừ khi tôi nghĩ rằng giải pháp của bạn là tốt. Không có UB, ngay cả đối với INT_MIN.
Chux - Khôi phục Monica

2

Dựa trên @Greg Hewgill's, nhưng tính đến số âm và trả về kích thước chuỗi.

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);
}

1

Câu trả lời của tôi không định dạng kết quả chính xác như hình minh họa trong câu hỏi, nhưng có thể đáp ứng nhu cầu thực tế trong một số trường hợp với một chữ lót hoặc macro đơn giản. Người ta có thể mở rộng nó để tạo thêm nghìn nhóm nếu cần.

Kết quả sẽ như sau:

Value: 0'000'012'345

Mật mã:

printf("Value: %llu'%03lu'%03lu'%03lu\n", (value / 1000 / 1000 / 1000), (value / 1000 / 1000) % 1000, (value / 1000) % 1000, value % 1000);

'một ký hiệu tương đương tiêu chuẩn để một ,(về mặt toán học, ít nhất) trong một số phần (s) của thế giới?
ysap

1
@ysap Nó là một phần nghìn phân cách ở một số nơi trên thế giới.
Roland Pihlakas

0

Không có cách thực sự đơn giản nào để làm điều này trong C. Tôi chỉ cần sửa đổi một hàm int-to-string để làm điều đó:

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);
}

0

Một hàm lặp khác

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);
  }
}

Tôi bị hấp dẫn bởi biểu thức được sử dụng để xác định kích thước của mảng !? Có lý do toán học nào cho điều đó không?
Clifford, 20/09/09

ld (10) bit cho mỗi chữ số thập phân. Làm tròn xuống 3. chúng ta có thể chia 3 một lần nữa (để giải thích rằng chúng ta lưu trữ đến 3 chữ số cùng một lúc). Nhưng tôi muốn giữ nó ở giới hạn trên.
Johannes Schaub - litb 20/09/09

0

Đây là cách triển khai hiệu quả về kích thước và tốc độ nhỏ nhất của loại định dạng chữ số thập phân này:

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;
}

Sử dụng như sau:

char buffer[16];
fprintf (stderr, "test : %s.", formatNumber (1234567890, buffer + 16, true));

Đầu ra:

test : +1,234,567,890.

Một số ưu điểm:

  • Hàm chiếm cuối bộ đệm chuỗi vì định dạng có thứ tự ngược lại. Cuối cùng, không cần cung cấp lại chuỗi được tạo (strrev).

  • Hàm này tạo ra một chuỗi có thể được sử dụng trong bất kỳ bí danh nào sau đó. Nó không phụ thuộc cũng như không yêu cầu nhiều cuộc gọi printf / sprintf, điều này rất chậm và luôn theo ngữ cảnh cụ thể.

  • Số lượng toán tử chia tối thiểu (/,%).

unlikelygì?
Dan Bechard

1
@Dan: unlikelycó thể là một gợi ý cho trình tối ưu hóa rằng điều kiện không chắc là đúng. Xem likely()/ unlikely()macro trong nhân Linux để biết thêm thông tin.
Jonathan Leffler

@JonathanLeffler Ồ, hả. Cảm ơn các liên kết.
Dan Bechard

0

An toàn format_commas, với số âm:

Vì VS <2015 không triển khai snprintf nên bạn cần thực hiện việc này

#if defined(_WIN32)
    #define snprintf(buf,len, format,...) _snprintf_s(buf, len,len, format, __VA_ARGS__)
#endif

Và sau đó

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;
}

Ví dụ sử dụng:

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);

0

Một phiên bản sửa đổi của giải pháp @paxdiablo, nhưng sử dụng WCHARwsprinf:

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);
}

0

Tôi mới học lập trình C. Đây là mã đơn giản của tôi.

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;
}

0
#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 ...
}

Giải pháp của tôi sử dụng a. thay vì a, Người đọc phải thay đổi điều này.


0

Câu này đã cũ và có rất nhiều câu trả lời nhưng câu hỏi không phải là "làm thế nào tôi có thể viết một thói quen để thêm dấu phẩy" mà là "làm thế nào nó có thể được thực hiện trong C"? Các nhận xét chỉ ra hướng này nhưng trên hệ thống Linux của tôi với GCC, điều này phù hợp với tôi:

#include <stdio.h>
#include <stdlib.h>
#include <locale.h>
int main()
{
    unsetenv("LC_ALL");
    setlocale(LC_NUMERIC, "");
    printf("%'lld\n", 3141592653589);
}

Khi điều này được chạy, tôi nhận được:

$ cc -g comma.c -o comma && ./comma
3,141,592,653,589

Nếu tôi bỏ đặt LC_ALLbiến trước khi chạy chương trình unsetenvthì không cần thiết.


0

Cần thiết để tự mình làm điều gì đó tương tự nhưng thay vì in trực tiếp, cần phải chuyển đến bộ đệm. Đây là những gì tôi nghĩ ra. Hoạt động ngược.

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;
}

Lưu ý rằng nó chỉ được thiết kế cho các số nguyên không dấu và bạn phải đảm bảo rằng bộ đệm đủ lớn.


0

Một giải pháp khác, bằng cách lưu kết quả vào một intmảng, kích thước tối đa là 7 vì long long intkiểu có thể xử lý các số trong phạm vi 9.223.372.036.854.775.807 đến -9.223.372.036.854.775.807 . (Lưu ý nó không phải là giá trị không dấu).

Chức năng in không đệ quy

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]);
            }
        }
    }
}

cuộc gọi chức năng chính

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
}

kiểm tra đầu ra

-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

Trong hàm main ():

int numberSeparated[8];
long long int number = 1234567890LL;
getNumWcommas(number, numberSeparated);

Nếu in là tất cả những gì cần thiết thì hãy chuyển int numberSeparated[8];vào bên trong hàm getNumWcommasvà gọi nó theo cách này getNumWcommas(number).


-1

Có thể được thực hiện khá dễ dàng ...

//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';
}

Cuộc gọi ví dụ:

char szBuffer[512];
pretty_number("1234567", szBuffer);
//strcmp(szBuffer, "1,234,567") == 0

-1
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(",");
           }

}

1
Ít nhất hãy sử dụng thụt lề thích hợp khi đăng mã. Cũng có thể thêm một số giải thích về điều này làm gì mà các câu trả lời hiện có chưa làm được.
EWit

Điều này có đức tính đơn giản và dễ dàng hiểu được trong nháy mắt.
steve newman

1
Giải pháp Bogus, in thêm ,cho các số bên dưới 100, sử dụng printf()nơi putchar()sẽ bay, sử dụng tên gây hiểu lầm, thụt lề lộn xộn và quá nhiều mã.
chqrlie

-1
        // 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';
        }

1
Mã này có nhiều vấn đề. Biến không sử dụng idxcó thể biến mất. Mã không tạo ra bất kỳ thứ gì cho 0. Nó không xử lý các số âm. Không có lý do rõ ràng để tạo buffermột staticbiến (nó hạn chế sự xuất hiện gần đây của mã). Không có giải thích về những gì nó làm, hoặc đề cập rằng sau khi mã hoàn tất, chuỗi được trỏ đến pchứa chuỗi được định dạng. Vấn đề ít nghiêm trọng nhất là nó sử dụng khoảng trống thay vì dấu phẩy làm dấu phân cách hàng nghìn. Tuy nhiên, thực tế là nó không xử lý số 0 là vấn đề giết người.
Jonathan Leffler
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.