Initialiser / réinitialiser la structure à zéro / null


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

Je remplis cette structure, puis j'utilise les valeurs. Lors de la prochaine itération, je souhaite réinitialiser tous les champs sur 0ou nullavant de commencer à les réutiliser.

Comment puis je faire ça? Puis-je utiliser memsetou dois-je parcourir tous les membres et ensuite le faire individuellement?

Réponses:


109

Définissez une instance statique const de la structure avec les valeurs initiales, puis affectez simplement cette valeur à votre variable chaque fois que vous souhaitez la réinitialiser.

Par exemple:

static const struct x EmptyStruct;

Ici, je me fie à l'initialisation statique pour définir mes valeurs initiales, mais vous pouvez utiliser un initialiseur struct si vous voulez des valeurs initiales différentes.

Ensuite, à chaque tour de boucle, vous pouvez écrire:

myStructVariable = EmptyStruct;

1
@David Heffernan: est-ce mieux que d'utiliser memsetsi je veux seulement tout réinitialiser sur 0??
hari

9
@hari Je préfère moi-même cette approche. L'utilisation memsetme fait me sentir sale. Je préfère laisser le compilateur s'inquiéter de la disposition de la mémoire dans la mesure du possible. À proprement parler, une telle utilisation memsetn'est pas portable, mais en pratique, je serais étonné si jamais vous compiliez votre code partout où cela comptait. Ainsi, vous pouvez probablement utiliser memset en toute sécurité si vous le préférez.
David Heffernan

