2013-06-07 9 views
7

Sto provando a creare un array di caratteri in C, per riempirlo con le cifre di un int, ma l'int può essere di un numero qualsiasi di cifre.Crea array di caratteri di numero intero utilizzando le cifre come dimensione

Sto utilizzando una funzione creata denominata getDigits(int num), che restituisce un numero di cifre che l'int ha.

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

ma quando compilo usando gcc, restituisce:

error: variable-sized object may not be initialized

Ho provato di tutto. Quando lo dichiaro come char fileSizeStr[5] = "";, funziona. Vedo che il problema sta sorgendo quando provo a dichiarare la dimensione del buffer in modo dinamico, ma mi piacerebbe davvero sapere se è un modo per raggiungere questo obiettivo.

+1

malloc il buffer. – Duck

+0

usa il compilatore c99 o usa malloc – BLUEPIXY

+4

Prova a rimuovere '=" "'. 'snprintf' non si preoccupa di cosa c'è nel suo buffer di output in anticipo. – zwol

risposta

16

Il problema è esattamente come il compilatore ti dice; non ti è permesso inizializzare VLA. Zack ha dato una soluzione ovvia nei commenti: rimuovere l'inizializzazione. Troverai esempi di lavoro in questa risposta, alcuni dei quali consentono un'inizializzazione, mentre altri no. Troverai maggiori informazioni a riguardo nei commenti. I seguenti esempi sono ordinati dal più ragionevole (IMHO) al meno sensibile (il che implica l'uso di malloc) per allocare la memoria per le sequenze di cifre decimali che rappresentano numeri.


Io suggerisco di usare lo stesso trucco per determinare il numero di byte necessari per memorizzare un valore int come cifre decimali come ci si utilizza per ottale: dividere il numero totale di bit in un int del 3 e aggiungere per qualsiasi segno e terminazione NUL. digit_count potrebbe essere scritto come una macro di preprocessore in questo modo:

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

Come si può vedere, un potente vantaggio è che digit_count può essere utilizzato per qualsiasi tipo di numero intero senza modifiche: char, short, int, long, long long e i corrispondenti tipi unsigned.

Uno svantaggio minore rispetto al confronto è che si sprecano pochi byte di spazio, in particolare per valori piccoli come 1. In molti casi, la semplicità di questa soluzione ha più che compensato; Il codice richiesto per contare le cifre decimali in fase di runtime occuperà più spazio nella memoria di quanto non sia sprecato qui.


Se siete pronti a buttare via la semplicità e qualità generici del codice di cui sopra, e si vuole veramente contare il numero di cifre decimali, consigli Zacks applica: Rimuovere l'inizializzazione.Ecco un esempio:

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

In risposta alle raccomandazioni malloc: Il modo meno orribile per risolvere questo problema è quello di evitare inutili code (ad esempio le chiamate a malloc e successivamente free.). Se non è necessario restituire l'oggetto da una funzione, non utilizzare malloc! Altrimenti, considera l'archiviazione in un buffer fornito dal chiamante (tramite argomenti) in modo che il chiamante possa scegliere il tipo di memoria da utilizzare. È molto raro che questa non sia un'alternativa appropriata all'uso di malloc.

Se si decide di utilizzare malloc e free per questo, tuttavia, farlo il modo meno orribile. Evita i typecasts sul valore di ritorno di malloc e le moltiplicazioni per sizeof (char) (che è sempre 1). Il seguente codice è un esempio. Utilizzare uno dei metodi di cui sopra per calcolare la lunghezza:

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

... e non dimenticate di free(buffer); quando hai finito con esso.

2

È necessario utilizzare malloc per allocare una quantità dinamica di memoria.

L'inizializzazione del modo in cui è stata eseguita è consentita solo se la dimensione è nota al momento della compilazione.

+0

Grazie! Non posso credere di aver dimenticato completamente di usare malloc. – anairinac

+0

Prego. Le altre risposte hanno esempi C. – John

5

provare qualcosa di simile:

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

malloc e calloc vengono utilizzati per l'allocazione dinamica.

+4

1. Non lanciare malloc. 2. Non esiste alcun punto moltiplicando per 'sizeof (char)' perché 'sizeof (char)' è * sempre * 1 in C. – Sebivor

+0

ronzio, interessante. Da quello che ho appena cercato, in C, non dobbiamo fare cast in questo caso. Ma i programmi C++, lo facciamo .. Grazie per l'informazione! –

+0

... e questa domanda è codificata [c], non [C++] ... – Sebivor

3

di seguito può aiutare

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

1. Non lanciare malloc. 2. Non c'è alcun punto moltiplicando per 'sizeof (char)' perché 'sizeof (char)' è * sempre * 1 in C. – Sebivor

+0

perché non cast malloc? Penso che ci sia solo un modo per allocare memoria nella vecchia C. – NonStatic

+0

@mmsc [Perché non si deve eseguire il cast del valore restituito da malloc] (http: // stackoverflow.it/questions/605845/do-i-cast-the-result-of-malloc/605858 # 605858) –

3

Per i miei soldi, c'è una soluzione che non è stata menzionata ma che è in realtà più semplice di quanto sopra. Esiste una versione allocata di sprintf chiamata "asprintf" disponibile su Linux e sulla maggior parte delle varianti BSD. Determina la dimensione necessaria, malloc la memoria e restituisce la stringa piena nel primo argomento.

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

Utilizzando un array allocato pila elimina certamente la necessità per la libera, ma Questo ovvia completamente la necessità di calcolare mai a parte le dimensioni.

+1

nota: su sistemi senza 'asprintf', usando C99 è facile eseguire il rollover con due chiamate a' snprintf' –

Problemi correlati