带有以下声明
int array[ROW][COLUMN]={0};
我得到全零的数组,但有以下一个
int array[ROW][COLUMN]={1};
我没有得到所有一个值的数组。默认值仍然是 0。
为什么会出现这种行为以及如何使用全 1 进行初始化?
编辑:我刚刚明白使用memset
with value as 1,会将每个字节设置为 1,因此每个数组单元格的实际值不会是 1,而是16843009
. 如何将其设置为 1?
带有以下声明
int array[ROW][COLUMN]={0};
我得到全零的数组,但有以下一个
int array[ROW][COLUMN]={1};
我没有得到所有一个值的数组。默认值仍然是 0。
为什么会出现这种行为以及如何使用全 1 进行初始化?
编辑:我刚刚明白使用memset
with value as 1,会将每个字节设置为 1,因此每个数组单元格的实际值不会是 1,而是16843009
. 如何将其设置为 1?
您会得到这种行为,因为这并不int array [ROW][COLUMN] = {1};
意味着“将所有项目设置为一个”。让我尝试逐步解释这是如何工作的。
初始化数组的明确的、过于清晰的方法是这样的:
#define ROW 2
#define COLUMN 2
int array [ROW][COLUMN] =
{
{0, 0},
{0, 0}
};
但是,C 允许您省略数组(或结构/联合)中的一些项目。例如,您可以编写:
int array [ROW][COLUMN] =
{
{1, 2}
};
这意味着,将第一个元素初始化为 1 和 2,其余元素“就好像它们具有静态存储持续时间一样”。C 中有一条规则说,所有静态存储持续时间的对象,没有被程序员显式初始化,必须设置为零。
所以在上面的例子中,第一行设置为 1,2,下一行设置为 0,0,因为我们没有给它们任何明确的值。
接下来,C 中有一条规则允许松散的大括号样式。第一个例子也可以写成
int array [ROW][COLUMN] = {0, 0, 0, 0};
虽然这当然是糟糕的风格,但更难阅读和理解。但是这条规则很方便,因为它允许我们写
int array [ROW][COLUMN] = {0};
这意味着:“将第一行中的第一列初始化为 0,以及所有其他项目,就好像它们具有静态存储持续时间一样,即将它们设置为零。”
因此,如果您尝试
int array [ROW][COLUMN] = {1};
它的意思是“将第一行中的第一列初始化为 1,并将所有其他项设置为零”。
如果要将数组初始化为,-1
则可以使用以下命令,
memset(array, -1, sizeof(array[0][0]) * row * count)
但这会起作用0
,而且-1
只有
int array[ROW][COLUMN]={1};
这仅将第一个元素初始化为 1。其他所有元素都为 0。
在第一种情况下,您正在做同样的事情 - 将第一个元素初始化为 0,其余的默认为 0。
原因很简单:对于一个数组,编译器会初始化你没有用 0 指定的每个值。
使用char
数组可以memset
设置每个字节,但这通常不适用于int
数组(尽管它适用于 0)。
一般for
循环会很快做到这一点:
for (int i = 0; i < ROW; i++)
for (int j = 0; j < COLUMN; j++)
array[i][j] = 1;
或者可能更快(取决于编译器)
for (int i = 0; i < ROW*COLUMN; i++)
*((int*)a + i) = 1;
要使用零初始化二维数组,请使用以下方法:
int arr[n][m] = {};
注意:上述方法仅适用于初始化为 0;
请注意,GCC 对指定的初始化符号有一个扩展,这对上下文非常有用。它也被允许clang
不加注释(部分是因为它试图与 GCC 兼容)。
扩展符号允许您使用...
以下值来指定要初始化的元素范围。例如:
#include <stdio.h>
enum { ROW = 5, COLUMN = 10 };
int array[ROW][COLUMN] = { [0 ... ROW-1] = { [0 ... COLUMN-1] = 1 } };
int main(void)
{
for (int i = 0; i < ROW; i++)
{
for (int j = 0; j < COLUMN; j++)
printf("%2d", array[i][j]);
putchar('\n');
}
return 0;
}
不出所料,输出是:
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
请注意,Fortran 66 (Fortran IV) 对数组的初始化程序有重复计数;当指定的初始化器被添加到语言中时,C 没有得到它们总是让我感到奇怪。并且 Pascal 使用0..9
符号来指定从 0 到 9 的范围,包括 0 到 9,但是 C 不用..
作标记,所以没有使用也就不足为奇了。
请注意,...
符号周围的空格本质上是强制性的;如果它们附加到数字,则该数字被解释为浮点数。例如,0...9
将被标记为0.
, .
, .9
,并且浮点数不允许作为数组下标。使用命名常量,...ROW-1
不会造成麻烦,但最好养成安全的习惯。
附加物:
我顺便注意到 GCC 7.3.0 拒绝:
int array[ROW][COLUMN] = { [0 ... ROW-1] = { [0 ... COLUMN-1] = { 1 } } };
1
标量初始化器( )周围有一组额外的大括号error: braces around scalar initializer [-Werror]
。我不确定这是正确的,因为您通常可以在标量 in 周围指定大括号int a = { 1 };
,这是标准明确允许的。我也不确定这是否不正确。
我还想知道是否会有更好的表示法[0]...[9]
——它是明确的,不能与任何其他有效语法混淆,并避免与浮点数混淆。
int array[ROW][COLUMN] = { [0]...[4] = { [0]...[9] = 1 } };
也许标准委员会会考虑这一点?
改用向量数组:
vector<vector<int>> array(ROW, vector<int>(COLUMN, 1));
char grid[row][col];
memset(grid, ' ', sizeof(grid));
这是为了将 char 数组元素初始化为空格字符。