Inizializza / reimposta la struttura su zero / null


92
struct x {
    char a[10];
    char b[20];
    int i;
    char *c;
    char *d[10];
};

Sto riempiendo questa struttura e quindi utilizzo i valori. Alla successiva iterazione, voglio ripristinare tutti i campi su 0o nullprima di iniziare a riutilizzarli.

Come lo posso fare? Posso usare memseto devo passare attraverso tutti i membri e poi farlo individualmente?

Risposte:


109

Definire un'istanza statica const della struttura con i valori iniziali e quindi assegnare semplicemente questo valore alla variabile ogni volta che si desidera ripristinarla.

Per esempio:

static const struct x EmptyStruct;

Qui mi affido all'inizializzazione statica per impostare i miei valori iniziali, ma potresti usare un inizializzatore di struttura se desideri valori iniziali diversi.

Quindi, ogni volta che fai il ciclo puoi scrivere:

myStructVariable = EmptyStruct;

1
@David Heffernan: è meglio che usare memsetse voglio solo resettare tutto a 0??
hari

9
@hari, preferirei questo approccio anch'io. Usare memsetmi fa sentire sporco. Preferisco lasciare che il compilatore si preoccupi del layout della memoria ove possibile. A rigor di termini tale uso di memsetnon è portabile, ma in pratica sarei sbalordito se mai compilassi il tuo codice ovunque sia importante. Quindi, puoi probabilmente usare memset in sicurezza se lo preferisci.
David Heffernan

2
@hari, è concettualmente migliore, poiché fornisci valori di inizializzazione predefiniti (qualcosa come un modello di fabbrica di oggetti.)
Diego Sevilla

1
@cnicutar Lo so. Nota che la mia risposta consiglia di non utilizzare memset. Nota anche il commento su dove indico la non portabilità dell'uso di memset come mezzo per assegnare valori nulli. Il mio commento precedente sottolinea semplicemente la realtà che 0 bit invariabilmente corrispondono a zero in virgola mobile.
David Heffernan

1
@ Kp11 citazione per favore
David Heffernan

85

Il modo per fare una cosa del genere quando hai il C moderno (C99) è usare un letterale composto .

a = (const struct x){ 0 };

Questo è in qualche modo simile alla soluzione di David, solo che non devi preoccuparti di dichiarare una struttura vuota o se dichiararla static. Se si utilizza constcome ho fatto io, il compilatore è libero di allocare staticamente il composto letterale nella memoria di sola lettura, se appropriato.


Questo crea un'istanza di x sullo stack per poi copiarlo in un? Per grandi strutture / piccole pile questo potrebbe essere un problema.
Étienne

1
Come tutte le ottimizzazioni, questa dipende completamente dal compilatore, quindi dovresti controllare cosa produce il tuo compilatore. "Di solito" sui compilatori moderni non è così, questi possono tracciare molto bene le inizializzazioni e fare solo ciò che è necessario, non di più. (E non pensare che queste cose siano problemi prima di misurare un vero rallentamento. Di solito non lo sono.)
Jens Gustedt,

3
Gli avvisi di "inizializzazione mancante" sono davvero fasulli. Lo standard C prescrive esattamente cosa deve accadere e prevede { 0 }come inizializzatore predefinito. Disattivare l'avviso, è falso falso allarme.
Jens Gustedt

1
@ JensGustedt Questo typecasting ha davvero bisogno? Non posso scriverlo così? struct xa = (const) {0};
Patrick

1
@Patrick, sebbene la sintassi sia simile, questo non è un cast ma un "letterale composto". E stai confondendo inizializzazione e assegnazione.
Jens Gustedt

58

Meglio di tutto sopra è sempre usare la specifica C standard per l'inizializzazione della struttura:

struct StructType structVar = {0};

Qui ci sono tutti i bit zero (mai).


13
Non penso che tu possa farlo ogni volta in un giro però
David Heffernan

