Як відформатувати число від 1123456789 до 1 123 456 789 в C?


83

Як я можу в мові C відформатувати число від 1123456789до 1,123,456,789? Я намагався використовувати, printf("%'10d\n", 1123456789);але це не працює.

Чи можете ви щось порадити? Чим простіше рішення, тим краще.


1
Просто FYI: прапор "роздільник тисяч" для printf()сімейства відформатованих функцій вводу-виводу (символ із одинарними лапками: ') - це нестандартний прапор, який підтримується лише в декількох реалізаціях бібліотеки. Шкода, що це не стандартно.
Michael Burr

1
Це залежить від мови. Згідно з робочою сторінкою Linux , це дивиться LC_NUMERIC. Однак я не знаю, яка мова підтримує це.
Joey Adams

1
@Joey, встановлення локальної установки LC_NUMERICдля поточного ""робить 'роботу на моєму Mac і на машині Linux, яку я щойно перевірив.
Carl Norum,

Зверніть увагу, що версії printf()сімейства функцій POSIX 2008 (2013) стандартизують використання 'символу (одинарна лапка або апостроф) із специфікаціями перетворення десяткового форматування чисел, щоб вказати, що число має бути відформатоване з тисячою роздільників.
Джонатан Леффлер

2
Також зауважте, що за замовчуванням "C"мовний розділ немонетарного роздільника тисяч не визначений, тому "%'d"в "C"локалі не буде виділятися комами . Вам потрібно встановити локаль із відповідним негрошовим роздільником тисяч. Часто це setlocale(LC_ALL, "");буде робити - інші значення для імені мови (крім порожнього рядка) визначаються реалізацією.
Джонатан Леффлер

Відповіді:


83

Якщо ваш printf підтримує 'прапор (як вимагає POSIX 2008 printf()), ви, можливо, можете це зробити, просто встановивши свою локаль належним чином. Приклад:

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

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

І побудувати та запустити:

$ ./example 
1,123,456,789

Перевірено на Mac OS X та Linux (Ubuntu 10.10).


1
Я перевірив це на sprintf()вбудованій системі, і це не працює (очевидно, тому що, як ви кажете, він не підтримуватиме "прапор".
gbmhunter

Я впевнений, що ви можете знайти бібліотеку C, яка б підтримувала її без зайвих проблем.
Карл Норум

Я швидко переглянув, не знайшов нічого підходящого і реалізував власну, використовуючи деякі з наведених вище ідей. Було б чудово знайти справжню бібліотеку, щоб ви могли використовувати її на поплавках та рядках з десятковою комою.
gbmhunter

1
Вбудована система FWIW AtmelStudio printf () трагічно не підтримує 'модифікатор. З заголовка: Copyright ... 2007 Joerg Wunsch ... 1993 Regents of the University of Californiaтобто похідне BSD.
Bob Stein

2
Хоча це зручно - вам не обов'язково потрібно змінювати стан для цієї функціональності (setlocale).
ideaman42,

46

Ви можете зробити це рекурсивно наступним чином (будьте обережні, INT_MINякщо ви використовуєте доповнення двох, вам знадобиться додатковий код для управління цим):

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

Короткий зміст:

  • Виклики користувача printfcommaз цілим числом, особливий випадок від’ємних чисел обробляється простим друком «-» і введенням позитивного числа (це біт, з яким не працюватиме INT_MIN).
  • Коли ви введете printfcomma2, число менше 1000 просто надрукується і повернеться.
  • В іншому випадку рекурсія буде викликана на наступному рівні вгору (так 1 234 567 буде викликано з 1234, потім 1), поки не буде знайдено число менше 1000.
  • Потім це число буде надруковано, і ми повернемося вгору по дереву рекурсії, друкуючи кому і наступне число.

Існує також більш стисла версія, хоча вона виконує непотрібну обробку під час перевірки від’ємних чисел на кожному рівні (не те, що це матиме значення з огляду на обмежену кількість рівнів рекурсії). Це повна програма для тестування:

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

і результат:

-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

Ітераційне рішення для тих, хто не довіряє рекурсії (хоча єдиною проблемою з рекурсією є, як правило, простір стека, яке тут не буде проблемою, оскільки воно буде глибиною лише на кілька рівнів, навіть для 64-розрядного цілого числа):

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

Обидва вони генерують 2,147,483,647для INT_MAX.


Я думаю, що це, швидше, слід вирішувати ітеративно, оскільки проблема є більш природно ітеративною ("відокремлювати кожну третю цифру"), ніж рекурсивною ("відокремити третю цифру від решти, а потім повторити це для решти").
Йорен

Запропоноване виправлення для MIN_INT: змініть printfcomma2 на непідписаний int. Це воно. Не дуже багато "зайвого коду" :-)
Стів Джессоп,

@Joren: Я додав ітераційне рішення, і певною мірою воно показує, чому рекурсивне рішення має переваги. Хоча в багатьох випадках уникнення рекурсії є питанням стандартів кодування.
Кліффорд,

@Steve: Просто змінюючи тип аргументу не виправити , тому що UB був викликаний , як тільки ви заперечувати nв printfcomma. Вам потрібно змусити перетворення перетворити на непідписане, перш ніж заперечити його.
R .. GitHub СТОП ДОПОМОГАЙ ЛЕД

1
@ Нехале, це не починається спочатку в тому сенсі, що втрачено весь поточний прогрес. Він називає себе рекурсивно , а потім повертається до наступної інструкції, то printf.
paxdiablo

11

Ось дуже проста реалізація. Ця функція не містить перевірки помилок. Розмір буфера повинен перевіряти абонент. Це також не працює для від’ємних чисел. Такі вдосконалення залишаються вправою для читача.

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

Мені подобається цей, він використовує sprintf замість printf, що корисно для вбудованих систем.
gbmhunter

1
Цілком приємно, але з необхідними незначними допрацюваннями для роботи з негативними числами.
ideaman42

(Модифікована версія для негативного числа підтримки stackoverflow.com/a/24795133/432509 )
ideasman42

5

Егади! Я роблю це постійно, використовуючи gcc / g ++ та glibc на linux, і так, оператор 'може бути нестандартним, але мені подобається його простота.

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

int main()
{
    int bignum=12345678;

    setlocale(LC_ALL,"");

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

    return 0;
}

Дає результат:

Велика кількість: 12 345 678

Просто запам’ятайте виклик “setlocale” там, інакше він нічого не відформатує.


2
На жаль, це, здається, не працює в Windows / gcc 4.9.2.
rdtsc

Ну Драт! Я б вважав, що gcc на будь-якій платформі дасть подібні результати незалежно від ОС. Приємно це знати, я гадаю, дивуйся, чому. Хммммм .....
lornix

Зверніть увагу, що якщо використовувана бібліотека C не підтримує 'прапор, то ви не отримаєте бажаного результату - і це не залежить від компілятора. Компілятор забезпечує, щоб функція бібліотеки printf()викликалася за допомогою рядка формату; функція бібліотеки залежить від її інтерпретації. У Windows цілком можливо, що бібліотека ЕПТ не надає потрібної вам підтримки - і не має значення, який компілятор ви використовуєте.
Джонатан Леффлер,

3

Можливо, цікавою є версія, яка відповідає локалі.

#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

У цьому є помилка (але та, яку я вважав би досить незначною). На апаратному забезпеченні двох він не перетворить найбільш негативне число правильно, тому що намагається перетворити від’ємне число на його еквівалентне додатне число за N = -N;допомогою Доповнення двох, максимально від’ємне число не має відповідного додатного числа, якщо ви не просувати його до більшого типу. Одним із способів обійти цю проблему є просування числа відповідного типу без підпису (але це дещо нетривіально).


Я задав питання , спрямований більше до поперечного реалізації платформи в форматі '-flag тут: stackoverflow.com/q/44523855/2642059 Я думаю , що ця відповідь зовсім адресу , що робить більш тестування. Якщо так, то, мабуть, я мав би позначити це запитання як обману?
Джонатан Мі

Добре, перше, що я впізнав, він не коригується, як налаштовується локаль. Навіщо підтримувати, tsep, place_strі neg_strвзагалі? Чому б не просто безпосередньо використовувати fmt_infoучасників?
Джонатан Мі

Добре, цифра номер 2, цей код не може обробляти від’ємні числа ... і я точно не знаю, як це могло, while (*ptr-- = *neg_str++)для мене не має особливого сенсу. Ви вставляєте мінус-символи рядка у зворотному порядку.
Джонатан Мі

Отже ... Я усунув витік пам’яті та виправив помилку від’ємними числами: ideone.com/gTv8Z4 На жаль, досі існує проблема з кількома символами-роздільниками або декількома символами негативних символів, які записуються в рядок назад. Я спробую розв’язати це наступне ...
Джонатан Мі

@JonathanMee: Я оновив код (і додав принаймні ще кілька тестових кейсів, включаючи негативні числа).
Джеррі Коффін,

2

Без рекурсії та обробки рядків математичний підхід:

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

В принципі схоже на рекурсивне рішення Пакса, але заздалегідь обчислюючи порядок величини, рекурсії вдається уникнути (можливо, з деякими значними витратами).

Зауважте також, що фактичний символ, що використовується для розділення тисяч, залежить від мови.

Редагувати : Див. Коментарі @ Chux нижче для вдосконалення.


1
Зміна, abs(n)щоб fabs(n)запобігти помилці комплімента 2 при виконанні print_number(INT_MIN).
chux

@chux: Хороший момент, але у виразі% LHS буде повернуто до int, і він все одно буде порушений. Можливо, простіше просто прийняти незначно менший діапазон допустимого введення або додати тест і вивід "-2,147,483,647" безпосередньо для INT_MIN (або що завгодно є INT_MIN на відповідній платформі - в цьому ще одна банка хробаків.
Кліффорд,

Я тестував його успішно, перш ніж запропонувати. Мда. Я бачу, моя ідея була призначена лише для, log10(abs(n))а не в іншому місці. Цікаво, що ваше рішення працює з єдиною зміною в log10(fabs(n))і print_number(INT_MIN)через printf(..., abs(n / order_of_magnitude))яку засіб n = abs(INT_MIN) % order_of_magnitudeнегативні КІ. Якщо ми відмовимося від INT_MIN, це printf(..., abs(n / order_of_magnitude))може стати printf(..., n / order_of_magnitude). Але я вважаю, що робота з цим хробаком, який називається "abs (INT_MIN)", як правило, погана .
chux

Нова думка: запропонувати 3 зміни log10(fabs(n)), n = abs(n% order_of_magnitude)і printf(",%03d", n/order_of_magnitude). BTW: Я б не витрачав на це зусилля, якщо не вважав, що ваше рішення є добрим. Немає UB, навіть для INT_MIN.
chux

2

Засновано на @Greg Hewgill, але враховує від’ємні числа та повертає розмір рядка.

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

Моя відповідь не форматує результат точно так, як це показано на ілюстрації у запитанні, але в деяких випадках може задовольнити фактичну потребу за допомогою простого однокласника чи макросу. Можна розширити його, щоб створити більше тисяч груп за необхідності.

Результат буде виглядати, наприклад, наступним чином:

Value: 0'000'012'345

Кодекс:

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

Чи 'еквівалентно стандартне позначення ,(принаймні математично) в певних частинах світу?
ysap

1
@ysap Це тисячовідділювач у деяких частинах світу.
Роланд

0

Немає реального простого способу зробити це в C. Я б просто змінив функцію int-to-string, щоб зробити це:

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

Ще одна ітераційна функція

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

Мене зацікавив вираз, що використовується для визначення розмірності масиву !? Чи існує це математичне обґрунтування?
Кліффорд,

ld (10) біт для кожної десяткової цифри. Округлити до 3. ми могли б знову розділити 3 (зважаючи на те, що ми зберігаємо до 3 цифр одночасно). Але я хотів тримати його на верхній межі.
Йоханнес Шауб - літб

0

Ось найтонша, ефективна за розмірами та швидкістю реалізація такого форматування десяткових цифр:

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

Використовуйте наступне:

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

Вихід:

test : +1,234,567,890.

Деякі переваги:

  • Функція, яка бере кінець буфера рядка через зворотне впорядковане форматування. Нарешті, де немає потреби в скасуванні сформованого рядка (strrev).

  • Ця функція створює один рядок, який можна використовувати в будь-якому алгоритмі після. Це не залежить і не вимагає багаторазових викликів printf / sprintf, що є жахливим повільним і завжди залежить від контексту.

  • Мінімальна кількість операторів розділення (/,%).

Що це таке unlikely?
Ден Бешард,

1
@Dan: unlikelyймовірно, натяк оптимізатору на те, що умова навряд чи буде правдою. Для отримання додаткової інформації дивіться likely()/ unlikely()макроси в ядрі Linux .
Джонатан Леффлер

@JonathanLeffler О, га. Дякую за посилання.
Ден Бешард

0

Захищений формат_ком, із від’ємними числами:

Оскільки VS <2015 не реалізує snprintf, вам потрібно це зробити

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

І потім

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

Приклад використання:

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

Модифікована версія рішення @paxdiablo, але з використанням WCHARі 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);
}

