我有一个API有一些选择:
void init_api(const char* options[][2]);
我被允许传递一个没有选项的NULL指针,或者,可以传递像这样的选项数组:
const char* some_options[][2] = { {"opt1", "val1"},
{"opt2", "val2"},
{0,0}
};
此可以正常运行:
...
init_api(some_options);
... or ...
init_api(NULL);
...
然而,无法编译:
const char* my_options[][2] = NULL; // error C2440: 'initializing' : cannot convert from 'int' to 'const char *[][2]'
if(...) {
my_options = some_options; // error C2440: '=' : cannot convert from 'const char *[4][2]' to 'const char *[][2]'
}
init_api(my_options); // no error here
这里发生了什么?有人可以解释一下吗?
答案 0 :(得分:3)
要声明一个指向const char的指针数组的空数组,您应该使用:
const char* my_options[][2] = {};
您需要声明一个指向const char指针数组的指针。我建议使用typedef来简化语法。
typedef const char* array_of_two_cstring[2];
array_of_two_cstring* my_options = NULL;
if (...) {
my_options = some_options;
}
init_api(my_options);
在C ++中(它是从C中删除),数组可以隐式转换为指针(只有一次,char[]
与char*
兼容但char[][]
与{ {1}}但不是`char **)。但是,无法重新分配变量。所以在这里你需要使用指针而不是数组。
char*[]
选项接受init_api
作为参数,因为对于编译器,其原型是NULL
(第一个数组退化为指针),而void init_api(char const* (*)[2])
是一个有效指针。
答案 1 :(得分:3)
编译器必须知道数组大小。
如果省略数组的大小(即:使用[]
),则需要使用定义初始化数组,以便让编译器计算数组将包含的项目数。
此外,您正在为数组指定一个指针(NULL
):const char *x[][2]
是一个包含两个指针const char
的数组。
修改强>:
在C ++中(如在C中),当你使用它们时,数组可以衰减为指针(有三个例外,这里不感兴趣)。
当你将一个数组传递给一个期望一个数组的函数时,你会发生一个指向数组的指针,因为数组会衰减;你不能在C或C ++中按值传递数组。
因此,您可以将NULL
传递给您的函数;函数参数将为NULL
,如果您尝试访问函数中的数组(options[0]
),您的应用程序将崩溃:您将取消引用无效指针。
但是你不能将你的数组变量设置为NULL
,因为它不是指针,它是一个数组:它只会在你在表达式中使用它时才会衰减。
答案 2 :(得分:1)
const char* options[][2]
是一个const char *指针数组。您无法指定指向数组的指针。
答案 3 :(得分:1)
声明为类型为T[N]
或T[]
的数组的参数实际上变为类型T*
的参数。对函数也是如此(声明为R(Params)
的参数实际上变为类型R(*)(Params...)
的参数)。
然而,这种转换不适用于其他声明。为函数按值参数完成的原因是C中没有办法直接实际复制数组(即实际复制其内容),尝试复制函数也没有意义,所以这些参数以一种以有意义的方式传达其目的的方式进行转换。
因此,当你在函数参数的情况下初始化一个指针时,你试图在另一种情况下初始化一个数组。