可以在函数调用期间将指针转换为数组吗?

时间:2018-11-18 16:48:23

标签: c++ arrays pointers type-conversion

请考虑以下代码:

#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的数组”

非常感谢指向该标准的指针。

3 个答案:

答案 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;
}