用一个值初始化整个2D数组


81

带有以下声明

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

我得到全零但下面的一个数组

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

我没有获得所有值的数组。默认值仍为0。

为什么会出现这种现象,以及如何用全1初始化?

编辑:我刚刚了解到,将memsetvalue用作1会将每个字节设置为1,因此每个数组单元的实际值不会为1而是16843009。如何将其设置为1?


1
@ckruse:问题不是如何,这是为什么
masoud

@MM。答案在我链接的线程中给出。
ckruse

问题实际上是why and how两个。:)
Kraken

@Kraken您编辑的问题可能应该作为与此问题分开的问题发布。
隆丁

1
@Kraken实际上我在这里找到了这个问题。我建议按照答案中的建议进行操作(当然!),而不要依赖GCC扩展。
隆丁

Answers:


123

您得到此行为,因为int array [ROW][COLUMN] = {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,并将所有其他项设置为零”。


2
为此,我能做些什么来将整个数组初始化为1?考虑我的行和列的大小是几百个?
Kraken

1
@Kraken具有宏技巧。看到这个
伦丁2014年

是我还是您需要第二组括号:int array [ROW][COLUMN] = {{0}};
user1794469 '16

@ user1794469不,你不会。
伦丁

1
@ user1794469是的,这很好,因为在大多数情况下,跳过大括号是不好的做法。但是编译器不具有给诊断。关于这种情况的好/坏做法,请参阅我对这个问题的回答
伦丁

40

如果要将数组初始化为,-1则可以使用以下代码,

memset(array, -1, sizeof(array[0][0]) * row * count)

但这将起作用0并且-1只有


14
使用“ sizeof(array)”比“ sizeof(array [0] [0])*行*计数”更容易。
Vladyslav Savchenko

它适用于任何固定字节,虽然它不是我清楚什么是有用的,除了00001111
user1794469

4
需要包含<cstring>在c ++中
mtk

但是,为什么这仅适用于0和-1?
user9989615

12
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

@EricPostpischil如此,它将所有字节设置为1,因此如果我考虑使用32位整数,则如果我的value字段memset为1,则矩阵中的实际值将为1,但是2^0 + 2^8 + 2^16 + 2^24
Kraken

@Kraken:基本上是。memset将目标中的每个字节设置为给定的值,将an设置int为1memset无效。除非希望将对象的每个字节设置为相同的值,否则不能用于设置多字节对象的值。
Eric Postpischil 2013年

@EricPostpischil因此,除了手动初始化每个方法之外,没有其他方法吗?考虑我的行和列甚至是几千?
Kraken

@Kraken我已经发布了一个解释,为什么{1}不起作用。实际上,除了手动初始化外,别无其他方法。尽管您不必键入数千个数字,但有一些技巧,但这可能是另一个问题的话题。
隆丁

8

请注意,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 } } };

标量初始值设定项1error: braces around scalar initializer [-Werror])周围还有一组花括号。鉴于您通常可以在中的标量周围指定大括号int a = { 1 };,因此我不确定这是正确的,这是标准明确允许的。我也不确定这是不正确的。

我还想知道是否会有更好的表示法[0]...[9]-明确,不能与任何其他有效语法混淆,并且避免与浮点数混淆。

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

也许标准委员会会考虑这一点?



3

使用向量数组代替:

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

3
可能,但是OP没有提到C ++。
Sangeet

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

这是为了将char数组元素初始化为空格字符。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.