2
@hari, c'est conceptuellement mieux, car vous fournissez des valeurs d'initialisation par défaut (quelque chose comme un modèle de fabrique d'objets.)
Diego Sevilla

1
@cnicutar je le sais. Notez que ma réponse recommande de ne pas utiliser memset. Notez également le commentaire sur l'endroit où je souligne la non-portabilité de l'utilisation de memset comme moyen d'attribuer des valeurs nulles. Mon commentaire précédent souligne simplement le fait que 0 bits correspond invariablement à des zéros en virgule flottante.
David Heffernan

1
@ kp11 citation please
David Heffernan

85

La manière de faire une telle chose quand vous avez C moderne (C99) est d'utiliser un littéral composé .

a = (const struct x){ 0 };

C'est un peu similaire à la solution de David, mais vous n'avez pas à vous soucier de déclarer une structure vide ou de la déclarer static. Si vous utilisez le constcomme je l'ai fait, le compilateur est libre d'allouer le littéral composé de manière statique dans le stockage en lecture seule, le cas échéant.


Cela crée-t-il une instance de x sur la pile pour ensuite la copier dans un? Pour les grandes structures / petites piles qui pourraient poser problème.
Étienne

1
Comme toutes les optimisations, cela dépend complètement du compilateur, vous devrez donc vérifier ce que votre compilateur produit. "Habituellement" sur les compilateurs modernes, ce n'est pas le cas, ceux-ci peuvent très bien suivre les initialisations et ne faire que ce qui est nécessaire, pas plus. (Et ne pensez pas que de telles choses sont des problèmes avant de mesurer un vrai ralentissement. Ils ne le sont généralement pas.)
Jens Gustedt

3
Les avertissements "initialiseur manquant" sont vraiment faux. La norme C prescrit exactement ce qui doit se passer que, et prévoit le { 0 }comme initialiseur par défaut. Éteignez cet avertissement, il s'agit d'une fausse alarme.
Jens Gustedt

1
@JensGustedt Ce typage est-il vraiment nécessaire? Je ne peux pas l'écrire comme ça? struct xa = (const) {0};
Patrick

1
@Patrick, bien que la syntaxe soit similaire, ce n'est pas un cast mais un "littéral composé". Et vous mélangez initialisation et affectation.
Jens Gustedt

58

Mieux que tout ce qui précède, c'est d'utiliser la spécification Standard C pour l'initialisation de la structure:

struct StructType structVar = {0};

Voici tous les bits zéro (jamais).


13
Je ne pense pas que vous puissiez faire cela à chaque fois autour d'une boucle
David Heffernan

2
Ceci est en effet supposé fonctionner. Mais malheureusement, gcc & g ++ s'en plaignent. gcc génère des avertissements, tandis que g ++ génère une erreur. Je sais que gcc & g ++ sont en faute à ce sujet (ils sont censés suivre la spécification Standard C), mais néanmoins, pour une bonne portabilité, il est obligatoire de prendre cette limitation en considération.
Cyan

3
@Cyan Vous pouvez utiliser {}en C ++. Les développeurs de gcc ne semblent pas sûrs de savoir si C ++ est censé prendre en charge{0} et je ne suis pas familier avec cette partie de la norme moi-même.
Matthew Lire

@Matthew: Oui, en fait, j'ai fini par utiliser memset (), car il y avait trop de problèmes de portabilité avec {0}ou {}. Je ne sais pas si les normes C et C ++ sont claires et synchronisées sur ce problème, mais apparemment, les compilateurs ne le sont pas.
Cyan

cela fonctionnera-t-il dans un tel cas? struct StructType structVar = malloc (sizeof(StructType)); structVar ={0}
Sam Thomas

35

En C, il est courant de mettre à zéro la mémoire pour une structutilisation memset:

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

Techniquement parlant, je ne pense pas que ce soit portable car cela suppose que le NULLpointeur sur une machine est représenté par la valeur entière 0, mais il est largement utilisé car c'est le cas sur la plupart des machines.

Si vous passez du C au C ++, veillez à ne pas utiliser cette technique sur chaque objet. C ++ rend cela légal uniquement sur les objets sans fonctions membres et sans héritage.


2
La norme C stipule que NULL est toujours 0. Si la machine est conçue de telle sorte qu'une adresse invalide prédéterminée n'est pas littéralement 0, le compilateur de cette architecture doit s'ajuster lors de la compilation.
Kevin M

9
@KevinM Oui, le symbole "0" correspond toujours au pointeur NULL même s'il est tout à zéro; mais il n'y a rien que le compilateur puisse faire si vous définissez les bits à zéro en utilisant memset.
Adrian Ratnapala

"C ++ rend cela légal uniquement sur les objets sans fonctions membres et sans héritage." Il s'agit de savoir si le type est considéré comme de «vieilles données simples». Les critères dépendent de la version du langage C ++.
Max Barraclough le

19

Si vous avez un compilateur compatible C99, vous pouvez utiliser

mystruct = (struct x){0};

sinon vous devriez faire ce que David Heffernan a écrit, c'est-à-dire déclarer:

struct x empty = {0};

Et dans la boucle:

mystruct = empty;

6

Vous pouvez utiliser memsetavec la taille de la structure:

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

1
Je ne pense pas que le casting soit nécessaire ici. C'est ça?
templatetypedef

Eh bien, je suis tellement habitué au C ++ que ... eh bien, cela fonctionnera également en C ++, donc je ne le vois pas comme un fardeau.
Diego Sevilla du

Ouais, je n'étais pas assez précis. Tout pointeur vers cv qualifié T peut être converti en cv qualifié void *. Tout pointeur de données, les pointeurs de fonction sont une tout autre affaire. Kudos @Kevin
Marcus Borkenhagen

memsetest une option, mais lorsque vous l'utilisez, vous devez vous assurer que la mémoire écrite est exactement de la même taille que le troisième paramètre, c'est pourquoi il est préférable de se référer à la taille de l'objet réel, pas à la taille du type que vous sachez qu'il est actuellement . IOW memset (&x_instance, 0, sizeof(x_instance));est un bien meilleur choix. BTW: la (void*)distribution est également superflue en C ++.
Wolf

(désolé j'ai manqué de s'occuper de la question, c'est mieux maintenant)
Wolf

5

Je crois que vous pouvez simplement affecter l'ensemble vide ( {}) à votre variable.

struct x instance;

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

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

5
Je pense qu'OP sait comment appeler memset, mais la question est plutôt de savoir si le faire est sage ou non
David Heffernan

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.