我想在C中反复归零一个大的2d数组。这就是我现在所做的:
// 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))
但这仅适用于1D阵列。当我打印2D阵列的内容时,第一行是零,但随后我得到了一大堆随机大数字,它崩溃了。
答案 0 :(得分:161)
memset(array, 0, sizeof(array[0][0]) * m * n);
其中m
和n
是二维数组的宽度和高度(在您的示例中,您有一个方形的二维数组,因此m == n
)。
答案 1 :(得分:72)
如果array
确实是一个数组,那么你可以用“
memset(array, 0, sizeof array);
但是你应该知道两点:
array
确实是“二维数组”时才有效,即某些类型T array[M][N];
被声明为T
。array
的范围。如果您将其传递给某个函数,则名称array
decays to a pointer和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, m*n*sizeof array[0][0]);
最后,您发布的memset()
和for
循环在严格意义上并不相同。可能存在(并且已经)编译器,其中“所有位零”对于某些类型不等于零,例如指针和浮点值。我怀疑你需要担心这一点。
答案 2 :(得分:9)
嗯,最快的方法就是不要这样做。
听起来很奇怪我知道,这里有一些伪代码:
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;
}
实际上,它仍在清除阵列,但只有在向阵列写入某些内容时。这不是一个很大的优势。但是,如果使用四叉树(不是动态的一个头脑)或一组数据行来实现2D数组,那么您可以本地化布尔标志的效果,但是您需要更多的标志。在四叉树中,只需为根节点设置空标志,在行数组中为每一行设置标志。
这引出了一个问题“为什么要反复归零大型2d阵列”?用于什么数组?有没有办法更改代码,以便数组不需要归零?
例如,如果你有:
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
这不需要清除数组但仍然有效。这比清除阵列要快得多。就像我说的那样,最快的方法是首先不要这样做。
答案 3 :(得分:7)
如果你真的非常痴迷于速度(而不是可移植性),我认为绝对最快的方法是使用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字节对齐,但这种限制对速度也有好处,因为它有助于缓存。另一个限制是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);
}
还有一个_mm_storeu
的变体可以绕过缓存(即清零数组不会污染缓存),这可能会在某些情况下为您带来一些次要的性能优势。
请参阅此处获取SSE2参考:http://msdn.microsoft.com/en-us/library/kcwz153a(v=vs.80).aspx
答案 4 :(得分:5)
如果使用malloc
初始化数组,请改用calloc
;它将免费归零您的阵列。 (显然与memset相同,只需要更少的代码。)
答案 5 :(得分:3)
int array[N][M] = {0};
......至少在GCC 4.8中。
答案 6 :(得分:2)
您的2D数组是如何声明的?
如果是这样的话:
int arr[20][30];
您可以通过执行以下操作将其归零:
memset(arr, sizeof(int)*20*30);
答案 7 :(得分:1)
使用calloc而不是malloc。 calloc将所有字段都启动为0。
int * a =(int *)calloc(n,size of(int));
// a的所有单元格都已初始化为0
答案 8 :(得分:0)
memset(array, 0, sizeof(int [n][n]));
答案 9 :(得分:0)
我认为手动执行此操作的最快方法是遵循代码。你可以将它的速度与memset函数进行比较,但它不应该慢。
(如果你的数组类型不同,那么改变ptr和ptr1指针的类型)
#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]);
while(ptr < ptr1)
{
*ptr++ = 0;
}
答案 10 :(得分:0)
你可以试试这个
int array[20,30] = {{0}};
答案 11 :(得分:-2)
这是因为sizeof(array)为您提供了 array 指向的对象的分配大小。 ( array 只是指向多维数组第一行的指针)。但是,您分配了大小为 i 的 j 数组。因此,您需要将sizeof(数组)返回的一行的大小乘以您分配的行数,例如:
bzero(array, sizeof(array) * j);
另请注意,sizeof(数组)仅适用于静态分配的数组。对于动态分配的数组,您可以编写
size_t arrayByteSize = sizeof(int) * i * j;
int *array = malloc(array2dByteSite);
bzero(array, arrayByteSize);