为什么我们不能直接将 arr 赋给指向数组的指针

Why can't we directly assign arr to pointer to array

我有一个包含 5 个整数的数组。 arr 和 &arr 是同一个地址。 那么为什么数字 2 给出编译错误而数字 3 工作正常。

  int arr[5] = {1,2,3,4,5};
  1. int *p = arr;
  2. int (*p1)[5] = arr //Compilation Error
  3. int (*p1)[5] = &arr; //Works fine.
  
     arr = 0x61fdf0 and &arr= 0x61fdf0

问题是初始化对象和初始化器有不同的指针类型,并且没有从一种指针类型到另一种指针类型的隐式转换。

在此声明中

int (*p1)[5] = arr;

初始化对象的类型为 int ( * )[5],而初始化器的类型为 int *,因为数组指示符隐式转换为指向其第一个元素的指针。

你必须写

int (*p1)[5] = &arr

或者例如

int ( *p1 )[5] = reinterpret_cast<int ( * )[5]>( arr );

这是一个演示程序。

#include <iostream>

int main() 
{
    int arr[5] = {1,2,3,4,5};   
    
    int ( *p1 )[5] = reinterpret_cast<int ( * )[5]>( arr );

    std::cout << "sizeof( *p1 ) = " << sizeof( *p1 ) << '\n';
    
    return 0;
}

程序输出为

sizeof( *p1 ) = 20

对象可以具有相同的值但不同的类型。

考虑另一种情况。

假设您有一个结构类型的对象

struct A
{
    int x;
} a;

在这种情况下,&a&a.x 具有相同的值,但表达式的类型不同。例如你可能不会写

int *p = &a;

编译器会报错。但是你可以写

int *p = ( int * )&a;

int *p = reinterpret_cast<int *>( &a );

这是一个演示程序。

#include <iostream>
#include <iomanip>

int main() 
{
    struct A
    {
        int x;
    } a = { 10 };
    
    std::cout << std::boolalpha << ( ( void * )&a.x == ( void * )&a ) << '\n';
    
    int *p = reinterpret_cast<int *>( &a );
    
    std::cout << "*p = " << *p << '\n';
    
    return 0;
}

程序输出为

true
*p = 10

关于你在评论中的另一个问题

Can you decode this in simple language to understand int** p = new int*[5];

然后在此表达式中使用运算符 new

new int*[5]

已为具有 5 个 int * 类型元素的数组分配了内存。表达式 returns 指向数组第一个元素的指针。指向 int * 类型对象(分配数组的元素类型)的指针将具有 int **.

类型

简单的说,这也是抛出编译错误的原因:

int main()
{
    int x = 5;
    int *p = x;
}

当你有一个为对象类型指定的指针时,你应该分配该类型对象的地址。话虽这么说,虽然上面的代码没有意义,但下面的代码确实如此:

int main()
{
    int x = 5;
    int *p = &x;
}

这适用于数组,就像它适用于其他任何东西一样。

int main()
{
    int x[5] = {1, 2, 3, 4, 5};
    int (*p)[5] = x; // Compilation error.
    int (*p)[5] = &x; // Does exactly what it should.
}

你说 x&x 很可能具有相同的值是正确的,因此将 x 分配给指针而不是 &x 应该有效并且说得通。虽然从技术角度来看它确实有意义,但从语义角度来看却没有意义。 C++ 语言优先考虑语义以帮助程序员避免错误。这是一个例子:

int main()
{
    int x = 0x72fe1c; // Let's imagine that 0x72fe1c just so happens to be the address of x.
    // x is an int variable holding a value which just so happens to be equal to its address.
    int *p = x; // This is never desirable; thank the compiler for telling you something is wrong.
}

以上代码从技术角度讲是有道理的。 x持有的值刚好等于自己的内存地址,那么把它的值赋值给指针有什么坏处呢? “危害”在于,在实际情况下,C++ 程序员永远不会想要这个,因为 C++ 比汇编高一级;你不应该像那样使用内存地址。因此,编译器禁止您执行此类代码以帮助您避免错误。