Wie formatiere ich eine Zahl von 1123456789 bis 1.123.456.789 in C?

83

Wie kann ich im C-Format eine Zahl von 1123456789bis formatieren 1,123,456,789? Ich habe es versucht, printf("%'10d\n", 1123456789);aber das funktioniert nicht.

Könnten Sie etwas raten? Je einfacher die Lösung, desto besser.

goe
quelle
1
Nur zu Ihrer Information: Das Flag 'Tausendertrennzeichen' für die printf()Familie der formatierten E / A-Funktionen (das einfache Anführungszeichen: ') ist ein nicht standardmäßiges Flag, das nur in einigen Bibliotheksimplementierungen unterstützt wird. Es ist schade, dass es nicht Standard ist.
Michael Burr
1
Es ist vom Gebietsschema abhängig. Laut der Linux-Manpage sieht es so aus LC_NUMERIC. Ich weiß jedoch nicht, welches Gebietsschema dies unterstützt.
Joey Adams
1
@Joey, die Einstellung der LC_NUMERIClocale auf den aktuellen ""macht die 'Arbeit auf meinem Mac und auf einer Linux - Maschine , die ich gerade überprüft.
Carl Norum
Beachten Sie, dass die POSIX 2008 (2013) -Versionen der printf()Funktionsfamilie die Verwendung des 'Zeichens (einfaches Anführungszeichen oder Apostroph) mit den Konvertierungsspezifikationen für die Dezimalzahlformatierung standardisieren, um anzugeben, dass die Zahl mit Tausenden von Trennzeichen formatiert werden soll.
Jonathan Leffler
2
Beachten Sie auch, dass im Standardgebietsschema "C"das nicht monetäre Tausendertrennzeichen undefiniert ist, sodass "%'d"im "C"Gebietsschema keine Kommas erzeugt werden . Sie müssen ein Gebietsschema mit einem geeigneten nicht monetären Tausendertrennzeichen festlegen. setlocale(LC_ALL, "");Wird oft die Arbeit erledigen - andere Werte für den Gebietsschemanamen (außer der leeren Zeichenfolge) sind implementierungsdefiniert.
Jonathan Leffler

Antworten:

82

Wenn Ihr printf das 'Flag unterstützt (wie von POSIX 2008 gefordert printf()), können Sie dies wahrscheinlich tun, indem Sie Ihr Gebietsschema entsprechend festlegen. Beispiel:

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

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

Und bauen & laufen lassen:

$ ./example 
1,123,456,789

Getestet unter Mac OS X & Linux (Ubuntu 10.10).

Carl Norum
quelle
1
Ich habe dies sprintf()in einem eingebetteten System getestet und es funktioniert nicht (offensichtlich, weil es, wie Sie sagen, die Flagge nicht unterstützt.
gbmhunter
Ich bin sicher, Sie können eine C-Bibliothek finden, die dies ohne allzu große Probleme unterstützt.
Carl Norum
Ich habe einen kurzen Blick darauf geworfen, nichts Passendes gefunden und meine eigenen mit einigen der oben genannten Ideen umgesetzt. Es wäre großartig, eine tatsächliche Bibliothek zu finden, damit Sie sie für Gleitkommazahlen und Zeichenfolgen mit Dezimalstellen verwenden können.
Gbmhunter
1
Das eingebettete System printf () von FWIW AtmelStudio scheint den Modifikator tragischerweise nicht zu unterstützen '. Aus dem Header: Copyright ... 2007 Joerg Wunsch ... 1993 Regents of the University of Californiadh eine BSD-Ableitung.
Bob Stein
2
Dies ist zwar praktisch, Sie möchten jedoch nicht unbedingt den Status für diese Funktionalität ändern (setlocale).
ideasman42
46

Sie können dies rekursiv wie folgt tun (Vorsicht, INT_MINwenn Sie das Zweierkomplement verwenden, benötigen Sie zusätzlichen Code, um dies zu verwalten):

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

Eine Zusammenfassung:

  • Benutzeranrufe printfcommamit einer Ganzzahl, der Sonderfall negativer Zahlen wird behandelt, indem einfach "-" gedruckt und die Zahl positiv gemacht wird (dies ist das Bit, mit dem nicht funktioniert INT_MIN).
  • Wenn Sie eingeben printfcomma2, wird eine Zahl unter 1.000 nur gedruckt und zurückgegeben.
  • Andernfalls wird die Rekursion auf der nächsthöheren Ebene aufgerufen (also werden 1.234.567 mit 1.234, dann 1 aufgerufen), bis eine Zahl unter 1.000 gefunden wird.
  • Dann wird diese Nummer gedruckt und wir gehen zurück zum Rekursionsbaum, drucken ein Komma und die nächste Nummer, während wir gehen.

Es gibt auch die prägnantere Version, obwohl sie auf jeder Ebene unnötig nach negativen Zahlen sucht (nicht, dass dies angesichts der begrenzten Anzahl von Rekursionsstufen von Bedeutung ist). Dies ist ein vollständiges Programm zum Testen:

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

und die Ausgabe ist:

-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

Eine iterative Lösung für diejenigen, die der Rekursion nicht vertrauen (obwohl das einzige Problem bei der Rekursion in der Regel der Stapelspeicher ist, der hier kein Problem darstellt, da er selbst für eine 64-Bit-Ganzzahl nur wenige Ebenen tief ist):

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

Beide erzeugen 2,147,483,647für INT_MAX.

paxdiablo
quelle
Ich denke, dies sollte eher iterativ gelöst werden, da das Problem natürlicher iterativ ("jede dritte Ziffer trennen") als rekursiv ist ("die dritte Ziffer vom Rest trennen, dann den Rest wiederholen").
Joren
Vorgeschlagene Korrektur für MIN_INT: Ändern Sie printfcomma2 in ein vorzeichenloses int. Das ist es. Nicht sehr viel "zusätzlicher Code" :-)
Steve Jessop
@Joren: Ich habe eine iterative Lösung hinzugefügt, und in gewissem Maße zeigt sie, warum die rekursive Lösung sinnvoll ist. Obwohl in vielen Fällen die Vermeidung von Rekursionen ein Problem der Codierungsstandards darstellt.
Clifford
@Steve: Nur die Änderung der Argumenttyp es nicht beheben , weil UB so schnell aufgerufen wurde , wie Sie negieren nin printfcomma. Sie müssen eine Konvertierung in unsigned erzwingen, bevor Sie sie negieren.
R .. GitHub STOP HELPING ICE
1
@Nehal, es startet nicht wieder in dem Sinne, dass alle aktuellen Fortschritte verloren gehen. Es ruft sich rekursiv auf und kehrt dann zur nächsten Anweisung zurück, der printf.
Paxdiablo
11

Hier ist eine sehr einfache Implementierung. Diese Funktion enthält keine Fehlerprüfung, Puffergrößen müssen vom Aufrufer überprüft werden. Es funktioniert auch nicht für negative Zahlen. Solche Verbesserungen bleiben dem Leser als Übung überlassen.

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
quelle
Ich mag dieses, es verwendet Sprintf anstelle von Printf, was für eingebettete Systeme nützlich ist.
Gbmhunter
1
Ganz nett, aber mit ein paar kleinen Änderungen, um für negative Zahlen zu arbeiten.
ideasman42
(modifizierte Version für die Unterstützung negativer Zahlen stackoverflow.com/a/24795133/432509 )
ideasman42
5

Egads! Ich mache das die ganze Zeit mit gcc / g ++ und glibc unter Linux und ja, der Operator 'ist vielleicht nicht Standard, aber ich mag die Einfachheit.

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

int main()
{
    int bignum=12345678;

    setlocale(LC_ALL,"");

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

    return 0;
}

Gibt Ausgabe von:

Große Zahl: 12.345.678

Sie müssen sich nur an den 'setlocale'-Aufruf erinnern, sonst wird nichts formatiert.

lornix
quelle
2
Leider scheint dies in Windows / gcc 4.9.2 nicht zu funktionieren.
rdtsc
Na Drat! Ich hätte gedacht, dass gcc auf jeder Plattform unabhängig vom Betriebssystem ähnliche Ergebnisse liefern würde. Gut zu wissen, denke ich, frage mich warum. Hmmmmm .....
Lornix
Beachten Sie, dass wenn die verwendete C-Bibliothek das 'Flag nicht unterstützt , Sie nicht die gewünschte Ausgabe erhalten - und das unabhängig vom Compiler. Der Compiler stellt sicher, dass die Bibliotheksfunktion für printf()mit der Formatzeichenfolge aufgerufen wird. Es liegt an der Bibliotheksfunktion, sie zu interpretieren. Unter Windows ist es durchaus möglich, dass die CRT-Bibliothek nicht die Unterstützung bietet, die Sie benötigen - und es spielt keine Rolle, welchen Compiler Sie verwenden.
Jonathan Leffler
3

Vielleicht wäre eine länderbezogene Version interessant.

#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

Dies hat einen Fehler (aber einen, den ich als ziemlich geringfügig betrachten würde). Auf der Zweierkomplement-Hardware wird die negativste Zahl nicht korrekt konvertiert, da versucht wird, eine negative Zahl mit N = -N;dem Zweierkomplement in die entsprechende positive Zahl umzuwandeln. Die maximal negative Zahl hat keine entsprechende positive Zahl, es sei denn, Sie fördern Sie es zu einem größeren Typ. Eine Möglichkeit, dies zu umgehen, besteht darin, die Nummer dem entsprechenden vorzeichenlosen Typ zuzuordnen (dies ist jedoch nicht trivial).

Jerry Sarg
quelle
Ich habe hier eine Frage gestellt, die eher auf eine plattformübergreifende Implementierung des Formats '-flag gerichtet ist: stackoverflow.com/q/44523855/2642059 Ich denke, diese Antwort spricht das perfekt an und führt jetzt weitere Tests durch. Wenn ja, sollte ich diese Frage wohl als Betrug markieren, oder?
Jonathan Mee
OK, als erstes habe ich erkannt, dass es sich nicht anpasst, wenn sich das Gebietsschema anpasst. Warum halten tsep, place_strund neg_strüberhaupt? Warum nicht einfach die fmt_infoMitglieder direkt nutzen ?
Jonathan Mee
OK, Nummer Sache Nummer 2, dieser Code kann nicht mit negativen Zahlen umgehen ... und ich weiß nicht genau, wie es könnte, while (*ptr-- = *neg_str++)macht für mich nicht viel Sinn. Sie fügen die negativen Zeichenfolgen in umgekehrter Reihenfolge ein.
Jonathan Mee
Also ... Ich habe den Speicherverlust beseitigt und den Fehler mit negativen Zahlen behoben : ideone.com/gTv8Z4 Leider gibt es immer noch ein Problem, wenn mehrere Zeichentrennzeichen oder mehrere negative Zeichensymbole rückwärts in die Zeichenfolge geschrieben werden. Ich werde versuchen, das nächste zu lösen ...
Jonathan Mee
@ JonathanMee: Ich habe den Code aktualisiert (und mindestens ein paar weitere Testfälle hinzugefügt, einschließlich negativer Zahlen).
Jerry Coffin
2

Ohne Rekursion oder String-Behandlung ein mathematischer Ansatz:

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

Im Prinzip ähnlich wie bei Pax 'rekursiver Lösung, aber durch vorherige Berechnung der Größenordnung wird eine Rekursion vermieden (möglicherweise mit erheblichem Aufwand).

Beachten Sie auch, dass das tatsächliche Zeichen, das zum Trennen von Tausenden verwendet wird, länderspezifisch ist.

Bearbeiten : Verbesserungen finden Sie in den Kommentaren von @ Chux unten.

Clifford
quelle
1
Das Ändern abs(n)auf fabs(n)verhindert den Komplimentfehler von 2 bei der Ausführung print_number(INT_MIN).
chux
@chux: Guter Punkt, aber im% -Ausdruck würde die LHS auf ein int zurückgesetzt und wäre immer noch defekt. Es ist vielleicht einfacher, nur den geringfügig kleineren Bereich akzeptabler Eingaben zu akzeptieren oder einen Test und eine Ausgabe "-2.147.483.647" direkt für INT_MIN hinzuzufügen (oder was auch immer INT_MIN auf der fraglichen Plattform ist - darin liegt eine weitere Dose Würmer.
Clifford
Ich habe es erfolgreich getestet, bevor ich vorgeschlagen habe. Hmmm. Ich sehe, meine Idee war nur für die log10(abs(n))und nicht anderswo gedacht . Interessanterweise funktioniert Ihre Lösung mit der einmaligen Änderung von log10(fabs(n))und print_number(INT_MIN)aufgrund dessen, printf(..., abs(n / order_of_magnitude))was bedeutet, n = abs(INT_MIN) % order_of_magnitudedass es in Ordnung ist, negativ zu sein. Wenn wir INT_MIN aufgeben, printf(..., abs(n / order_of_magnitude))kann das werden printf(..., n / order_of_magnitude). Aber ich nehme an, die Arbeit mit diesem Wurm namens "abs (INT_MIN)" ist normalerweise eine schlechte Sache.
chux
Neuer Gedanke: 3 Änderungen vorschlagen log10(fabs(n)), n = abs(n% order_of_magnitude)und printf(",%03d", n/order_of_magnitude). Übrigens: Ich würde diese Mühe nicht aufwenden, wenn ich nicht denke, dass Ihre Lösung gut ist. Keine UB, auch für INT_MIN.
chux
2

Basierend auf @Greg Hewgills, berücksichtigt jedoch negative Zahlen und gibt die Zeichenfolgengröße zurück.

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);
}
ideasman42
quelle
1