0

Я новачок у програмуванні на мові C. Ось мій простий код.

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

Моє рішення використовує. замість a, читачеві залишається змінити це.


0

Це старий варіант, на який є багато відповідей, але питання полягало не в тому, "як я можу написати процедуру додавання коми", а "як це можна зробити на C"? Коментарі вказували на цей напрямок, але в моїй системі Linux з GCC це працює для мене:

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

Коли це запускається, я отримую:

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

Якщо я зняв LC_ALLзмінну перед запуском програми, unsetenvце не потрібно.


0

Потрібно було зробити щось подібне самому, але замість того, щоб друкувати безпосередньо, потрібно було перейти до буфера. Ось що я придумав. Працює назад.

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

Майте на увазі, що він призначений лише для цілих чисел без знака, і ви повинні переконатися, що буфер є достатньо великим.


0

Ще одне рішення - збереження результату в intмасив, максимальний розмір 7, оскільки long long intтип може обробляти числа в діапазоні від 9 223 372 076 854 775 807 до -9 223 372 036 854 775 807 . (Зверніть увагу, що це не беззнакове значення).

Функція нерекурсивного друку

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

виклик основної функції

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
}

вихід тестування

-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

У функції main ():

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

Якщо друк - це все, що потрібно, перейдіть int numberSeparated[8];всередину функції getNumWcommasта назвіть це так getNumWcommas(number).


-1

Це можна зробити досить просто ...

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

Приклад виклику:

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
Принаймні використовуйте належні відступи під час розміщення коду. Також, можливо, додайте пояснення щодо того, що це робить, а існуючі відповіді ще не роблять.
EWit

Це має перевагу простоти і легко зрозуміти з першого погляду.
Стів Ньюман

1
Підроблене рішення, друкує додатковий ,номер для наведених нижче цифр 100, використовує printf()куди putchar()літати, використовує оманливі імена, хаотичний відступ та занадто багато коду.
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
Цей код має безліч проблем. Невикористана змінна idxможе піти. Код нічого не дає для 0. Він не обробляє від’ємні числа. Там немає очевидної причини , щоб bufferу staticзмінному (вона обмежує реєнтерабельним коду). Немає пояснення того, що він робить, або згадується, що після завершення коду рядок, на який вказує, pмістить відформатований рядок. Найменш серйозна проблема полягає в тому, що він використовує порожнє замість коми як роздільник тисяч. Той факт, що він не справляється з нулем, є проблемою вбивці.
Джонатан Леффлер
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.