Answers:
memset(array, 0, sizeof(array[0][0]) * m * n);
其中m
和n
是二维数组的宽度和高度(在您的示例中,您有一个正方形二维数组,所以m == n
)。
memset
,而不是在崩溃,因为您提到过也将零行归零。
int d0=10, d1=20; int arr[d0][d1]
,并按memset(arr, 0, sizeof arr);
预期工作(gcc 3.4.6,使用-std=c99 -Wall
标志进行编译)。我意识到“可以在我的机器上工作”是指深蹲,但memset(arr, 0, sizeof arr);
应该可以工作。sizeof arr
应该返回整个数组使用的字节数(d0 * d1 * sizeof(int))。 sizeof array[0] * m * n
不会给您正确的数组大小。
int array[][10]
,则sizeof(array) == sizeof(int*)
由于第一维的大小未知。OP没有指定如何获取数组。
如果array
确实是数组,则可以使用以下方法“将其归零”:
memset(array, 0, sizeof array);
但是,您应该知道两点:
array
确实是“二维数组”(即为T array[M][N];
某种类型声明了)时才有效T
。array
声明的范围内起作用。如果将其传递给函数,则名称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]
是array的大小arr[0]
,它是“的数组[5] int
”。它不是an的大小int *
,因为“衰减”仅发生在第一级,这就是为什么我们需要声明f()
为采用指向正确大小的数组的指针的原因。
因此,正如我所说,只有满足上述两个条件,您的原始工作才能起作用。如果没有,您将需要做其他人说的话:
memset(array, 0, m*n*sizeof array[0][0]);
最后,严格意义上讲,您发布memset()
的for
循环并不等效。可能存在(并且曾经存在过)某些类型的“所有位为零”不等于零的编译器,例如指针和浮点值。我怀疑您是否需要为此担心。
memset(array, 0, n*n*sizeof array[0][0]);
我猜你的意思是m*n
不是n*n
正确的?
memset
在字节(字符)级别工作。由于基本表示形式中的字节数相同1
或2
不同,因此您不能使用memset
。
int
您的系统上为4字节”,以便读者可以轻松地计算总和。
好吧,最快的方法就是根本不做。
我知道这听起来有些奇怪,这是一些伪代码:
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
这不需要清除数组,但仍然可以使用。这将比清除阵列快得多。就像我说的,最快的方法是一开始就不要这样做。
如果您真的非常着迷于速度(而不是那么着迷于便携性),那么我认为绝对最快的方法是使用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/zh-cn/library/kcwz153a (v=vs.80) .aspx
如果您使用初始化数组malloc
,请calloc
改用; 它将免费将您的数组清零。(显然,性能与memset相同,只需要更少的代码。)
memset(array, 0, sizeof(int [n][n]));
发生这种情况是因为sizeof(array)为您提供了array指向的对象的分配大小。(数组只是指向多维数组第一行的指针)。但是,您分配了j个大小为i的数组。因此,您需要将sizeof(array)返回的一行的大小乘以您分配的行数,例如:
bzero(array, sizeof(array) * j);
还要注意,sizeof(array)仅适用于静态分配的数组。对于动态分配的数组,您可以编写
size_t arrayByteSize = sizeof(int) * i * j;
int *array = malloc(array2dByteSite);
bzero(array, arrayByteSize);
sizeof
操作符,array
不是指针(如果已声明为数组)。请参阅我的答案作为示例。