从“ int []的数组”到“ int的指针”的显式衰减令人困惑吗?

时间:2019-01-10 16:29:17

标签: c++

我是一个新手,正在以随机顺序学习C ++。

在接下来的前三种情况下,我可以理解发生了什么,因为隐式衰减的模式很清楚。

  

X的数组”隐式地衰减为“ X的指针”。

void case1()
{
    int a[] = { 1,2,3,4,5,6 };
    int *b = a;// array of int ---> pointer to int
}

void case2()
{
    int input[][3] = { {1,2,3},{4,5,6} };
    int(*output)[3] = input;// array of int[] ---> a pointer to int[]

    for (int i = 0; i < 2; i++)
        for (int j = 0; j < 3; j++)
            cout << output[i][j] << endl;
}

int case3()
{
    int input[][3] = { {1,2,3},{4,5,6} };

    int* aux[2];

    aux[0] = input[0];// array of int ---> pointer to int
    aux[1] = input[1];// array of int ---> pointer to int

    int** output = aux;// array of int* ---> pointer to int*

    for (int i = 0; i < 2; i++)
        for (int j = 0; j < 3; j++)
            cout << output[i][j] << endl;
}

问题

但是,我对第四种情况确实感到困惑,如下。

int case4()
{
    int input[][3] = { {1,2,3},{4,5,6} };

    int* aux[2];
    aux[0] = (int*)input;// array of int[] ---> pointer to int
    aux[1] = aux[0] + 3;

    int** output = aux;// array of int* ---> pointer to int*

    for (int i = 0; i < 2; i++)
        for (int j = 0; j < 3; j++)
            cout << output[i][j] << endl;
}

如何将“ int[]的数组”显式衰减为“ int的指针”?

aux[0] = (int*)input;// array of int[] ---> pointer to int

欢迎任何简单的解释!

2 个答案:

答案 0 :(得分:3)

  

如何将“ int []数组”显式衰减为“ int指针”?

对术语不屑一顾:“显性衰变”是矛盾的。根据定义,衰减是隐式转换。

回答“如何将[数组]显式转换为[不是第一个元素类型的指针]?”

这是因为数组可以衰减为指针,并且所有数据指针都可以显式转换(重新解释)为任何其他数据指针类型。在这种情况下,input会衰减为int(*)[3],然后将其显式转换为int*

尽管它肯定格式正确,但另一件事是通过显式重新解释的指针进行的间接定义是否已定义为行为。围绕指针重新解释的规则是复杂而微妙的-很难保证它可以遵循您观察到的方式运行。我会更自信地写:

aux[0] = *input;

在这里,input数组会衰减为指向第一个子数组的指针,该指针被间接获得lvalue,然后它会衰减为指向该子数组元素的指针。


更一般地说,在使用显式转换(T)expr或函数转换T(expr)或重新解释强制转换reinterpret_cast<T>(expr)时要非常小心。除非您可以引用明确定义其用法的标准规则,否则请不要使用它们。

答案 1 :(得分:1)

嗯,这听起来像可以,但是合法吗?

众所周知,数组的第一个元素和数组本身在内存中共享相同的地址。

在常见实现中起作用的是所有指针共享相同的表示形式,并且该表示形式只是其第一个字节的内存地址。简而言之,这是标准所不能保证的。

但是足以成功地将数组的地址转换为其第一个元素的地址。显式强制转换将数组地址的表示形式重新解释为第一个元素的地址,由于实现,它恰好起作用。

这对于未定义行为非常有用:它不禁止自然行为,但也不保证自然行为。

因此,根据标准的字符串读取,尤其是根据 strict别名规则,将指向数组的指针转换为指向其第一个元素的指针,并使用该指针取消引用该元素是UB,因为数组及其元素类型是不同的类型。只需AFAIK,它就可以在所有常见的实现上使用。

TL / DR:它适用于所有常见的实现,但是如果您要编写符合标准的程序,则不要使用它。