Initialiser un tableau d’octets à une certaine valeur, autre que la valeur par défaut null?

Je suis en train de réécrire un ancien projet en C ++, en C #.

Ma tâche consiste à réécrire le programme pour qu’il fonctionne le plus près possible de l’original.

Lors d’un tas de manipulations de fichiers, le développeur précédent qui a écrit ce programme crée une structure contenant une tonne de champs correspondant au format défini dans lequel un fichier doit être écrit, de sorte que tout ce travail est déjà fait pour moi.

Ces champs sont tous des tableaux d’octets. Le code C ++ utilise alors memset pour définir cette structure entière sur tous les espaces ( 0x20 ). Une ligne de code. Facile.

Ceci est très important car l’utilitaire que ce fichier va éventuellement attend attend le fichier dans ce format. Ce que j’ai dû faire, c’est de changer cette structure en une classe en C #, mais je ne peux pas trouver un moyen d’initialiser facilement chacun de ces tableaux d’octets à tous les caractères d’espace.

Ce que j’ai fini par faire, c’est ceci dans le constructeur de la classe:

 //Initialize all of the variables to spaces. int index = 0; foreach (byte b in UserCode) { UserCode[index] = 0x20; index++; } 

Cela fonctionne bien, mais je suis sûr qu’il doit y avoir un moyen plus simple de le faire. Lorsque le tableau est défini sur UserCode = new byte[6] dans le constructeur, le tableau d’octets est automatiquement initialisé aux valeurs NULL par défaut. N’y a-t-il pas moyen que je puisse faire en sorte que tous les espaces soient déclarés, de sorte que lorsque j’appelle le constructeur de ma classe, il est initialisé immédiatement comme ceci? Ou une fonction similaire à memset ?

Pour les petits tableaux, utilisez la syntaxe d’initialisation des tableaux:

 var sevenItems = new byte[] { 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 }; 

Pour les grandes baies, utilisez une norme for boucle. C’est le moyen le plus lisible et efficace de le faire:

 var sevenThousandItems = new byte[7000]; for (int i = 0; i < sevenThousandItems.Length; i++) { sevenThousandItems[i] = 0x20; } 

Bien sûr, si vous avez besoin de faire cela, vous pouvez créer une méthode d’aide pour garder votre code concis:

 byte[] sevenItems = CreateSpecialByteArray(7); byte[] sevenThousandItems = CreateSpecialByteArray(7000); // ... public static byte[] CreateSpecialByteArray(int length) { var arr = new byte[length]; for (int i = 0; i < arr.Length; i++) { arr[i] = 0x20; } return arr; } 

Utilisez ceci pour créer le tableau en premier lieu:

 byte[] array = Enumerable.Repeat((byte)0x20, ).ToArray(); 

Remplacez par la taille de tableau souhaitée.

Vous pouvez utiliser Enumerable.Repeat ()

Tableau de 100 éléments initialisés à 0x20:

 byte[] arr1 = Enumerable.Repeat(0x20,100).ToArray(); 
 var array = Encoding.ASCII.GetBytes(new ssortingng(' ', 100)); 

Si vous devez initialiser un petit tableau, vous pouvez utiliser:

 byte[] smallArray = new byte[] { 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 }; 

Si vous avez un plus grand tableau, vous pouvez utiliser:

 byte[] bitBiggerArray Enumerable.Repeat(0x20, 7000).ToArray(); 

Ce qui est simple et facile à lire pour le prochain gars / fille. Et sera assez rapide 99,9% du temps. (Normalement sera le BestOption ™)

