我想知道给二维数组赋值的最优方法是什么
比如说,我想把值12赋值给下面的数组
for (int i = 0; i < m; i+++)
for (int j = 0; j < n; j++)
array[i][j] = 10
在没有for
循环的情况下,是否有更好的方法来做到这一点?
您的代码很好,可读且简单,除了一些错别字。只要确保对i
和j
使用与n
和m
相同的类型即可。
#define N 10
#define M 10
int array[M][N];
for (int i = 0; i < M; i++) {
for (int j = 0; j < N; j++)
array[i][j] = 0;
}
以这种方式编写代码的优点是它既适用于平面二维数组int array[M][N]
,也适用于数组的数组int *array[M]
以及指向数组的数组的指针int **array
。
如果数组是平面二维整数数组,且值为0
,则有另一种选择:
memset(array, 0, sizeof(array[0][0]) * M * N);
但是它只适用于非常特定的值,这些值在内存中的所有位置都用相同的字节表示。这就是0
和-1
在常规双互补体系结构中的情况,以及其他254个不太明显的值(40亿)。
您也可以初始化单行并将其复制到下面的行…
这样的优化是令人困惑的,容易出错和不必要的,因为现代优化编译器会为此生成非常有效的代码:
#define M 10
#define N 10
void clear_matrix(int array[M][N]) {
for (int i = 0; i < M; i++) {
for (int j = 0; j < N; j++)
array[i][j] = 0;
}
}
指出:
- 代码正确性总是优于优化:快速获得不正确结果的目的是什么?
- 在优化之前,始终要进行基准测试和配置,并首先关注作为明显目标的瓶颈。
- 矩阵初始化不太可能成为瓶颈。如果是,你的算法可能有问题。
- 找到一个更好的算法,降低复杂性,比微优化更有成效。
这个问题几乎无法回答。简单的测试:
#define ROWS 1000
#define COLS 4000
int arr[ROWS][COLS];
void __attribute__((noinline)) set(int val)
{
for(size_t col = 0; col < COLS; col++)
{
arr[0][col] = val;
}
for(size_t row = 1; row < ROWS; row++)
{
memcpy(arr[row], arr[0], sizeof(arr[0]));
}
}
void __attribute__((noinline)) set1(int val)
{
static int arr1[COLS];
for(size_t col = 0; col < COLS; col++)
{
arr1[col] = val;
}
for(size_t row = 0; row < ROWS; row++)
{
memcpy(arr[row], arr1, sizeof(arr1));
}
}
void __attribute__((noinline)) set2(int val)
{
for(size_t row = 0; row < ROWS; row++)
for(size_t col = 0; col < COLS; col++)
{
arr[row][col] = val;
}
}
int main(void)
{
clock_t begin, end;
double time_spent;
begin = clock();
for(int x = 0; x < 1000; x++)
{
set(x);
}
end = clock();
time_spent = (double)(end - begin) / CLOCKS_PER_SEC;
printf("%fn", time_spent);
begin = clock();
for(int x = 0; x < 1000; x++)
{
set1(x);
}
end = clock();
time_spent = (double)(end - begin) / CLOCKS_PER_SEC;
printf("%fn", time_spent);
begin = clock();
for(int x = 0; x < 1000; x++)
{
set2(x);
}
end = clock();
time_spent = (double)(end - begin) / CLOCKS_PER_SEC;
printf("%fn", time_spent);
}
Godbolt表明循环方法是最快的:https://godbolt.org/z/K9Gcbs
1.162777
1.009047
0.973361
但是通过ubuntu 20.4 64位测试(相同的编译器版本,相同的编译器选项)给出了相反的结果。
0.542433
0.502667
0.936434
所以结论是:永远是基准。不要相信观点和神话。