声明int的数组

这两个声明有什么区别?

int x[10]; 

 int* x = new int[10]; 

我想前面的声明(就像后面的声明)是一个指针声明,两个variables都可以被视为相同的。 这是否意味着它们本质上是一样的?

 #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]; 

– 在堆栈上创build一个大小为10的整数数组。
– 你不必显式地删除这个内存,因为它随着堆栈展开而消失。
– 它的范围仅限于函数doSomething()

 int y[10]; 

– 在BSS /数据段上创build一个大小为10的整数数组。
– 您不必显式删除此内存。
– 由于它是global它可以在全球范围内使用。

 int *z = new int[10]; 

– 在堆上分配一个大小为10的整数的dynamic数组,并将该内存的地址返回给z
– 你必须在使用它之后明确地删除这个dynamic内存。 使用:

 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

在第一种情况下, &xtypes是int (*)[10]

在第二种情况下, &xtypes是int**

区别3

给定function

 void foo(int (&arr)[10]) { } 

你可以使用第一个x而不是第二个x来调用它。

 foo(x); // OK for first case, not OK for second case. 

第一个是大小为10int数组。 说它在堆栈上创build是错误的。 因为标准不能保证。 其实现定义。 它的存储时间可以是静态的也可以是自动的,取决于x全局variables还是局部variables。

在第二个,你创build一个int*types的指针。 标准不一定在堆上创build,标准不会这么说。 分配的内存跨越10 * sizeof(int)个字节。 为此,你必须自己释放记忆,写下:

 delete [] x; 

在这种情况下,指针x的内存被dynamic地分配,并被dynamic地解除分配,所以这样的对象被称为具有dynamic存储持续时间

根据标准,我们应该实际区分三种不同types的数组声明:

 int x[10]; void method() { int y[10]; int *z = new int[10]; delete z; } 

第一个声明int x[10]使用由cppreference定义的静态存储持续时间:“对象的存储在程序开始时被分配,当程序结束时被释放,只存在对象的一个​​实例。在名称空间范围(包括全局名称空间)有这个存储持续时间,加上那些声明与静态或外部“。

第二个函数int y[10]使用自动存储持续时间,由cppreference定义为:“对象分配在封闭代码块的开始位置,并在结束时释放,所有本地对象都有这个存储持续时间,静态,外部或thread_local“。

第三个int *z = new int[10]通常被称为dynamic内存分配,实际上是一个两步的序列:

  • 首先调用operator new,它使用标准库的默认分配方法或用户定义的实现(因为new可以在运行时被覆盖)dynamic地分配内存。 分配的内存将足以适应分配的N个元素,加上为给定分配保留元数据所需的额外内存(以便稍后可以成功释放)。
  • 其次,如果第一步成功,我们继续初始化或构造数组中的每个对象。

正如其他评论已经提到的那样,这些types的声明有微妙的差别,但最常见的是:

  1. 在大多数现代操作系统上:

    • 自动存储通常在堆栈上分配,这通常是使用LIFO机制的线程专用的预分配内存空间
    • 静态存储使用预先分配的可执行文件内存空间( 更具体地说,.BSS和.DATA段,取决于variables是否初始化为零 )
    • dynamic内存使用堆内存进行分配,并受制于系统的RAMpipe理系统和寻呼等其他机制。
  2. dynamic分配的内存应由程序员明确delete ,而静态和自动存储variables由“环境”

  3. 静态和自动存储variables被限制在一个特定的范围内,而dynamic分配的内存没有边界,这意味着在一个模块中声明的variables可以传递到在相同地址空间中运行的任何其他模块

  4. 使用new[]分配数组时,大小可以是0

  5. (正如@R Sahu所指出的那样) &x&z的types是不同的:

    • &xint (*)[10]
    • &zint **

声明是完全不同的。

第一种情况,

 int x[10]; 

x声明为10整数的数组,而第二种情况,

 int* x = new int[10]; 

声明x为指向int的指针 – 一个值等于int地址的variables,并初始化指向新expression式( new int [10] )的结果的指针,该expression式dynamic地分配十个整数的数组。

不pipe有什么不同,两者可以相似的方式使用;

  • 可以使用数组语法(例如, x[i] ,其中i09之间的整数值)来设置或检索上述语法中的各个数组的值;
  • 指针运算可以用来获得数组元素的地址(例如x + i相当于&x[i]对于i010之间(包括010 (是的,可以获得“one of the end”地址]。
  • 指针取消引用和数组访问是等价的。 即*(x+i)x[i]是等价的,因为i介于09之间[解除引用“一个超过结尾”指针给出未定义的行为]。

但是,也有一些关键的差异,

运算符sizeof结果sizeof(x)在两种情况下给出不同的值。

  1. 在第一种情况下sizeof(x) == sizeof(int)*10sizeof(int)给出了一个实现定义的balue,但sizeof(x)/sizeof(*x)将始终给出数组中元素的数量(即一个值为10std::size_t )。
  2. 在第二个, sizeof(x) == sizeof(int *) – 这是一个实现定义的值。 sizeof(x)/sizeof(*x)值实际上不太可能产生10的值。 这意味着这种技术不能用来获取元素的数量。

终身

  1. 在第一种情况下, x的生存期取决于声明发生的范围。 如果声明出现在文件范围(即在编译单元中,在任何function块之外),则x具有静态存储持续时间(只要程序正在运行就存在)。 如果声明出现在块中,则块及其所有元素在块结束时不再存在。 例如

     { int x[10]; } // x and all its elements cease to exist here 
  2. 在第二种情况下,只有指针x的生命周期取决于范围。 dynamic分配的内存( new x[10]的结果)永远不会被释放。 这意味着x的生命周期和它所引用的(dynamic分配的)数组的生命周期是分离的,这就带来了第三个差异…..

赋值结果一个数组不能被重新分配,一个指针可以(除非适当的const限定)。

考虑一下上下文

  // x as previously defined in one or the other form int y[10]; int z; x = y; x = &z; 

在第一种情况下,这两个分配都会导致编译器诊断 – 分配无效。 在第二种情况下,赋值是有效的,并使得x分别指向y (的第一个元素)的地址和z的地址。 除非x的值在重新分配之前存储在另一个指针中,否则由新expression式( new int [10] )分配的内存将被泄漏 – 程序将不能再访问它,但也不会被释放。

第一种情况:根据是非静态局部variables还是静态/全局variables,在堆栈/数据段上创buildxx地址是不可修改的。

第二种情况:“x”是一个指向通常在堆上创build的数组的指针(自由存储)。 你也可以改变x指向别的东西。 而且,你需要注意通过使用delete[] x;来释放它delete[] x;

它们是相同的,就像这两个x指向10个整数数组中的第一个存储地址一样,然而在这个数组中非常不同

 int x[10] 

在静态随机存取内存中声明内存,关键字'new'使用堆dynamic创build它们,与在c中使用mallocdynamic创build数组大致相同。

不仅如此,而且(我相信,没有检验过这个理论)有一个​​机会:

 int* x = new int[10]; 

可能会失败,并根据编译器,可能会返回一个错误或一个空指针。 如果c ++编译器符合ANSI / ISO标准,那么它支持新的“不抛出”forms,如果分配失败,则返回null,而不抛出exception。

另一个区别是“新”操作符可能被重载。

然而,我不确定的是,如果任何一个(在c + +中)创build一个null终止数组。 我知道在c中,在我至less使用的编译器中,如果您希望能够在不超出边界的情况下迭代它们,则必须确保总是将\ 0附加到任何string或数组。

只是我的0.02美元的价值。 🙂