web-dev-qa-db-fra.com

Comment memset char array avec un caractère final nul?

Quel est le moyen correct et le plus sûr de memset le tableau de caractères entier avec le caractère final nul? Je peux lister quelques usages:

...
char* buffer = new char [ARRAY_LENGTH];

//Option 1:             memset( buffer, '\0', sizeof(buffer) );
//Option 2 before edit: memset( buffer, '\0', sizeof(char*) * ARRAY_LENGTH );
//Option 2 after edit:  memset( buffer, '\0', sizeof(char) * ARRAY_LENGTH );
//Option 3:             memset( buffer, '\0', ARRAY_LENGTH );
...
  • Est-ce que l'un d'entre eux a un avantage significatif par rapport à d'autres?
  • Quels types de problèmes puis-je rencontrer avec les utilisations 1, 2 ou 3?
  • Quelle est la meilleure façon de traiter cette demande?
13
Koray

Les options un et deux sont tout simplement fausses. Le premier utilise la taille d'un pointeur au lieu de la taille du tableau, il n'écrira donc probablement pas dans tout le tableau. La seconde utilise sizeof(char*) au lieu de sizeof(char) pour écrire au-delà de la fin du tableau. L'option 3 est d'accord. Vous pouvez aussi utiliser ceci

memset( buffer, '\0', sizeof(char)*ARRAY_LENGTH );

mais sizeof(char) est garanti égal à 1.

18
Dirk Holsopple

La méthode idiomatique consiste à initialiser le tableau en valeur:

char* buffer = new char [ARRAY_LENGTH]();

Option 1 définit uniquement les premiers octets sizeof(char*) sur 0, ou exécute un comportement non défini si ARRAY_LENGHT < sizeof(char*).

Option 2 rencontre un comportement indéfini car vous essayez de définir plus d'octets ARRAY_LENGTH. sizeof(char*) est presque certainement supérieur à 1.

Puisqu'il s'agit bien de C++ (pas de new en C), je vous suggère d'utiliser plutôt un std::string.

Pour C (en prenant malloc au lieu de new[]), vous pouvez utiliser 

memset( buffer, 0, ARRAY_LENGTH );
13
Luchian Grigore

Comme la question ne cesse de changer, je définis:

1: memset( buffer, '\0', sizeof(buffer) );

2a: memset( buffer, '\0', sizeof(char*) * ARRAY_LENGTH );

2b: memset( buffer, '\0', sizeof(char) * ARRAY_LENGTH );

3: memset( buffer, '\0', ARRAY_LENGTH );

Si la question est simplement "quelle est la bonne façon d'appeler memset" plutôt que "quelle est la meilleure façon de mettre à zéro ce tableau", alors 2b ou 3 est correct. 1 et 2a ont tort.

Vous pouvez mener une guerre de styles sur 2b vs 3: inclure ou non le sizeof(char) (certaines personnes l'ignorent car il est redondant (ce que je fais habituellement), d'autres l'insèrent pour créer une sorte de cohérence avec le même code un tableau de int. C'est-à-dire qu'ils multiplient toujours une taille par un certain nombre d'éléments, même s'ils savent que la taille est 1. Une conclusion possible est que le moyen le plus sûr de memset le tableau pointé par buffer est:

std::memset(buffer, 0, sizeof(*buffer) * ARRAY_LENGTH);

Ce code reste correct si le type de mémoire tampon change, à condition bien sûr qu'il contienne toujours les éléments ARRAY_LENGTH, quel que soit leur type, et à condition que la valeur tout-bits-zéro reste la valeur initiale correcte.

Une autre option appréciée des programmeurs "C++ n'est pas C" est:

/* never mind how buffer is allocated */
std::fill(buffer, buffer + ARRAY_LENGTH, 0);

Si vous le souhaitez, vous pouvez alors vérifier par vous-même si votre compilateur optimise cette option avec le même code que celui qui optimise l'appel équivalent à std::memset.

char *buffer = new char [ARRAY_LENGTH](); est astucieux mais presque inutile en C++ en pratique car vous n'allouez pratiquement jamais un tableau avec new en premier lieu.

std::string buffer(ARRAY_LENGTH, 0); introduit une manière particulière de gérer le tampon, ce qui peut être ou ne pas être ce que vous voulez, mais c'est souvent le cas. Il y a beaucoup à dire sur char buffer[ARRAY_LENGTH] = {0}; dans certains cas.

5
Steve Jessop
  • Est-ce que l'un d'entre eux a un avantage significatif par rapport à d'autres?
  • Quels types de problèmes puis-je rencontrer avec les utilisations 1, 2 ou 3?

1er est faux, parce que sizeof(buffer) == sizeof(char*).

2ème et 3ème sont OK.

  • Quelle est la meilleure façon de traiter cette demande?

Pourquoi pas simplement:

buffer[0] = '\0';

S'il s'agit d'un tableau char, pourquoi s'embarrasser du reste des caractères? Lorsque le premier octet est défini sur zéro, vous avez l’équivalent de "" dans votre buffer.

Bien sûr, si vous insistez vraiment pour que tous les buffer soient mis à zéro, utilisez la réponse avec std::fill - c'est la bonne façon. Je veux dire std::fill(buffer, buffer + ARRAY_LENGTH, 0);.

3
PiotrNycz

Si vous devez absolument utiliser un tableau brut en C++ (c'est une très mauvaise idée), procédez comme suit:

char* buffer = new char [ARRAY_LENGTH]();

Pour C++, memset est généralement le dernier refuge des incompétents, même si j’ai appris ces derniers mois que pour obtenir des performances acceptables, avec les outils actuels, il est nécessaire de descendre à ce niveau lorsqu’on met en œuvre sa propre classe de cordes.

Au lieu de ces tableaux bruts, etc., qui peuvent sembler avoir besoin de memset, utilisez par exemple. std::string (pour le cas ci-dessus), std::vector, std::array etc.

2

Depuis C++ 11, je choisirais:

#include <array>

std::array<char, ARRAY_LENGTH> buffer{ '\0' };

buffer.fill('\0');
1
Amit G.

Personnellement, j'aime bien l'option 3:

memset( buffer, '\0', ARRAY_LENGTH )

ARRAY_LENGTH est exactement ce que je voudrais remplir dans la mémoire.

0
Simon Lau

Option 3: memset( buffer, '\0', ARRAY_LENGTH ): vous donnera seulement la longueur du tableau, mais en réalité ce paramètre indique combien d'octets de mémoire sont totaux.

Option 1: memset( buffer, '\0', sizeof(buffer) ): vous donnera une mauvaise réponse car, buffer est char*. sizeof(buffer) ne vous donnera pas la taille d'un tableau entier, mais uniquement la taille d'une variable de pointeur.

L'option 2 est juste.

0
taufique