我的XCode(默认编译器应该是clang?)向我展示了这段代码的警告:
Incompatible pointer types passing 'char *(*)[2]' to parameter of type 'char ***'
(调用func时)
void func (char ***arrayref, register size_t size) {
/// ...
}
int main()
{
char *array[2] = {"string", "value"};
func(&array, 2);
}
虽然这段代码没有问题(=没有警告):
void func (char **arrayref, register size_t size) {
/// ...
}
int main()
{
char *array[2] = {"string", "value"};
func(array, 2);
}
虽然这会删除警告
func((char***)&array, 2);
我仍然不知道为什么第一个会发出警告,而后者则没有。
另外,当第一个出现问题时,我也希望第一个发出警告,如:
Incompatible pointer types passing 'char *[2]' to parameter of type 'char **'
答案 0 :(得分:14)
简要介绍数组语义的时间。
除非它是sizeof
或一元&
运算符的操作数,或者是用于在声明中初始化另一个数组的字符串文字,否则表达式为“N-element array of T
“将被转换(”衰减“)为”指向T
的指针“类型的表达式,表达式的值将是数组中第一个元素的地址。
代码中的表达式array
的类型为“{-1}}的2元素数组”或char *
。当您将其作为参数传递给char *[2]
时,如
func
表达式转换为“指向func( array, 2 );
”的类型的表达式,或char *
,这是您的函数所期望的类型,表达式的值是第一个的地址元素:char **
。这就是为什么你没有得到第二个代码片段的警告。
在第一个片段中,数组是一元array == &array[0]
运算符的操作数,因此不会转换为指针类型;相反,表达式的类型是“指向 2元素数组 &
”的指针,或char *
,它与char *(*)[2]
不兼容。地址值是相同的(数组的第一个元素的地址与数组本身的地址相同),但类型不匹配,因此警告。
那么为什么这很重要?指针只是一个地址,所有地址都是一样的,对吧?好吧,不。指针是地址的抽象,具有关联的类型语义。指向不同类型的指针不必具有相同的大小或表示,指针算法取决于指向类型的类型。
例如,如果我将指针声明为char **
,则表达式char **p;
会使指针前进指向p++
类型的下一个对象,或char *
当前地址的字节数。但是,如果sizeof (char *)
被声明为p
,则表达式char *(*p)[2]
将p++
推进p
以指向{{的下一个双元素数组 1}},它是当前地址的2 * char *
个字节。
答案 1 :(得分:5)
char *array[2] = {"string", "value"};
是一个包含2个char *
元素的数组。
使用array
作为地址会产生指向第一个元素的指针,i。即类型为char **
。
将&array
结果用于指向同一位置的指针,但类型为char *(*)[2]
(不确定拼写是否正确)。
这与char ***
不同 - 内存中的表示完全不同。
更加详细,
+++++++++++++++++++++++
+ array[0] + array[1] +
+++++++++++++++++++++++
这是数组。
char ** p1 = array; // is a pointer to the first element, which in turn is a pointer.
char *(*p2)[2] = &array; // is a pointer to the whole array. Same address, but different type, i. e. sizeof(*p1) != sizeof(*p2) and other differences.
char ***p3 = &p1; // Now, p1 is a different pointer variable which has an address itself which has type `char ***`.
答案 2 :(得分:3)
以下是如何执行所需操作以及更改数组指向的示例:
char *array2[] = {"string", "NewValue"};
void func0 (char **arrayref, register size_t size) {
puts(arrayref[1]);
}
void func1 (char ***arrayref, register size_t size) {
puts(arrayref[0][1]);
*arrayref= (char **) array2;
}
int main()
{
char *array[] = {"string", "value"};
char **foo = array;
func0(foo, 2);
func1(&foo,2);
func0(foo, 2);
}
答案 3 :(得分:2)
你有一个char *[2]
类型的数组,即指向char
的2个指针的数组。它是一个固定大小的数组,具有自动存储持续时间。你的函数可以用这种数组做的唯一事情就是要么使用它的元素要么改变它们(它不能调整它或解除分配它...因此试图改变数组是没有意义的本身〜>换句话说:你真的不需要指向这种数组的指针。)
这是一个简单的例子:
void func (char *arrayref[2]) {
printf("%s", arrayref[1]);
arrayref[1] = "new value";
}
int main() { {
char *array[2] = {"string", "value"};
func(array);
printf(" -> %s", array[1]);
return 0;
}
或者更改func
以获取未指定大小的数组,使char *[X]
可用于任何X
,而不只是2
(在这种情况下,它已经有意义了)传递数组的大小):
void func (char *arrayref[], size_t size) {
if (size > 1) {
printf("%s", arrayref[1]);
arrayref[1] = "new value";
}
}
以某种方式,该程序将输出value -> new value
。
如果您需要您的函数能够以其他方式调整此数组的大小或影响数组本身,则应考虑使用动态分配的数组并以char**
的形式传递