Meine Antwort formatiert das Ergebnis nicht genau wie die Abbildung in der Frage, kann jedoch in einigen Fällen den tatsächlichen Bedarf mit einem einfachen Einzeiler oder Makro decken. Man kann es erweitern, um bei Bedarf mehr als tausend Gruppen zu generieren.

Das Ergebnis sieht beispielsweise wie folgt aus:

Value: 0'000'012'345

Der Code:

printf("Value: %llu'%03lu'%03lu'%03lu\n", (value / 1000 / 1000 / 1000), (value / 1000 / 1000) % 1000, (value / 1000) % 1000, value % 1000);
Roland Pihlakas
quelle
Ist 'eine Standardnotation entspricht einem ,(mathematisch, zumindest) in einem Teil (e) der Welt?
Ysap
1
@ysap Es ist tausend Separator in einigen Teilen der Welt.
Roland Pihlakas
0

In C gibt es keine wirklich einfache Möglichkeit, dies zu tun. Ich würde einfach eine Int-to-String-Funktion ändern, um dies zu tun:

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);
}
Jeremy Ruten
quelle
0

Eine weitere iterative Funktion

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
quelle
Ich bin fasziniert von dem Ausdruck, mit dem die Dimension des Arrays bestimmt wird!? Gibt es dafür eine mathematische Rechtfertigung?
Clifford
ld (10) Bits für jede Dezimalstelle. Runden Sie auf 3 ab. Wir könnten 3 erneut teilen (um zu berücksichtigen, dass wir bis zu 3 Ziffern gleichzeitig speichern). Aber ich wollte es an einer Obergrenze halten.
Johannes Schaub - litb
0

