子数组分配:用“{...}”初始化聚合对象错误
Subarray assignment: initialization with "{...}" expected for aggregate object error
第 1 行的错误有什么好的解释?
/* Line 0 */ int foo[10][10];
/* Line 1 */ int foo_alias_compile_error[] = foo[0];
/* Line 2 */ int foo_alias_also_errors[10] = foo[0];
/* Line 3 */ int * foo_alias_works = foo[0];
第 2 行的错误并没有真正困扰我,因为我不需要能够重复自己并重新声明数组的大小。然而,第 1 行的错误(初始化为聚合对象 预期的“{...}”)让我感到困惑。我知道 int foo_alias_compile_error[]
可能是 "aggregate object"。我只是不明白为什么语言设置不工作。我理解为什么第 3 行有效,但它有点不具代表性——它是一个数组,所以我宁愿将它自己记录为一个数组。
当您未指定数组大小时(第 1 行)。编译器为您指定它。为此你必须这样做:
/* Line 0 */ int foo[10][10];
/* Line 1 */ int foo_alias_compile_error[] = {foo[0]};
但还是有问题。编译该代码时:
$ g++ error.cpp
$ error.cpp:4:28: error: invalid conversion from ‘int*’ to ‘int’ [-fpermissive]
$ 4 | int fooError[] = {foo[0]};
$ | ~~~~~^
$ | |
$ | int*
因为 foo[0]
是一个指针,指向矩阵的第一行(第 1 行)。你可以这样做:
/* Line 0 */ int foo[10][10];
/* Line 1 */ int foo_alias_compile_error[] = {foo[0][0]};
人们可能希望将第 1 行视为为 foo
的第 0 个条目创建引用。然而,这不是 C++ 的工作方式。相反,赋值运算符 (=
) 正在调用复制操作。因此,C++ 将第 1 行解释为将 foo[0]
的元素复制到一个不恰当地命名为 foo_alias_compile_error
.
的新数组中的指令
这不是本意 -- 需要参考,而不是副本。所以,还好C++恰好因为一个不相关的原因导致了一个错误,自己救了一个。
@FrançoisAndrieux 提出了一个可行的解决方案。这是一个更完整的示例,显示可以使用 int (&foo_reference)[10] = foo[0];
.
进行引用(不是副本)
int foo[10][10];
for (int i = 0; i < 10; ++i) {
for (int j = 0; j < 10; ++j) {
foo[i][j] = i + j * 10;
}
}
int (&foo_reference)[10] = foo[0];
for (int j = 0; j < 10; ++j) {
foo_reference[j] = 100 + j;
}
for (int i = 0; i < 10; ++i) {
printf("foo [0][%i] is %i\n", i, foo[0][i]);
printf("foo_refer[%i] is %i\n", i, foo_reference[i]);
}
输出代码段
foo [0][0] is 100
foo_alias[0] is 100
foo [0][1] is 101
foo_alias[1] is 101
foo [0][2] is 102
foo_alias[2] is 102
foo [0][3] is 103
foo_alias[3] is 103
Side-note
值得一提的是,以数组为参数的函数会将其数组参数隐式转换为指针(如第 3 行所示)。所以,这就是为什么人们可能会错误地认为像第 1 行这样的东西应该起作用的原因之一。
也就是说下面的代码
void barz(int arg[]) {
arg[2] = 99999;
}
int another_array[] = {0, 1, 2, 3, 4};
barz(another_array);
printf("another_array[2] is %i\n", another_array[2]);
"Correctly" 打印 99999
,而不是 2
。
数组定义中的初始值设定项(C-style数组,即)必须是花括号列表。
此规则涵盖您的第 1 行和第 2 行,其中您提供的内容不是大括号列表,因此代码不正确。
更多信息:当您提供大括号列表时,列表中的每个元素都将作为数组中 一个 元素的初始值设定项。作为推论,不可能提供单个初始化程序,导致多个数组元素由它设置。
这条规则几乎是递归适用的;如果你有一个数组数组,那么初始值设定项应该是一个大括号列表的大括号列表。然而,有一条规则是在某些情况下可以省略嵌套大括号(并且代码的行为就像提供了完整的大括号一样)。例如 int x[2][2] = { 1, 2, 3, 4 };
是允许的,其行为类似于 int x[2][2] = { {1, 2}, {3, 4} };
。
第 1 行的错误有什么好的解释?
/* Line 0 */ int foo[10][10];
/* Line 1 */ int foo_alias_compile_error[] = foo[0];
/* Line 2 */ int foo_alias_also_errors[10] = foo[0];
/* Line 3 */ int * foo_alias_works = foo[0];
第 2 行的错误并没有真正困扰我,因为我不需要能够重复自己并重新声明数组的大小。然而,第 1 行的错误(初始化为聚合对象 预期的“{...}”)让我感到困惑。我知道 int foo_alias_compile_error[]
可能是 "aggregate object"。我只是不明白为什么语言设置不工作。我理解为什么第 3 行有效,但它有点不具代表性——它是一个数组,所以我宁愿将它自己记录为一个数组。
当您未指定数组大小时(第 1 行)。编译器为您指定它。为此你必须这样做:
/* Line 0 */ int foo[10][10];
/* Line 1 */ int foo_alias_compile_error[] = {foo[0]};
但还是有问题。编译该代码时:
$ g++ error.cpp
$ error.cpp:4:28: error: invalid conversion from ‘int*’ to ‘int’ [-fpermissive]
$ 4 | int fooError[] = {foo[0]};
$ | ~~~~~^
$ | |
$ | int*
因为 foo[0]
是一个指针,指向矩阵的第一行(第 1 行)。你可以这样做:
/* Line 0 */ int foo[10][10];
/* Line 1 */ int foo_alias_compile_error[] = {foo[0][0]};
人们可能希望将第 1 行视为为 foo
的第 0 个条目创建引用。然而,这不是 C++ 的工作方式。相反,赋值运算符 (=
) 正在调用复制操作。因此,C++ 将第 1 行解释为将 foo[0]
的元素复制到一个不恰当地命名为 foo_alias_compile_error
.
这不是本意 -- 需要参考,而不是副本。所以,还好C++恰好因为一个不相关的原因导致了一个错误,自己救了一个。
@FrançoisAndrieux 提出了一个可行的解决方案。这是一个更完整的示例,显示可以使用 int (&foo_reference)[10] = foo[0];
.
int foo[10][10];
for (int i = 0; i < 10; ++i) {
for (int j = 0; j < 10; ++j) {
foo[i][j] = i + j * 10;
}
}
int (&foo_reference)[10] = foo[0];
for (int j = 0; j < 10; ++j) {
foo_reference[j] = 100 + j;
}
for (int i = 0; i < 10; ++i) {
printf("foo [0][%i] is %i\n", i, foo[0][i]);
printf("foo_refer[%i] is %i\n", i, foo_reference[i]);
}
输出代码段
foo [0][0] is 100
foo_alias[0] is 100
foo [0][1] is 101
foo_alias[1] is 101
foo [0][2] is 102
foo_alias[2] is 102
foo [0][3] is 103
foo_alias[3] is 103
Side-note
值得一提的是,以数组为参数的函数会将其数组参数隐式转换为指针(如第 3 行所示)。所以,这就是为什么人们可能会错误地认为像第 1 行这样的东西应该起作用的原因之一。
也就是说下面的代码
void barz(int arg[]) {
arg[2] = 99999;
}
int another_array[] = {0, 1, 2, 3, 4};
barz(another_array);
printf("another_array[2] is %i\n", another_array[2]);
"Correctly" 打印 99999
,而不是 2
。
数组定义中的初始值设定项(C-style数组,即)必须是花括号列表。
此规则涵盖您的第 1 行和第 2 行,其中您提供的内容不是大括号列表,因此代码不正确。
更多信息:当您提供大括号列表时,列表中的每个元素都将作为数组中 一个 元素的初始值设定项。作为推论,不可能提供单个初始化程序,导致多个数组元素由它设置。
这条规则几乎是递归适用的;如果你有一个数组数组,那么初始值设定项应该是一个大括号列表的大括号列表。然而,有一条规则是在某些情况下可以省略嵌套大括号(并且代码的行为就像提供了完整的大括号一样)。例如 int x[2][2] = { 1, 2, 3, 4 };
是允许的,其行为类似于 int x[2][2] = { {1, 2}, {3, 4} };
。