Je veux remettre à zéro à plusieurs reprises un grand tableau 2d en C.C'est ce que je fais pour le moment:
// Array of size n * m, where n may not equal m
for(j = 0; j < n; j++)
{
for(i = 0; i < m; i++)
{
array[i][j] = 0;
}
}
J'ai essayé d'utiliser memset:
memset(array, 0, sizeof(array))
Mais cela ne fonctionne que pour les baies 1D. Quand j'imprime le contenu du tableau 2D, la première ligne est des zéros, mais ensuite j'ai eu une charge de grands nombres aléatoires et ça plante.
memset
, parce que vous avez mentionné le crash de la mise à zéro d'une seule ligne aussi.int d0=10, d1=20; int arr[d0][d1]
, et amemset(arr, 0, sizeof arr);
fonctionné comme prévu (gcc 3.4.6, compilé avec des-std=c99 -Wall
indicateurs). Je me rends compte que "ça marche sur ma machine" veut dire s'accroupir, maismemset(arr, 0, sizeof arr);
aurait dû marcher.sizeof arr
doit renvoyer le nombre d'octets utilisés par le tableau entier (d0 * d1 * sizeof (int)).sizeof array[0] * m * n
ne vous donnera pas la taille correcte du tableau.int array[][10]
, alorssizeof(array) == sizeof(int*)
puisque la taille de la première dimension n'est pas connue. L'OP n'a pas précisé comment le tableau a été obtenu.Si
array
est vraiment un tableau, alors vous pouvez le "remettre à zéro" avec:Mais il y a deux points que vous devez savoir:
array
est vraiment un "tableau à deux d", c'est-à-dire a été déclaréT array[M][N];
pour un typeT
.array
été déclaré. Si vous le passez à une fonction, le nomarray
se désintègre en pointeur etsizeof
ne vous donnera pas la taille du tableau.Faisons une expérience:
Sur ma machine, les impressions ci-dessus:
Même s'il
arr
s'agit d'un tableau, il se désintègre en un pointeur vers son premier élément lorsqu'il est passé àf()
, et par conséquent, les tailles impriméesf()
sont "incorrectes". En outre,f()
la taille dearr[0]
est la taille du tableauarr[0]
, qui est un "tableau [5] deint
". Ce n'est pas la taille d'unint *
, parce que la "décomposition" ne se produit qu'au premier niveau, et c'est pourquoi nous devons déclarerf()
comme prenant un pointeur vers un tableau de taille correcte.Donc, comme je l'ai dit, ce que vous faisiez à l'origine ne fonctionnera que si les deux conditions ci-dessus sont remplies. Sinon, vous devrez faire ce que les autres ont dit:
Enfin,
memset()
et lafor
boucle que vous avez postée ne sont pas équivalentes au sens strict. Il pourrait y avoir (et il y a eu) des compilateurs où «tous les bits à zéro» n'est pas égal à zéro pour certains types, tels que les pointeurs et les valeurs à virgule flottante. Je doute que vous ayez à vous en préoccuper.la source
memset(array, 0, n*n*sizeof array[0][0]);
Je suppose que tu veux direm*n
pasn*n
bien?memset
fonctionne au niveau de l'octet (char). Puisque1
ou2
n'ont pas les mêmes octets dans la représentation sous-jacente, vous ne pouvez pas faire cela avecmemset
.int
sur votre système, il y a 4 octets" quelque part avant l'exemple de travail minimal, afin que le lecteur puisse facilement calculer les sommes.Eh bien, le moyen le plus rapide de le faire est de ne pas le faire du tout.
Cela semble étrange, je sais, voici un pseudocode:
En fait, il efface toujours le tableau, mais seulement lorsque quelque chose est écrit dans le tableau. Ce n'est pas un gros avantage ici. Cependant, si le tableau 2D a été implémenté en utilisant, par exemple, un quadruple arbre (pas un esprit dynamique) ou une collection de lignes de données, vous pouvez localiser l'effet du drapeau booléen, mais vous auriez besoin de plus d'indicateurs. Dans l'arbre quadruple, définissez simplement le drapeau vide pour le nœud racine, dans le tableau de lignes, définissez simplement le drapeau pour chaque ligne.
Ce qui conduit à la question "pourquoi voulez-vous remettre à zéro à plusieurs reprises un grand tableau 2D"? À quoi sert le tableau? Existe-t-il un moyen de modifier le code afin que le tableau ne nécessite pas de mise à zéro?
Par exemple, si vous aviez:
autrement dit, utilisez-le pour un tampon d'accumulation, puis le changer comme cela améliorerait les performances sans fin:
Cela ne nécessite pas d'effacer le tableau mais fonctionne toujours. Et ce sera beaucoup plus rapide que d'effacer le tableau. Comme je l'ai dit, le moyen le plus rapide est de ne pas le faire en premier lieu.
la source
Si vous êtes vraiment, vraiment obsédé par la vitesse (et pas tant par la portabilité), je pense que le moyen le plus rapide de le faire serait d'utiliser les éléments intrinsèques du vecteur SIMD. par exemple sur les processeurs Intel, vous pouvez utiliser ces instructions SSE2:
Chaque instruction de stockage mettra quatre entiers 32 bits à zéro en un seul coup.
p doit être aligné sur 16 octets, mais cette restriction est également bonne pour la vitesse car elle aidera le cache. L'autre restriction est que p doit pointer vers une taille d'allocation qui est un multiple de 16 octets, mais c'est cool aussi car cela nous permet de dérouler la boucle facilement.
Ayez ceci dans une boucle, et déroulez la boucle plusieurs fois, et vous aurez un initialiseur fou et rapide:
Il existe également une variante
_mm_storeu
qui contourne le cache (c'est-à-dire que la remise à zéro du tableau ne polluera pas le cache) qui pourrait vous donner des avantages de performances secondaires dans certaines circonstances.Voir ici pour la référence SSE2: http://msdn.microsoft.com/en-us/library/kcwz153a(v=vs.80).aspx
la source
Si vous initialisez le tableau avec
malloc
, utilisez à lacalloc
place; il mettra à zéro votre tableau gratuitement. (Même performance évidemment que memset, juste moins de code pour vous.)la source
int array[N][M] = {0};
... au moins dans GCC 4.8.
la source
Comment votre tableau 2D a-t-il été déclaré?
Si c'est quelque chose comme:
Vous pouvez le mettre à zéro en faisant:
la source
memset(a, 0, sizeof(char)*10*10);
fonctionne très bien pour moi. , comment ça se passe?Utilisez calloc au lieu de malloc. calloc initialisera tous les champs à 0.
int * a = (int *) calloc (n, taille de (int));
// toutes les cellules de a ont été initialisées à 0
la source
Je pense que le moyen le plus rapide de le faire à la main est de suivre le code. Vous pouvez comparer sa vitesse à la fonction memset, mais elle ne devrait pas être plus lente.
(changez le type des pointeurs ptr et ptr1 si votre type de tableau est différent de int)
la source
memset
pour les types char.la source
Vous pouvez essayer ceci
la source
Cela se produit car sizeof (array) vous donne la taille d'allocation de l'objet pointé par array . ( tableau est juste un pointeur vers la première ligne de votre tableau multidimensionnel). Cependant, vous avez alloué des tableaux j de taille i . Par conséquent, vous devez multiplier la taille d'une ligne, qui est retournée par sizeof (tableau) par le nombre de lignes que vous avez allouées, par exemple:
Notez également que sizeof (array) ne fonctionnera que pour les tableaux alloués statiquement. Pour un tableau alloué dynamiquement, vous écririez
la source
sizeof
opérateur,array
n'est pas un pointeur (s'il a été déclaré un tableau). Voir ma réponse pour un exemple.