为什么我们不能直接将 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++ 比汇编高一级;你不应该像那样使用内存地址。因此,编译器禁止您执行此类代码以帮助您避免错误。
我有一个包含 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++ 比汇编高一级;你不应该像那样使用内存地址。因此,编译器禁止您执行此类代码以帮助您避免错误。