Hier ist die schlankste, größen- und geschwindigkeitseffiziente Implementierung dieser Art der Dezimalstellenformatierung:

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

Verwenden Sie wie folgt:

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

Ausgabe:

test : +1,234,567,890.

Einige Vorteile:

  • Funktion, die das Ende des Zeichenfolgenpuffers aufgrund der Formatierung in umgekehrter Reihenfolge übernimmt. Schließlich, wo es nicht nötig ist, generierte Zeichenfolgen (strrev) zu verehren.

  • Diese Funktion erzeugt eine Zeichenfolge, die in jedem Algo danach verwendet werden kann. Es hängt nicht davon ab und erfordert nicht mehrere printf / sprintf-Aufrufe, was schrecklich langsam und immer kontextspezifisch ist.

  • Mindestanzahl von Divisionsoperatoren (/,%).
Zorg
quelle
Was ist unlikely?
Dan Bechard
1
@Dan: unlikelyist wahrscheinlich ein Hinweis für den Optimierer, dass die Bedingung wahrscheinlich nicht wahr ist. Weitere Informationen finden Sie unter likely()/ unlikely()macros im Linux-Kernel .
Jonathan Leffler
@ JonathanLeffler Oh, nicht wahr? Danke für den Link.
Dan Bechard
0

Sichere format_commas mit negativen Zahlen:

