最快的方法来清零C中的二维数组?

我想用C重复一个大的二维数组。这就是我现在所做的:

// 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; } } 

我试过使用memset:

 memset(array, 0, sizeof(array)) 

但是这只适用于一维数组。 当我打印二维数组的内容时,第一行是零,但随后我得到了大量的随机数,它崩溃了。

 memset(array, 0, sizeof(array[0][0]) * m * n); 

其中mn是二维数组的宽度和高度(在你的例子中,你有一个正方形的二维数组,所以m == n )。

如果array确实是一个数组,那么你可以用下面的方法“清零”:

 memset(array, 0, sizeof array); 

但有两点你应该知道:

  • 这只适用于array是真的“二维数组”,即被声明为T array[M][N]; 对于某些types的T
  • 它只适用于声明array的范围。 如果你将它传递给一个函数,那么name array 会衰减到一个指针 ,而sizeof将不会给你数组的大小。

让我们做一个实验:

 #include <stdio.h> void f(int (*arr)[5]) { printf("f: sizeof arr: %zu\n", sizeof arr); printf("f: sizeof arr[0]: %zu\n", sizeof arr[0]); printf("f: sizeof arr[0][0]: %zu\n", sizeof arr[0][0]); } int main(void) { int arr[10][5]; printf("main: sizeof arr: %zu\n", sizeof arr); printf("main: sizeof arr[0]: %zu\n", sizeof arr[0]); printf("main: sizeof arr[0][0]: %zu\n\n", sizeof arr[0][0]); f(arr); return 0; } 

在我的机器上,上面的打印:

 main: sizeof arr: 200 main: sizeof arr[0]: 20 main: sizeof arr[0][0]: 4 f: sizeof arr: 8 f: sizeof arr[0]: 20 f: sizeof arr[0][0]: 4 

即使arr是一个数组,当它传递给f()时,会衰减到指向其第一个元素的指针,因此f()中打印的大小是“错误的”。 另外,在f()中, arr[0]的大小是数组arr[0]的大小,它是“ int数组[5]”。 它不是int *的大小,因为“衰减”只发生在第一级,所以我们需要声明f()是指向一个正确大小的数组的指针。

所以,正如我所说的,只有满足上述两个条件,你原来所做的才会起作用。 如果不是的话,你需要做别人所说的话:

 memset(array, 0, n*n*sizeof array[0][0]); 

最后, memset()和你发布的for循环在严格意义上是不等价的。 可能有(和已经)编译器的“所有位零”不等于零的某些types,如指针和浮点值。 我怀疑你需要担心。

那么最快的方法就是不要这样做。

听起来奇怪,我知道,这是一些伪代码:

 int array [][]; bool array_is_empty; void ClearArray () { array_is_empty = true; } int ReadValue (int x, int y) { return array_is_empty ? 0 : array [x][y]; } void SetValue (int x, int y, int value) { if (array_is_empty) { memset (array, 0, number of byte the array uses); array_is_empty = false; } array [x][y] = value; } 

事实上,它仍然清除数组,但只有当某些东西正在写入数组。 这在这里不是一个很大的优势。 但是,如果二维数组是使用四叉树(而不是一个dynamic的头脑)或一组数据实现的,那么可以本地化布尔标志的效果,但是您需要更多的标志。 在四叉树中,只需为根节点设置空标志,在行数组中只需设置每行的标志即可。

这导致了“为什么要重复一个大的二维数组”的问题? 数组用于什么? 有没有办法改变代码,使数组不需要调零?

例如,如果你有:

 clear array for each set of data for each element in data set array += element 

也就是说,使用它作为累积缓冲区,然后像这样改变会提高性能无止境:

  for set 0 and set 1 for each element in each set array = element1 + element2 for remaining data sets for each element in data set array += element 

这不需要数组被清除,但仍然有效。 这将比清除数组快得多。 就像我说的,最快的方法就是不要把它放在第一位。

如果你真的对速度非常痴迷(而不是那么多的可移植性),我认为最简单的方法就是使用SIMD向量内在函数。 例如在Intel CPU上,您可以使用这些SSE2指令:

 __m128i _mm_setzero_si128 (); // Create a quadword with a value of 0. void _mm_storeu_si128 (__m128i *p, __m128i a); // Write a quadword to the specified address. 

每个存储指令将在一次命中中将四个32位整数设置为零。

p必须是16字节alignment的,但这个限制对于速度也是有好处的,因为它会帮助caching。 另一个限制是p必须指向一个16字节的倍数的分配大小,但这也很酷,因为它允许我们轻松地展开循环。

把它放在一个循环中,然后展开循环几次,你将拥有一个疯狂的快速初始化器:

 // Assumes int is 32-bits. const int mr = roundUpToNearestMultiple(m, 4); // This isn't the optimal modification of m and n, but done this way here for clarity. const int nr = roundUpToNearestMultiple(n, 4); int i = 0; int array[mr][nr] __attribute__ ((aligned (16))); // GCC directive. __m128i* px = (__m128i*)array; const int incr = s >> 2; // Unroll it 4 times. const __m128i zero128 = _mm_setzero_si128(); for(i = 0; i < s; i += incr) { _mm_storeu_si128(px++, zero128); _mm_storeu_si128(px++, zero128); _mm_storeu_si128(px++, zero128); _mm_storeu_si128(px++, zero128); } 

还有一个绕过caching的variables_mm_storeu (即调零数​​组不会污染caching),在某些情况下可以给你一些次要的性能好处。

在这里看到SSE2参考: http : //msdn.microsoft.com/en-us/library/kcwz153a (v=vs.80) .aspx

如果使用malloc初始化数组,请使用calloc 。 它将免费为你的数组。 (与memset显然相同,只是更less的代码。)

int array[N][M] = {0};

至less在GCC 4.8中

你的2D数组是如何声明的?

如果这样的话:

 int arr[20][30]; 

您可以通过以下步骤将其归零:

 memset(arr, sizeof(int)*20*30); 

我认为最快的方法是手动编写代码。 你可以将它的速度与memset函数进行比较,但速度不会太慢。

(如果您的数组types不同,则更改ptr和ptr1指针的types,然后int)

 #define SIZE_X 100 #define SIZE_Y 100 int *ptr, *ptr1; ptr = &array[0][0]; ptr1 = ptr + SIZE_X*SIZE_Y*sizeof(array[0][0]); 

而(ptr <ptr1)
 {
     * ptr ++ = 0;
 }
 memset(array, 0, sizeof(int [n][n])); 

你可以试试这个

 int array[20,30] = {{0}}; 

使用calloc而不是malloc。 calloc将启动所有字段为0。

int * a =(int *)calloc(n,size(int));

// a的所有单元格已被初始化为0

发生这种情况是因为sizeof(array)给了你数组指向的对象的分配大小。 ( 数组只是指向multidimensional array的第一行的指针)。 但是,您分配了j个大小为i的数组。 因此,您需要将sizeof(array)返回的一行的大小乘以分配的行数,例如:

 bzero(array, sizeof(array) * j); 

还要注意sizeof(array)只能用于静态分配的数组。 对于一个dynamic分配的数组,你会写

 size_t arrayByteSize = sizeof(int) * i * j; int *array = malloc(array2dByteSite); bzero(array, arrayByteSize);