2
Questo è davvero supponiamo di funzionare. Ma sfortunatamente, gcc e g ++ se ne lamentano. gcc genera avvisi, mentre g ++ genera un errore. So che gcc e g ++ sono colpevoli di questo (si suppone che seguano le specifiche dello standard C), ma comunque, per una buona portabilità, è obbligatorio prendere in considerazione tale limitazione.
Ciano

3
@Cyan Puoi usare {}in C ++. Gli sviluppatori di gcc sembrano incerti se si suppone che C ++ supporti{0} e io stesso non ho familiarità con quella parte dello standard.
Matthew Read

@ Matthew: Sì, in realtà, ho finito per usare memset (), perché c'erano troppi problemi di portabilità con {0}o {}. Non sono sicuro che gli standard C e C ++ siano chiari e sincronizzati su questo problema, ma a quanto pare i compilatori non lo sono.
Ciano

funzionerà in questo caso? struct StructType structVar = malloc (sizeof(StructType)); structVar ={0}
Sam Thomas

34

In C, è un idioma comune azzerare la memoria per un structutilizzo memset:

struct x myStruct;
memset(&myStruct, 0, sizeof(myStruct));

Tecnicamente parlando, non credo che sia portatile perché si presume che il file NULL puntatore su una macchina sia rappresentato dal valore intero 0, ma è ampiamente utilizzato perché sulla maggior parte delle macchine questo è il caso.

Se passi da C a C ++, fai attenzione a non usare questa tecnica su ogni oggetto. Il C ++ lo rende legale solo sugli oggetti senza funzioni membro e senza ereditarietà.


2
Lo standard C afferma che NULL è sempre 0. Se la macchina è progettata in modo tale che un indirizzo non valido predeterminato non sia letteralmente 0, il compilatore per quell'architettura deve regolare durante la compilazione.
Kevin M

8
@KevinM Sì, il simbolo "0" corrisponde sempre al puntatore NULL anche se è tutto zero; ma non c'è niente che il compilatore possa fare se imposti i bit a zero usando memset.
Adrian Ratnapala

"Il C ++ lo rende legale solo su oggetti senza funzioni membro e senza ereditarietà." Riguarda se il tipo è considerato "semplice vecchio dato". I criteri dipendono dalla versione del linguaggio C ++.
Max Barraclough il

19

Se hai un compilatore compatibile con C99, puoi usare

mystruct = (struct x){0};

altrimenti dovresti fare quello che ha scritto David Heffernan, cioè dichiarare:

struct x empty = {0};

E nel ciclo:

mystruct = empty;

6

Puoi usare memsetcon la dimensione della struttura:

struct x x_instance;
memset (&x_instance, 0, sizeof(x_instance));

1
Non credo che il cast sia necessario qui. È?
templatetypedef

Beh, sono così abituato al C ++ che ... beh, funzionerà anche in C ++, quindi non lo vedo come un peso.
Diego Sevilla

Sì, non ero abbastanza specifico. Qualsiasi puntatore a cv qualificato T può essere convertito in cv qualificato void *. Qualsiasi puntatore di dati, puntatori a funzione sono una questione completamente diversa. Kudos @Kevin
Marcus Borkenhagen

memsetè un'opzione, ma quando la usi, devi assicurarti che la memoria scritta abbia esattamente la stessa dimensione del terzo parametro, ecco perché è meglio fare riferimento alla dimensione dell'oggetto reale, non alla dimensione del tipo che so che attualmente lo è. IOW memset (&x_instance, 0, sizeof(x_instance));è una scelta molto migliore. BTW: il (void*)cast è superfluo anche in C ++.
Wolf

(scusate mi sono perso per occuparmi della domanda, ora è meglio)
Wolf

5

Credo che tu possa semplicemente assegnare il set vuoto ( {}) alla tua variabile.

struct x instance;

for(i = 0; i < n; i++) {
    instance = {};
    /* Do Calculations */
}

0
 struct x myX;
 ...
 memset(&x, 0, sizeof(myX));

5
Penso che OP sappia come chiamare memset, ma piuttosto il problema è se farlo è saggio o meno
David Heffernan

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.