Da VS <2015 snprintf nicht implementiert, müssen Sie dies tun

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

Und dann

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

Anwendungsbeispiel:

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);
Stefan Steiger
quelle
0

Eine modifizierte Version der @ paxdiablo-Lösung, jedoch mit WCHARund 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);
}

quelle
0

Ich bin neu in der C-Programmierung. Hier ist mein einfacher 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;
}
K.tin
quelle
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 ...
}

Meine Lösung verwendet a. Anstelle von a bleibt es dem Leser überlassen, dies zu ändern.

Frank Abbing
quelle
0

Dies ist alt und es gibt viele Antworten, aber die Frage war nicht "Wie kann ich eine Routine schreiben, um Kommas hinzuzufügen", sondern "Wie kann das in C gemacht werden"? Die Kommentare wiesen auf diese Richtung hin, aber auf meinem Linux-System mit GCC funktioniert dies für mich:

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

Wenn dies ausgeführt wird, erhalte ich:

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

Wenn ich die LC_ALLVariable vor dem Ausführen des Programms deaktiviere, unsetenvist dies nicht erforderlich.

user1683793
quelle
0

Musste etwas Ähnliches selbst machen, aber anstatt direkt zu drucken, musste ich in einen Puffer gehen. Folgendes habe ich mir ausgedacht. Funktioniert rückwärts.

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

