2013-06-07 3 views
7

Ich versuche, einen char-Array in C zu erstellen, sie mit den Ziffern eines int zu füllen, aber das int kann von einem beliebigen Anzahl von Ziffern sein.erstellen char-Array von Integer mit den Ziffern als Größe

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

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

aber wenn ich gcc kompilieren verwenden, es gibt:

error: variable-sized object may not be initialized

Ich habe alles versucht. Wenn ich es als char fileSizeStr[5] = ""; deklariere, funktioniert es. 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.

+1

malloc der Puffer. – Duck

+0

Verwenden Sie den Compiler c99 oder verwenden Sie malloc – BLUEPIXY

+4

Versuchen Sie, das '=" "zu entfernen. 'snprintf' ist es egal, was vorher in seinem Ausgabepuffer ist. – zwol

Antwort

16

Das Problem ist, helfen, genau wie Ihr Compiler sagt Ihnen; 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 werden von den meisten sinnvollen (IMHO) zu den am wenigsten sinnvollen (mit der Verwendung von malloc) Ordnungen zum Zuweisen von Speicher für Dezimalziffernfolgen, die Zahlen darstellen, angeordnet.


Ich schlage vor, den gleichen Trick, um zu bestimmen mit, wie viele Bytes notwendig sind, um einen int Wert als Dezimalstellen zu speichern, wie Sie für Oktal verwenden würde: Teilen Sie die Gesamtzahl der Bits in einem int von 3 und fügen Sie für jedes Zeichen und NULL Kündigung. digit_count als Präprozessormakro wie so 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 können, ein leistungsfähiger Vorteil hierbei ist, dass digit_count kann für jede Art von Integer ohne Modifikation verwendet werden: char, short, int, long longlong und die entsprechenden unsigned Typen.

Ein kleiner Nachteil im Vergleich ist, dass Sie ein paar Byte Speicherplatz verschwenden, vor allem für kleine Werte wie 1. In vielen Fällen gleicht die Einfachheit dieser Lösung dies aus; Der Code benötigt, um die Dezimalstellen zur Laufzeit zu zählen, wird mehr Platz im Speicher belegen als hier verschwendet wird.


Wenn Sie bereit sind, die Einfachheit und die generische Qualitäten des obigen Codes wegzuwerfen, und Sie wirklich wollen, um die Anzahl der Dezimalstellen zählen, Zacks Rat gilt: die Initialisierung entfernen.Hier 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 Reaktion auf die malloc Empfehlungen: Die am wenigsten schreckliche Art und Weise, dieses Problem zu lösen, ist nicht notwendig, den Code zu vermeiden (zB Anrufe zu malloc und später free.). Wenn Sie das Objekt nicht von einer Funktion zurückgeben müssen, verwenden Sie 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 von malloc ist.

Wenn Sie sich dafür entscheiden, malloc und free dafür zu verwenden, tun Sie es jedoch die am wenigsten schreckliche Weise. Vermeiden Sie Typumwandlungen auf dem Rückgabewert malloc und Multiplikationen von sizeof (char) (die immer 1 ist). Der folgende Code ist ein Beispiel. Verwenden Sie eine der oben genannten Methoden, um die Länge zu berechnen:

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

... und vergessen Sie nicht zu free(buffer);, wenn Sie mit ihm fertig sind.

2

Sie müssen malloc verwenden, um eine dynamische Speichermenge zuzuweisen.

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

+0

Danke! Ich kann nicht glauben, dass ich komplett vergessen habe, malloc zu benutzen. – anairinac

+0

Gern geschehen. Die anderen Antworten haben C Beispiele. – John

5

versuchen so etwas wie:

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

malloc und calloc werden dinamic Zuordnung verwendet.

+4

1. Gießen Sie kein malloc. 2. Es gibt keinen Punkt, der mit "sizeof (char)" multipliziert, weil "sizeof (char)" * immer * 1 in C ist. – Sebivor

+0

hum, interesting. Nach dem, was ich gerade gesucht habe, müssen wir in C wirklich keine Casts machen. Aber C++ Programme machen wir .. Danke von der Information! –

+0

... und diese Frage ist markiert [c], nicht [C++] ... – Sebivor

3

unten kann

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

1. Gießen Sie nicht malloc. 2. Es gibt keinen Punkt, der mit "sizeof (char)" multipliziert, weil "sizeof (char)" * immer * 1 in C ist. – Sebivor

+0

Warum nicht malloc werfen? Ich denke, es gibt nur eine Möglichkeit, Speicher in alten C. – NonStatic

+0

@ mmsc zuweisen [Warum sollten Sie nicht den Wert von malloc zurückgegeben] (http: // stackoverflow.com/questions/605845/do-i-cast-das-Ergebnis-von-malloc/605858 # 605858) –

3

Für mein Geld gibt es eine Lösung, die unerwähnt geblieben ist, die aber tatsächlich einfacher als die oben genannten ist. 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); 

einen Stapel zugeordnet Array entfernt sicherlich die Notwendigkeit für den freien, aber dies vermeidet vollständig die Notwendigkeit, immer separat die Größe zu berechnen.

+1

hinweis: auf systemen ohne "asprintf", mit C99 ist es einfach zu rollen eigenen mit zwei anrufe zu "snprintf" –