问题描述
|
这两个声明之间有什么区别吗?
int x[10];
与
int* x = new int[10];
我假设前一个声明(与后一个声明一样)是指针声明,并且两个变量可以被视为相同。这是否意味着它们本质上是相同的?
解决方法
#include<iostream>
int y[10];
void doSomething()
{
int x[10];
int *z = new int[10];
//Do something interesting
delete []z;
}
int main()
{
doSomething();
}
int x[10];
-在堆栈上创建大小为10的整数的数组。
-您不必显式删除此内存,因为随着堆栈展开,它会消失。
-其范围仅限于功能doSomething()
int y[10];
-在BSS /数据段上创建大小为10的整数数组。
-您不必显式删除该内存。
-由于声明为“ 6”,因此可以全局访问。
int *z = new int[10];
-在堆上分配一个大小为10的整数的动态数组,并将该内存的地址返回到“ 8”。
-使用动态内存后,必须明确删除它。使用:
delete[] z;
, 唯一相似的是
int x[10];
和
int* x = new int[10];
是可以在某些情况下使用int*
的情况:
int* b = x; // Either form of x will work
void foo(int* p) {}
foo(x); // Either form will work
但是,不能在期望int*
的所有情况下使用它们。特别,
delete [] x; // UB for the first case,necessary for the second case.
其他答案中已经解释了一些核心差异。其他核心差异是:
差异1
sizeof(x) == sizeof(int)*10 // First case
sizeof(x) == sizeof(int*) // Second case.
差异2
case17ѭ的类型在第一种情况下为int (*)[10]
第二种情况下,&x
的类型为int**
差异3
给定功能
void foo(int (&arr)[10]) { }
您可以使用前一个x
而不是第二个x
来调用它。
foo(x); // OK for first case,not OK for second case.
, 第一个是大小为10
的int
数组。说它在堆栈上创建是错误的。因为标准不能保证这一点。其实现定义。它的存储持续时间可以是静态的也可以是自动的,具体取决于“ 22”是全局变量还是局部变量。
在第二个中,创建类型为“ 12”的指针。不一定在堆上创建,标准并没有这么说。分配的内存跨度超过29个字节。为此,您必须自己编写以下代码来释放内存:
delete [] x;
在这种情况下,指针“ 22”的存储器是动态分配的,并且是动态释放的,因此这种对象被称为具有动态的存储时间。
,根据标准,我们实际上应该区分三种不同类型的数组声明:
int x[10];
void method() {
int y[10];
int *z = new int[10];
delete z;
}
第一个声明int x[10]
使用静态存储持续时间,由cppreference定义为:\“对象的存储在程序开始时分配,并在程序结束时释放。仅存在该对象的一个实例。所有在名称空间范围内声明的对象(包括全局名称空间)具有此存储期限,以及用static或extern声明的存储期限。\“
第二个,int y[10]
,使用自动存储持续时间,由cppreference定义为:\“对象在封闭代码块的开头分配,并在末尾释放。所有本地对象都具有此存储持续时间,声明为static,extern的对象除外或thread_local。\“
第三,one35ѭ,通常称为动态内存分配,实际上是一个两步序列:
首先,调用new运算符,该运算符使用标准库的默认分配方法或用户定义的实现方式动态分配内存(因为new可以在运行时覆盖)。分配的内存足以容纳分配的N个元素,再加上为给定分配保留元数据所需的任何其他内存(以便以后可以成功释放)。
第二,如果第一步成功,那么我们将继续初始化或构造数组中的每个对象。
正如其他评论所提到的,这些类型的声明有细微的差别,但最常见的是:
在大多数现代操作系统上:
自动存储通常是在堆栈上分配的,该堆栈通常是使用LIFO机制的(通常是)线程特定的预分配内存空间
静态存储使用在可执行文件内保留的预分配内存空间(更具体地说,.BSS和.DATA段,取决于变量是否初始化为零)
动态内存是使用堆内存分配的,并且受系统RAM管理系统和其他机制(例如分页)的支配。
动态分配的内存应由程序员明确地分配“ 36”位,而静态和自动存储变量由“环境”处理。
静态和自动存储变量仅限于特定范围,而动态分配的内存没有界限,这意味着,在一个模块中声明的变量可以传递给在相同地址空间中运行的任何其他模块
使用new[]
分配数组时,大小可以为0
(如@R Sahu所指出的)&x
和&z
的类型不同:
&x
是int (*)[10]
&z
是int **
,声明完全不同。
第一种情况
int x[10];
将x
声明为10
整数的数组,而第二种情况是
int* x = new int[10];
将x
声明为指向int
(其值等于int
的地址的变量)的指针,并将该指针初始化为动态分配十个整数数组的新表达式(ѭ51expression)的结果。
尽管存在差异,但两者可以类似的方式使用。
数组语法(例如x[i]
,其中i
是0
和9
之间的整数值),可以用于设置或检索上述语法中各个数组的值;
指针算术可用于获取数组元素的地址(例如,对于在53中介于54和26之间的53,ѭ56等效于&x[i]
。[是的,有可能获得“末尾一个”);
指针解引用和数组访问是等效的。即*(x+i)
和x[i]
是等效的,对于0
和9
之间的i
[解引用\“越过终点\”指针给出了不确定的行为]。
但是,例如,也存在一些关键差异。
sizeof
运算符的结果。 sizeof(x)
在两种情况下给出不同的值。
第一种情况是ѭ68。 sizeof(int)
给出实现定义的balue,但是but70ѭ总是给出数组中元素的数量(即i71ѭ,值value26ѭ)。
在第二个中,“ 73”-这是实现定义的值。 sizeof(x)/sizeof(*x)
的值实际上几乎不可能产生10
的值。这意味着该技术无法用于获取元素数量。
一生。
在第一种情况下,“ 22”的生存期取决于声明发生的范围。如果声明发生在文件范围内(即,在任何功能块外部的编译单元中),则“ 22”具有静态存储持续时间(因此,只要程序运行,它就会存在)。如果声明出现在一个块中,则在该块结束时,x
及其所有元素将不复存在。例如
{
int x[10];
} // x and all its elements cease to exist here
在第二种情况下,只有指针x
的生存期取决于范围。动态分配的内存(new x[10]
的结果)永远不会被释放。这意味着ѭ22的生存期与它引用的(动态分配的)数组的生存期解耦,这使我们产生了第三个差异.....
赋值结果不能重新赋值数组,可以重新分配指针(除非适当地用“ѭ83”限定)。
考虑一个上下文
// x as previously defined in one or the other form
int y[10];
int z;
x = y;
x = &z;
在第一种情况下,两个分配都将导致编译器诊断-分配无效。在第二种情况下,分配是有效的,并使x
指向y
(的第一个元素)的地址和to8ѭ的地址。除非在重新分配之前将x
的值存储在另一个指针中,否则由新表达式(new int [10]
)分配的内存将泄漏-程序不再可访问,但也不会释放。
, 第一种情况:根据栈/数据段的非静态局部变量还是静态/全局变量创建“ 22”。 x
的地址不可修改。
第二种情况:\“ x \”是指向通常在堆(免费存储)上创建的数组的指针。您也可以将x
指向其他对象。此外,您需要注意使用ѭ93进行分配
,就x都指向10个整数数组中的第一个内存地址而言,它们是相同的,但是在这方面有很大的不同
int x[10]
在静态随机存取存储器中声明该存储器,并且
关键字\'new \'与堆一起动态创建它们,与在c中使用malloc动态创建一个数组大致相同。
不仅如此,而且(我相信,还没有检验过该理论)有机会:
int* x = new int[10];
可能失败,并且取决于编译器,可能返回错误或空指针。如果c ++编译器符合ANSI / ISO标准,则它支持new的“不抛出”形式,如果分配失败,则返回null,而不是引发异常。
另一个区别是\'new \'运算符可以重载。
但是,我不确定的是(在c ++中)是否创建了一个空终止数组。我知道在c中,至少要在编译器中使用,如果您希望能够在不扩展范围的情况下对其进行迭代,则必须确保始终将\\ 0附加到任何字符串或数组。
只值我$ .02。 :)
, 如果要动态调整数组大小,例如:
void doSomething(int size)
{
int x[size]; // does not compile
int *z = new int[size];
//Do something interesting ...
doMore(z,size);
}
那么x将无法在C ++中编译,因此您必须使用z。好消息是,您现在可以在大多数情况下使用z,就像它是静态分配的一样,例如:
void doMore(int anArray[],int size)
{
// ...
}
以z为参数,将指针视为数组。