考虑这段代码:
void test(int** p)
{
}
int main()
{
int arr[] = {30, 450, 14, 5};
test(&arr);
return 0;
}
gcc 对此不太满意,并发出警告:passing arg 1
of test from incompatible pointer type。 C++ 有更严格的类型
检查,所以让我们尝试通过g++ 运行相同的代码。作为
预期,我们得到一个错误:cannot convert int (*)[4] to int** for
argument 1 to void test(int**)。
那么这里的问题是什么?上面的代码有什么问题?好,
一切。这简直是无效的,没有任何意义。有些人会
认为它应该有效,因为它有效:
void test(int* p)
{
}
int main()
{
int arr[] = {30, 450, 14, 5};
test(arr);
return 0;
}
但是这个特别有效,因为 C 编译器应该遵循
C标准,它要求数组“衰减”成指针,当
用作左值。因此,指向数组第一个元素的指针是
实际上通过了测试,一切正常。
但是,第一个代码sn-p是不同的。虽然数组名称可能
衰减成指针,数组的地址不会衰减成
指向指针的指针。为什么要这样做?它有什么意义
这么对待数组?
有时会传递指向指针的指针来修改指针
(简单的指针参数在这里不起作用,因为 C 按值传递,
这只允许修改指向的内容,而不是指针
本身)。这是一些虚构的代码(不会编译):
void test(int** p)
{
*p = malloc ... /* retarget '*p' */
}
int main()
{
int arr[] = {30, 450, 14, 5};
int* ptr;
/* Fine!
** test will retarget ptr, and its new value
** will appear after this call.
*/
test(&ptr);
/* Makes no sense!
** You cannot retarget 'arr', since it's a
** constant label created by the compiler.
*/
test(&arr);
return 0;
}
指向数组的指针
请注意,原始代码可以稍作修改以使其成为
工作:
void test(int (*p)[4])
{
(*p)[2] = 10;
}
int main()
{
int arr[] = {30, 450, 14, 5};
test(&arr);
printf("%d\n", arr[2]);
return 0;
}
现在那个奇怪的类型测试接受了什么?向“指向
数组”,C 的无用特性之一。这就是 C 常见问题解答的内容
说一下:
2.12:如何声明指向数组的指针?
通常,您不想这样做。当人们随便谈论一个指向
一个数组,它们通常表示指向其第一个元素的指针。
虽然前面的 sn-p 中的测试函数编译并工作,
它没有多大用处,因为它写起来更清晰:
void test(int* p)
{
p[2] = 10;
}
...
...
/* then call */
test(arr);
指针作为函数参数的主要用途是避免
按值传递整个结构,或修改指向的对象
指针。对于指向数组的指针,两者都无关紧要。这里是
一个澄清的sn-p:
int joe[] = {1, 2, 3, 4};
void test(int (*p)[4])
{
/* Fine: assign to an element through the
** pointer.
*/
(*p)[2] = 10;
/* Works, but won't be reflected in the
** caller since p was passed by value.
*/
p = &joe;
/* Error: arrays can't be assigned.
*/
*p = joe;
}
数组不是按值传递的,所以指向数组的指针是
对这个目的没用。数组也不能被修改,所以
杀死第二个原因。