Frage Erstellen Sie ein char-Array mit einer Ganzzahl, die Ziffern als Größe verwendet


Ich versuche, ein char-Array in C zu erstellen, um es mit den Ziffern eines int zu füllen, aber das int kann aus einer beliebigen Anzahl von Ziffern bestehen.

Ich benutze eine erstellte Funktion namens getDigits(int num), die eine Anzahl von Ziffern zurückgibt, die der Int hat.

char buffer[getDigits(number)] = "";
snprintf(buffer, sizeof(buffer),"%d",number);

aber wenn ich mit gcc kompiliere, gibt es zurück:

error: variable-sized object may not be initialized

Ich habe alles versucht. Wenn ich es als deklariere char fileSizeStr[5] = "";, Es klappt. Ich kann sehen, dass das Problem steigt, wenn ich versuche, die Puffergröße dynamisch zu deklarieren, aber ich würde wirklich gerne wissen, ob dies ein Weg ist, dies zu erreichen.


7
2018-06-07 00:25


Ursprung


Antworten:


Das Problem ist genau so, wie dein Compiler es dir sagt; Sie dürfen keine VLAs initialisieren. Zack gab eine offensichtliche Lösung in den Kommentaren: Entfernen Sie die Initialisierung. In dieser Antwort finden Sie Arbeitsbeispiele, von denen einige eine Initialisierung erlauben und andere nicht. Mehr dazu finden Sie in Kommentaren. Die folgenden Beispiele sind von den meisten vernünftigen (IMHO) zu den am wenigsten vernünftigen (die Verwendung von verwenden malloc) zum Zuweisen von Speicher für Dezimalziffernfolgen, die Zahlen darstellen.


Ich schlage vor, den gleichen Trick zu verwenden, um zu bestimmen, wie viele Bytes zum Speichern eines benötigt werden int Wert als Dezimalstellen, wie Sie für oktal verwenden würden: Teilen Sie die Gesamtzahl der Bits in einem int um 3 und für jedes Zeichen und NUL Kündigung hinzufügen. digit_count könnte wie ein Präprozessor-Makro geschrieben werden:

#include <limits.h>
#include <stddef.h>
#include <stdio.h>

#define digit_count(num) (1                                /* sign            */ \
                        + sizeof (num) * CHAR_BIT / 3      /* digits          */ \
                        + (sizeof (num) * CHAR_BIT % 3 > 0)/* remaining digit */ \
                        + 1)                               /* NUL terminator  */

int main(void) {
    short short_number = -32767;
    int int_number = 32767;
    char short_buffer[digit_count(short_number)] = { 0 }; /* initialisation permitted here */
    char int_buffer[digit_count(int_number)];
    sprintf(short_buffer, "%d", short_number);
    sprintf(int_buffer, "%d", int_number);
}

Wie Sie sehen, ist dies ein großer Vorteil digit_count kann für jede Art von Ganzzahl ohne Änderung verwendet werden: char, short, int, long, long longund das entsprechende unsigned Arten.

Ein kleiner Nachteil im Vergleich ist, dass Sie ein paar Bytes Speicherplatz verschwenden, insbesondere für kleine Werte wie 1. In vielen Fällen gleicht die Einfachheit dieser Lösung dies aus; Der Code, der zum Zählen der Dezimalziffern zur Laufzeit benötigt wird, belegt mehr Speicherplatz im Speicher als hier verschwendet wird.


Wenn Sie bereit sind, die Einfachheit und generischen Eigenschaften des obigen Codes wegzuwerfen, und Sie wirklich die Anzahl der Dezimalstellen zählen möchten, gilt Zacks Rat: Entfernen Sie die Initialisierung. Hier ist ein Beispiel:

#include <stddef.h>
#include <stdio.h>

size_t digit_count(int num) {
    return snprintf(NULL, 0, "%d", num) + 1;
}

int main(void) {
    int number = 32767;
    char buffer[digit_count(number)]; /* Erroneous initialisation removed as per Zacks advice */
    sprintf(buffer, "%d", number);
}

Als Antwort auf die malloc Empfehlungen: Der am wenigsten schreckliche Weg, dieses Problem zu lösen, ist unnötigen Code zu vermeiden (zB Anrufe an malloc und später free). Wenn Sie das Objekt nicht von einer Funktion zurückgeben müssen, verwenden Sie es nicht malloc! Andernfalls sollten Sie in einem vom Aufrufer bereitgestellten Puffer speichern (über Argumente), damit der Anrufer auswählen kann, welcher Speichertyp verwendet werden soll. Es ist sehr selten, dass dies keine geeignete Alternative zur Verwendung ist malloc.

Wenn Sie sich entscheiden zu verwenden malloc und free Dafür aber tu es am wenigsten schrecklichen Weg. Vermeiden Sie Typumwandlungen auf dem Rückgabewert von malloc und Multiplikationen durch sizeof (char) (Das ist immer 1). Der folgende Code ist ein Beispiel. Verwenden Sie eine der obigen Methoden, um die Länge zu berechnen:

char *buffer = malloc(digit_count(number)); /* Initialisation of malloc bytes not possible */
sprintf(buffer, "%d", number);

... und vergiss es nicht free(buffer); wenn du damit fertig bist.


16
2018-06-07 02:45



versuche etwas wie:

 char* buffer =(char *)malloc(getDigits(number)*sizeof(char));

malloc und calloc werden zur dynamischen Zuordnung verwendet.


5
2018-06-07 00:32



unten kann helfen

char* buffer;
buffer = (char*)malloc(number * sizeof(char));

3
2018-06-07 00:34



Für mein Geld gibt es eine Lösung, die unerwähnt geblieben ist, die aber tatsächlich einfacher ist als alle anderen. Es gibt eine kombinierte Allokationsversion von sprintf namens "asprintf", die unter Linux und den meisten BSD-Varianten verfügbar ist. Sie bestimmt die erforderliche Größe, mallokiert den Speicher und gibt die gefüllte Zeichenfolge in das erste Argument zurück.

char * a;
asprintf(&a, "%d", 132);
// use a
free(a);

Die Verwendung eines stapelzugewiesenen Arrays beseitigt sicherlich die Notwendigkeit für das freie, aber dies beseitigt vollständig die Notwendigkeit, die Größe separat zu berechnen.


3
2018-06-14 17:28



Sie müssen verwenden malloc Zuweisen einer dynamischen Speichermenge.

Das Initialisieren der Art, wie Sie es getan haben, ist nur erlaubt, wenn die Größe zum Zeitpunkt der Kompilierung bekannt ist.


2
2018-06-07 00:29