静态数组名与动态数组名的区别分析
前言
今天做题发现了以前常常发现却没有试图去分析了解的东西,就是静态数组名和动态数组名有什么区别吗?
如下:
int * x=new int[20];
memset(x,0,sizeof(*x)*20);
//如果用静态数组则是:
int y[20];
memset(y,0,sizeof(y));
使用RTTI测试
int array[10];
cout<<typeid (array).name()<<endl;
int *arrayP=new int [10];
cout<<typeid (arrayP).name()<<endl;
大概意思:
array类型 容量为10 整型 即:大小为10的整型数组;
指针类型 整型 即:整型指针;
目前的结论
静态数组名和动态数组名其实质就是不一样的:
1、静态数组名是带有元素类型和容量的数组类型;
2、动态数组名是一个整型指针。
所以前言提到的问题已经得到了解答,为什么sizeof返回两个不同的大小因为其实质就是不一样的。但我们有时候又会有一样的情况,比如:
1)、对他们直接解引用都能得到首元素;
2)、数组下标访问。
为什么都能获得首元素
malloc是C语言的动态分配内存函数。
翻malloc的手册:
原型:
void* malloc( std::size_t size );
介绍:
分配 size 字节的未初始化存储。
若分配成功,则
返回
指向分配的适合对任何标量类型对齐的内存块中,
最低(首)字节的指针
。
所以
指针能得到首元素。
那数组又是如何得到首元素的呢?
继续翻手册找到如下描述:
数组到指针的退化
:
存在从数组类型的左值和右值到指针类型的右值的隐式转换:它构造一个指向数组首元素的指针。凡在数组出现于不期待数组而期待指针的语境中时,均使用这个转换。
什么意思呢?
简单讲:数组左值(我的认知就是有名数组接受赋值)或者右值(类似大花括号包起来的一个数组,没有名字的数组,不接受赋值)都可以转换为指针右值,返回首元素。
它又说了一句好像很有哲学的话,:
凡在数组出现于不期待数组而期待指针的语境中
时,均使用这个转换。
(当然前提是你的语法正确。)
进一步结论
存在数组到指针的退化,数组可转换为首元素的指针;
动态数组指针是由于先天声明时的返回值所决定的。
至此为什么能得到首元素的问题得到解答,接下来的
问题
:
为什么指针可以执行数组的下标运算?
下标运算(又称数据访问方式)
成员访问操作符
提供以下解释:
1、内建的下标 (subscript)运算符即
[]
提供对其指针或数组操作数所指向的对象的访问。
如:
//这里的p为指针操作数,y为数组操作数
int y[10];
int* p = &y[2];
接下来的内容是C/C++中的数据访问方式,不感兴趣可跳到
指针运算
。
2、内建的间接寻址 (indirection)运算符提供对其指针操作数所指向的对象或函数的访问。
如:
int n = 1;
int* pn = &n;//pn存放n的地址
int m = *pn;//m通过pn取n值
3、内建的取地址 (address of)运算符创建指向其对象或函数操作数的指针。
如:
int n=1;
int *p=&n;
4、对象的成员和对象的成员指针运算符提供对其对象操作数的数据成员或成员函数的访问。
如:
struct ST{
int a;
}
ST st{10};
cout<<st.a;
5、内建的指针的成员和指针的成员指针运算符提供对其指针操作数所指向的类的数据成员或成员函数的访问。
即类成员指针另一篇博文也有详细提及:
类成员指针 友元
简单示例:
class A{
public:
int val;
void fun(){}
}
int main(){
int A::*p=&A::val;//指向val的整型指针
int A::(*pf)()=&A::fun;//指向fun的函数指针
}
指针算术
转换
若传递给算术运算符的操作数是整型或无作用域枚举类型,则在任何其他行动前(但在左值到右值转换后,若其适用),对操作数实施整型提升。若操作数之一具有数组或函数类型,则
实施数组到指针和函数到指针转换。
如:
int * x=new int[20];
int *p=x+1;
则
p
为指向
x[1]
的指针
参考资料:
sizeof的C文档
数组文档 数组到指针转换
成员访问运算符
指针算术