Beachten Sie, dass es nur für vorzeichenlose Ganzzahlen ausgelegt ist und Sie sicherstellen müssen, dass der Puffer groß genug ist.

Kranka
quelle
0

Eine andere Lösung besteht darin, das Ergebnis in einem intArray mit einer maximalen Größe von 7 zu speichern, da der long long intTyp Zahlen im Bereich von 9.223.372.036.854.775.807 bis -9.223.372.036.854.775.807 verarbeiten kann . (Beachten Sie, dass es sich nicht um einen vorzeichenlosen Wert handelt.)

Nicht rekursive Druckfunktion

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

Hauptfunktionsaufruf

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
}

Ausgabe testen

-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 der main () Funktion:

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

Wenn nur gedruckt werden muss, gehen Sie int numberSeparated[8];in die Funktion getNumWcommasund rufen Sie sie so auf getNumWcommas(number).

aah134
quelle
-1

Kann ziemlich einfach gemacht werden ...

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

Beispielaufruf:

char szBuffer[512];
pretty_number("1234567", szBuffer);
//strcmp(szBuffer, "1,234,567") == 0
Brian R. Bondy
quelle
-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(",");
           }

}
Steve Newman
quelle
1
Verwenden Sie mindestens den richtigen Einzug, wenn Sie den Code eingeben. Fügen Sie vielleicht auch eine Erklärung hinzu, was dies bewirkt, was vorhandene Antworten noch nicht tun.
EWit
Dies hat den Vorteil der Einfachheit und ist auf einen Blick leicht zu verstehen.
Steve Newman
1
Scheinlösung, druckt ein Extra ,für die unten stehenden Zahlen 100, verwendet, printf()wo putchar()fliegen würde, verwendet irreführende Namen, chaotische Einrückungen und viel zu viel Code.
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';
        }
Frans van Nispen
quelle
1
Dieser Code weist eine Vielzahl von Problemen auf. Die nicht verwendete Variable idxkönnte gehen. Der Code erzeugt nichts für 0. Er verarbeitet keine negativen Zahlen. Es gibt keinen offensichtlichen Grund, buffereine staticVariable zu erstellen (dies schränkt die Wiedereintrittsfähigkeit des Codes ein). Es gibt keine Erklärung dafür, was es tut, oder es wird erwähnt, dass die Zeichenfolge, auf die durch gezeigt wird, nach Abschluss des Codes pdie formatierte Zeichenfolge enthält. Das am wenigsten schwerwiegende Problem ist, dass Leerzeichen anstelle von Komma als Tausendertrennzeichen verwendet werden. Die Tatsache, dass es nicht mit Null umgeht, ist jedoch das Killerproblem.
Jonathan Leffler