La façon la plus rapide pour mettre à zéro un tableau 2d en C?
Je tiens à plusieurs reprises à zéro un grand tableau 2d en C. C'est ce que je fais en ce 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 tableaux 1D. Quand je printf le contenu du tableau 2D, la première ligne est de zéros, mais j'ai eu une charge aléatoire d'un grand nombre et il se bloque.
Vous devez vous connecter pour publier un commentaire.
Où
m
etn
sont la largeur et la hauteur du tableau à deux dimensions (dans votre exemple, vous avez un carré tableau à deux dimensions, de sortem == n
).memset
, parce que vous avez mentionné s'écraser à partir de zéro seulement une ligne trop.memset
code,sizeof(array[0] * n)
donne la taille du résultat de l'expressionarray[0] * n
, qui est probablement le même quesizeof(array[0])
.int d0=10, d1=20; int arr[d0][d1]
, etmemset(arr, 0, sizeof arr);
a fonctionné comme prévu (gcc 3.4.6, compilé avec-std=c99 -Wall
drapeaux). Je me rends compte que "ça fonctionne sur ma machine" signifie diddly squat, maismemset(arr, 0, sizeof arr);
devrait ont travaillé.sizeof arr
devrait retourne le nombre d'octets utilisés par l'ensemble de la matrice (d0 * d1 * sizeof(int)).sizeof array[0] * m * n
ne vous donnera pas la bonne taille de la matrice.int array[][10]
, puissizeof(array) == sizeof(int*)
puisque la taille de la première dimension n'est pas connue. L'OP n'a pas de spécifier comment le tableau a été obtenu.bzero
ing un tableau.Si
array
est vraiment un tableau, alors vous pouvez zéro "sortir" avec:Mais il ya deux points que vous devez savoir:
array
est vraiment un "deux-d tableau", c'est à dire, a été déclaréT array[M][N];
pour certains type deT
.array
a été déclarée. Si vous passez à une fonction, puis sur le nomarray
se désintègre à un pointeur, etsizeof
ne vous donnera pas la taille du tableau.Faisons une expérience:
Sur ma machine, le ci-dessus imprime:
Même si
arr
est un tableau, il se désintègre à un pointeur vers son premier élément lorsqu'il est passé àf()
, et donc la taille imprimé enf()
sont "mauvais". Aussi, dansf()
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" n'arrive qu'au premier niveau, et c'est pourquoi nous avons besoin de déclarerf()
que de prendre un pointeur vers un tableau de la bonne taille.Donc, comme je l'ai dit, ce que vous faisiez à l'origine ne fonctionne que si les deux conditions ci-dessus sont remplies. Si non, vous aurez besoin de faire ce que les autres ont dit:
Enfin,
memset()
et lafor
boucle que vous avez posté ne sont pas équivalentes au sens strict. Il pourrait être (et ont été) les 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 avez besoin de s'inquiéter que si.memset(array, 0, n*n*sizeof array[0][0]);
Je suppose que tu veux direm*n
pasn*n
droit?memset
fonctionne à l'octet (char) niveau. Depuis1
ou2
n'ont pas la même octets dans la représentation sous-jacente, vous ne pouvez pas faire cela avecmemset
.Bien, la façon la plus rapide de le faire est de ne pas le faire du tout.
Semble bizarre je sais, voici quelques pseudo-code:
En fait, c'est toujours la compensation de la matrice, mais seulement lorsque quelque chose est écrit au tableau. Ce n'est pas un gros avantage ici. Cependant, si le tableau 2D a été mis en œuvre en utilisant, par exemple, un quad arbre (pas une dynamique de l'esprit), ou un ensemble de lignes de données, alors vous pouvez le localiser l'effet de l'indicateur booléen, mais vous auriez besoin de plus de drapeaux. Dans le quad arbre il suffit de régler le vide drapeau pour le nœud racine, dans le tableau de lignes il suffit de régler l'indicateur pour chaque ligne.
Qui mène à la question "pourquoi voulez-vous plusieurs fois à zéro, un grand tableau 2d"? Qu'est-ce que le tableau est-il utilisé? Est-il un moyen de modifier le code afin que le tableau n'a pas besoin de mise à zéro?
Par exemple, si vous avez eu:
qui est, utiliser un tampon d'accumulation, puis de le changer comme cela permettrait d'améliorer la performance sans fin:
Cela ne nécessite pas que la matrice soit effacé mais fonctionne encore. Et ce sera bien plus rapide que la compensation de la matrice. Comme je l'ai dit, le moyen le plus rapide est de ne pas le faire en premier lieu.
Si vous êtes vraiment obsédé par la vitesse (et pas tellement avec la portabilité) je pense que l'absolu plus rapide façon de le faire serait d'utiliser SIMD vecteur intrinsèques. par exemple, sur les Processeurs Intel, vous pouvez utiliser ces instructions SSE2:
Chaque magasin instruction set de quatre 32 bits ints à zéro d'un seul coup.
p doit être de 16 octets aligné, mais cette restriction est également bon pour la vitesse, car il aidera le cache. L'autre limite est que p doit pointer vers une répartition de taille qui est un multiple de 16 octets, mais c'est trop cool parce qu'il nous permet de dérouler la boucle facilement.
Ont cela dans une boucle, et dérouler la boucle un peu de temps, et vous aurez un fou rapide initialiser:
Il y a aussi une variante de
_mm_storeu
qui contourne le cache (c'est à dire d'une réinitialisation de la matrice de ne pas polluer le cache) qui pourrait vous donner quelques secondaires des avantages de performance dans certaines circonstances.Voir ici pour SSE2 référence: http://msdn.microsoft.com/en-us/library/kcwz153a(v=vs. 80).aspx
Si vous initialiser le tableau avec
malloc
, utilisezcalloc
au lieu de cela; il est égal à zéro votre tableau pour gratuit. (Même perf évidemment, en tant que memset, juste moins de code pour vous.)int array[N][M] = {0};
...au moins dans GCC 4.8.
Comment a été votre tableau 2D déclaré?
Si quelque chose comme:
Vous pouvez zéro en faisant:
memset(a, 0, sizeof(char)*10*10);
fonctionne très bien pour moi. comment se fait-il?Utiliser calloc à la place de malloc . calloc lancera tous les champs à 0.
int *a = (int *)calloc(n,la taille de l'(int)) ;
//toutes les cellules d'un avoir été initialisé à 0
Je pense que la façon la plus rapide de le faire à la main est code suivant. Vous pouvez comparer la vitesse à fonction memset, mais il ne devrait pas être plus lent.
(changement de type de ptr et ptr1 pointeurs si votre type de tableau est différent alors int)
memset
pour char types.Vous pouvez essayer ce
Cela se produit parce que sizeof(tableau) vous donne la répartition de la taille de l'objet pointé par tableau. (tableau est juste un pointeur vers la première ligne de votre tableau multidimensionnel). Cependant, vous avez alloué j des tableaux de taille je. Par conséquent, vous devez multiplier la taille d'une ligne, qui est retourné par sizeof(array) avec le nombre de lignes que vous avez alloué, par exemple:
Également noter que sizeof(tableau) ne fonctionne que pour les allouée statiquement tableaux. Pour un tableau alloué dynamiquement, vous écrirez
sizeof
opérateur,array
n'est pas un pointeur (s'il a été déclaré un tableau). Voir ma réponse par un exemple.