Cependant, si vous avez vraiment besoin de super rapidité, appeler la méthode memset optimisée, en utilisant P / invoke, est pour vous: (Ici, vous avez une classe agréable à utiliser)

 public static class Superfast { [DllImport("msvcrt.dll", EntryPoint = "memset", CallingConvention = CallingConvention.Cdecl, SetLastError = false)] private static extern IntPtr MemSet(IntPtr dest, int c, int count); //If you need super speed, calling out to M$ memset optimized method using P/invoke public static byte[] InitByteArray(byte fillWith, int size) { byte[] arrayBytes = new byte[size]; GCHandle gch = GCHandle.Alloc(arrayBytes, GCHandleType.Pinned); MemSet(gch.AddrOfPinnedObject(), fillWith, arrayBytes.Length); return arrayBytes; } } 

Usage:

 byte[] oneofManyBigArrays = Superfast.InitByteArray(0x20,700000); 

Peut-être que cela pourrait être utile?

Quel est l’équivalent de memset en C #?

http://techmikael.blogspot.com/2009/12/filling-array-with-default-value.html

Les gars avant moi vous ont donné votre réponse. Je veux juste signaler votre mauvaise utilisation de la boucle foreach. Voir, puisque vous devez incrémenter la norme d’index “for loop” serait non seulement plus compact, mais aussi plus efficace (“foreach” fait beaucoup de choses sous le capot):

 for (int index = 0; index < UserCode.Length; ++index) { UserCode[index] = 0x20; } 

Le moyen le plus rapide de le faire est d’utiliser l’API:

bR = 0xFF;

RtlFillMemory (pBuffer, nFileLen, bR);

utiliser un pointeur vers un tampon, la longueur à écrire et l’octet codé. Je pense que le moyen le plus rapide de le faire en code géré (beaucoup plus lent) est de créer un petit bloc d’octets initialisés, puis d’utiliser Buffer.Blockcopy pour les écrire dans le tableau d’octets d’une boucle. Je l’ai jeté ensemble mais je ne l’ai pas testé, mais vous avez l’idée:

 long size = GetFileSize(FileName); // zero byte const int blocksize = 1024; // 1's array byte[] ntemp = new byte[blocksize]; byte[] nbyte = new byte[size]; // init 1's array for (int i = 0; i < blocksize; i++) ntemp[i] = 0xff; // get dimensions int blocks = (int)(size / blocksize); int remainder = (int)(size - (blocks * blocksize)); int count = 0; // copy to the buffer do { Buffer.BlockCopy(ntemp, 0, nbyte, blocksize * count, blocksize); count++; } while (count < blocks); // copy remaining bytes Buffer.BlockCopy(ntemp, 0, nbyte, blocksize * count, remainder); 

Juste pour développer ma réponse, une manière plus simple de le faire serait probablement:

 PopulateByteArray(UserCode, 0x20); 

qui appelle:

 public static void PopulateByteArray(byte[] byteArray, byte value) { for (int i = 0; i < byteArray.Length; i++) { byteArray[i] = value; } } 

Cela présente l'avantage d'une boucle efficace (mention de la réponse de gwiazdorrr) et d'un bel appel si elle est très utilisée. Et beaucoup plus d'un coup d'œil lisible que l'énumération que je pense personnellement. 🙂

Vous pouvez utiliser un initialiseur de collection :

 UserCode = new byte[]{0x20,0x20,0x20,0x20,0x20,0x20}; 

Cela fonctionnera mieux que Repeat si les valeurs ne sont pas identiques.

Cette fonction est beaucoup plus rapide qu’une boucle for pour remplir un tableau.

La commande Array.Copy est une fonction de copie de mémoire très rapide. Cette fonction tire parti de cela en appelant à plusieurs resockets la commande Array.Copy et en doublant la taille de ce que nous copions jusqu’à ce que le tableau soit plein.

J’en discute sur mon blog à http://coding.grax.com/2013/06/fast-array-fill-function-revisited.html

Notez que cela serait facile à intégrer dans une méthode d’extension en ajoutant simplement le mot “this” aux déclarations de méthode, c’est-à-dire à public static void ArrayFill(this T[] arrayToFill ...

 public static void ArrayFill(T[] arrayToFill, T fillValue) { // if called with a single value, wrap the value in an array and call the main function ArrayFill(arrayToFill, new T[] { fillValue }); } public static void ArrayFill(T[] arrayToFill, T[] fillValue) { if (fillValue.Length >= arrayToFill.Length) { throw new ArgumentException("fillValue array length must be smaller than length of arrayToFill"); } // set the initial array value Array.Copy(fillValue, arrayToFill, fillValue.Length); int arrayToFillHalfLength = arrayToFill.Length / 2; for (int i = fillValue.Length; i < arrayToFill.Length; i *= 2) { int copyLength = i; if (i > arrayToFillHalfLength) { copyLength = arrayToFill.Length - i; } Array.Copy(arrayToFill, 0, arrayToFill, i, copyLength); } } 

Ceci est une version plus rapide du code de la publication marquée comme réponse.

Tous les tests que j’ai effectués montrent qu’une simple boucle qui ne contient que quelque chose comme un remplissage de tableau est généralement deux fois plus rapide si elle est décrémentée ou incrémentée.

De plus, la propriété du tableau de longueur est déjà passée en tant que paramètre, il n’est donc pas nécessaire de la récupérer à partir des propriétés du tableau. Il doit également être pré-calculé et assigné à une variable locale. Les calculs de limites de boucle impliquant un accesseur de propriété recalculeront la valeur des limites avant chaque itération de la boucle.

 public static byte[] CreateSpecialByteArray(int length) { byte[] array = new byte[length]; int len = length - 1; for (int i = len; i >= 0; i--) { array[i] = 0x20; } return array; } 

Vous pouvez accélérer l’initialisation et simplifier le code en utilisant la classe Parallel (.NET 4 et plus récent):

 public static void PopulateByteArray(byte[] byteArray, byte value) { Parallel.For(0, byteArray.Length, i => byteArray[i] = value); } 

Vous pouvez bien sûr créer le tableau en même temps:

 public static byte[] CreateSpecialByteArray(int length, byte value) { var byteArray = new byte[length]; Parallel.For(0, length, i => byteArray[i] = value); return byteArray; }