请考虑以下代码:
#include <iostream>
#include <typeinfo>
void use_pointer(int *ptr)
{
std::cout << typeid(ptr).name() << std::endl;
}
void use_array(int arr[])
{
std::cout << typeid(arr).name() << std::endl;
}
int main()
{
int *ptr = nullptr;
// std::cout << typeid(int *).name() << std::endl; // output: Pi
int arr[1];
// std::cout << typeid(int[]).name() << std::endl; // output: A_i
use_pointer(arr);
use_array(ptr);
}
使用g++ 6.5.0
输出编译该程序:
$ g++ -std=c++11 arrays_2.cpp -Wall
$ ./a.out
Pi
Pi
现在,当将array is being decayed调用use_pointer(arr)
到指针时。 (对吗?“衰减”一词对我来说是陌生的。)
C ++标准在 [conv.array#1] 中说:
“ N T数组”或“未知边界数组”类型的左值或右值 T的值可以转换为“ T的指针”的prvalue。的 应用临时物化转换([conv.rval])。的 结果是一个指向数组第一个元素的指针。
我想我知道我的“ int数组”会转换为“ int指针” 。 (对吗?)
现在,调用use_array(ptr)
时会发生什么。由于在这种情况下参数的类型为int数组,因此“指向int的指针” 是否转换为“ int的数组” ?
非常感谢指向该标准的指针。
答案 0 :(得分:5)
指针是指针,而数组是数组。但是,数组自然会衰减指向其第一个元素的指针。因此,当您将数组arr
传递给您拥有的任何函数时,它将衰减为&arr[0]
。
还请注意,在声明函数参数时,数组符号(如int arr[]
)并不意味着它是一个数组,编译器仍将其转换为指针(即int* arr
)。 / p>
关于从数组到指针的衰减,不可能以其他方式发生。一旦有了一个指针,您所拥有的就是该指针及其指向的单个元素。
答案 1 :(得分:2)
您的代码与指针衰减没有任何关系。相反,它演示了功能参数的类型调整。
将T[]
用作功能参数的类型时,正在将它们{em>调整为T*
。这不是衰减,不是转换,而是 rewrite 。程序被重写为使用T*
,好像源代码中根本没有T[]
一样。
重申一下,C ++中没有{em> no 函数类型为T[]
的函数参数。当程序员编写一个时,编译器立即替换T*
,而忘记了T[]
在那里。这与普通数组及其对指针的衰减相反。在C ++中,绝对有一些数组与指针有很大不同。它们仅在(很多但不是全部)表达式中衰减到指针 。这是一条单向路:指针永远不会衰减到数组
答案 2 :(得分:1)
函数调用期间指针可以转换为数组吗?
不。通过引用传递时,请参见最后一个示例。
数组类型具有大小(包括所有元素)。当它衰减为指针时,此大小信息将丢失。因此,无法将指针转换回数组(因为您不知道数组的大小)。
您可能已经注意到,数组和指针参数实际上是编译器彼此的同义词:
> cat b.cpp
void use_pointer(int *ptr)
{}
void use_pointer(int (arr)[])
{}
> g++ b.cpp
b.cpp:8:6: error: redefinition of 'use_pointer'
void use_pointer(int (arr)[])
^
b.cpp:4:6: note: previous definition is here
void use_pointer(int *ptr)
这对编译器没关系,它们都是同一回事。
因此,当您将数组作为参数传递时,它通常会衰减为一个指针(表示数组第一个元素的地址)。
现在您可以通过引用传递数组,但是语法不同。
void use_pointerref(int (&arr)[1]) // You have to specify the exact size
{} // And lace the ampersand in there.
但是您会注意到指针不会绑定到此函数。
use_arrayref(arr);
use_arrayref(ptr);
> g++ b.cpp
b.cpp:31:5: error: no matching function for call to 'use_arrayref'
use_arrayref(ptr);
^~~~~~~~~~~~
b.cpp:14:6: note: candidate function not viable: no known conversion from
'int *' to 'int (&)[1]' for 1st argument
void use_arrayref(int (&arr)[1])
但是让我们考虑一下。 C ++语义通常按值传递。因此,如果您成功地(或者我应该说是否允许的语言)通过数组,则将复制该数组的副本,该副本将被传递给函数。这可能是不希望的,因此,使用指针是一种按值传递的有效方法(尽管您确实进行了类型更改)。
请注意,按引用传递非常有限,因为它必须知道确切的类型。通常,我们通过将其作为模板来解决尺寸问题。
template<int S>
void use_pointerref(int (&arr)[S])
{
std::cout << typeid(arr).name() << " Size: " << S << std::endl;
}