用一个值初始化整个二维数组

107

使用以下声明

int array[ROW][COLUMN]={0};

我得到了一个全为零的数组,但是有一个例外:

int array[ROW][COLUMN]={1};

我不理解所有元素都为1的数组。默认值仍然是0。

为什么会这样以及如何初始化为全1?

编辑:我刚明白使用值为1的memset将每个字节设置为1,因此每个数组单元格的实际值不是1而是16843009。如何将其设置为1?


1
@ckruse:问题不在于“如何”,而在于“为什么”。 - masoud
@Kraken,你编辑中的问题可能应该作为一个独立的问题发布,而不是与这个问题混在一起。 - Lundin
@Lundin 是的,我想我需要这样做。谢谢 :) - Kraken
1
@Kraken 实际上我在这里找到了那个问题 here。我建议按照我的答案所建议的去做(当然!),而不是依赖于GCC扩展。 - Lundin
@Lundin 正在研究中。 :) - Kraken
显示剩余9条评论
7个回答

151

你会得到这种结果,是因为int array [ROW][COLUMN] = {1};不是表示“将所有项目设置为1”。让我逐步解释一下它的工作原理。

初始化数组的明确、过于清晰的方式如下:

#define ROW 2
#define COLUMN 2

int array [ROW][COLUMN] =
{
  {0, 0},
  {0, 0}
};

然而,在C语言中,允许您省略数组(或struct/union)中的一些项。例如,您可以写成:

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,将所有其他项目设置为零”。

如果想要将整个数组初始化为特定值/值,请参见https://dev59.com/-2Yr5IYBdhLWcg3wssGP#13488596


3
谢谢您的问题,我可以帮您将整个数组初始化为1。考虑到您的行和列都有数百个元素,需要保持简洁高效。 - Kraken
1
@Kraken 通过宏技巧实现。请参见此处 - Lundin
@user1794469 不,你不需要。 - Lundin
1
@user1794469 是的,这很好,因为在大多数情况下跳过花括号是不好的做法。但编译器不必给出诊断。关于这种情况的好坏实践,请参阅我对此问题的答案。 - Lundin
1
@TomMcLean 我已将上面评论中的链接添加到答案中。 - Lundin
显示剩余3条评论

55
如果您想将数组初始化为-1,则可以使用以下方法:
memset(array, -1, sizeof(array[0][0]) * row * count)

但这仅适用于0-1


27
使用 "sizeof(array)" 比使用 "sizeof(array[0][0]) * row * count" 更简单。 - Vladyslav Savchenko
它适用于任何常量字节,尽管除了 00001111 之外,我不清楚还有什么有用的。 - user1794469
5
需要在C++中包含<cstring>头文件。 - mtk
这也适用于由同一字节重复组成的任何值,但不适用于其他情况。 - Plas
你也可以将其设置为0x7f或0x3f,以获得一个非常大的数字,并用作无穷大。 - Michael Yang
#include <string.h> 用于 C - dumbitdownjr

14
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;

1
@Kraken - 它不会 - 0 仅初始化第一个值。然后默认情况下将所有其余值初始化为 0 - teppic
@Kraken:基本上是这样的。memset将其目标中的每个字节设置为给定的值,这不适用于将int设置为1。除非您希望将对象的每个字节设置为相同的值,否则不能使用memset来设置多字节对象的值。 - Eric Postpischil
@Kraken 我已经发布了一个解释,为什么 {1} 不起作用。事实上,除手动初始化外没有其他方法。虽然你不必输入数千个数字,但有一些宏技巧,但这可能是另一个问题的主题。 - Lundin
@teppic 为什么后者比两个for循环更快? - Kraken
@Kraken - 它可能会优化为更快的指令,但我期望一个好的编译器会为两者生成相同的代码。 - teppic
显示剩余3条评论

12

要初始化二维数组为0,请使用以下方法:int arr[n][m] = {};

注意:上述方法仅适用于初始化为0;


10
请注意,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的范围,但是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]),我不确定这是正确的,因为通常可以在int a = {1};中指定标量周围的大括号,这是明确被标准允许的。我也不确定它是否不正确。

我还想知道一个更好的符号表示是否为 [0]...[9] - 这是不含糊的、不会与任何其他有效语法混淆,并避免与浮点数混淆。

int array[ROW][COLUMN] = { [0]...[4] = { [0]...[9] = 1 } };

也许标准委员会会考虑这个问题?

7

请使用向量数组:

vector<vector<int>> array(ROW, vector<int>(COLUMN, 1));

4
可以,但是OP没有提到C++。 - Sangeet

3
char grid[row][col];
memset(grid, ' ', sizeof(grid));

这是将字符数组元素初始化为空格字符的方法。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接