【问题标题】:Can a pointer convert to an array during a function call?函数调用期间指针可以转换为数组吗?
【发布时间】:2019-04-21 03:22:42
【问题描述】:

考虑以下代码:

#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

现在,当调用 use_pointer(arr) 时,array is being decayed 指向一个指针。 (对吗?“腐烂”这个词对我来说很陌生。)

C++ 标准在 [conv.array#1] 说:

“N T 数组”或“未知边界数组”类型的左值或右值 of T”可以转换为“pointer to T”类型的纯右值。这 应用临时实现转换 ([conv.rval])。这 result 是指向数组第一个元素的指针。

我想我明白我的 “int 数组”转换为“指向 int 的指针”。 (对吗?)

现在,调用use_array(ptr) 时究竟会发生什么。由于本例中参数的类型是 int 数组,所以 “指向 int 的指针” 是否转换为 “int 数组”

我们将不胜感激。

【问题讨论】:

    标签: c++ arrays pointers type-conversion


    【解决方案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++ 语义通常是按值传递的。因此,如果您成功(或者我应该说如果语言允许)传递数组,那么您将制作一个将传递给函数的数组副本。这可能是不可取的,因此 apssing 指针是按值传递的一种有效方式(尽管您这样做 . 获取类型更改)。

    请注意,通过引用传递非常有限,因为它必须知道确切的类型。我们通常通过将其作为模板来解决大小问题。

    template<int S>
    void use_pointerref(int (&arr)[S])
    {
        std::cout << typeid(arr).name() << " Size: " << S << std::endl;
    }
    

    【讨论】:

      【解决方案2】:

      您的代码与指针衰减无关。相反,它演示了函数参数的类型调整。

      当用作函数参数的一种类型时,T[] 正在调整T*。这不是衰变,不是转换,而是重写。该程序被重写为使用T*,就好像源代码中没有T[]

      重申一下,C++ 中没有类型为T[] 的函数参数。当程序员编写一个时,编译器立即替换T* 并忘记T[] 曾经在那里。这与普通数组及其对指针的衰减相反。 C++ 中肯定有与指针非常不同的数组。它们仅在(许多但不是全部)表达式中衰减为指针。这是一条单行道:指向数组的指针永远不会衰减

      【讨论】:

      • 谢谢! “功能参数的类型调整”是我需要听到的。我猜标准中的相关部分是[[dcl.fct#5]](eel.is/c++draft/dcl.fct#5),对吗?
      • 是的,这是段落。
      【解决方案3】:

      指针就是指针,数组就是数组。然而,数组自然衰减为指向其第一个元素的指针。因此,当您将数组 arr 传递给您拥有的任何函数时,它将衰减为 &amp;arr[0]

      另请注意,在声明函数参数时,数组表示法(如int arr[])并不意味着它是一个数组,编译器仍会将其转换为指针(即int* arr)。

      关于从数组到指针的衰减,不能反过来。一旦你有了一个指针,你所拥有的就是那个指针和它指向的单个元素。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-08-08
        • 1970-01-01
        • 1970-01-01
        • 2019-01-04
        • 1970-01-01
        • 2011-07-03
        • 1970-01-01
        相关资源
        最近更新 更多