声明int数组

Mey*_*sam 63 c++ arrays pointers initialization

这两个声明之间有什么区别吗?

int x[10];
Run Code Online (Sandbox Code Playgroud)

int* x = new int[10];
Run Code Online (Sandbox Code Playgroud)

我认为前一个声明(如后一个声明)是一个指针声明,两个变量都可以相同.这是否意味着它们本质上是一样的?

Alo*_*ave 75

#include<iostream>    

int y[10];


void doSomething()
{
    int x[10];
    int *z  = new int[10];
    //Do something interesting

    delete []z;
}

int main()
{
    doSomething();

}
Run Code Online (Sandbox Code Playgroud)

‏‏‏‏‏‏‏

int x[10]; 
Run Code Online (Sandbox Code Playgroud)

- 在堆栈上创建一个大小为10的整数数组.
- 您不必显式删除此内存,因为它会在堆栈展开时消失.
- 其范围仅限于此功能doSomething()

int y[10];
Run Code Online (Sandbox Code Playgroud)

- 在BSS /数据段上创建一个大小为10的整数数组.
- 您不必明确删除此内存.
- 因为它被声明global它是全球可访问的.

int *z = new int[10];
Run Code Online (Sandbox Code Playgroud)

- 在堆上分配一个大小为10的整数的动态数组,并返回该内存的地址z.
- 使用后必须明确删除此动态内存.使用:

delete[] z;
Run Code Online (Sandbox Code Playgroud)

  • 即使完全,迂腐正确,Als也是如此.具有`auto`存储类的变量使用后进/先出模式分配 - *是*堆栈.硬件可能支持也可能不支持该堆栈,但无论如何它都是LIFO.同样,对于动态分配,标准使用短语"free store",但定义的操作适合通常与"堆管理器"相关联的操作 - 以任意顺序分配和释放任意大小的内存块.同样,根据所需的操作,它*是一个堆管理器."堆栈"和"堆积"是完全准确的术语. (9认同)
  • @Als:告诉他在堆栈上创建一个数组,并在堆上创建指针`是不对的.这是不对的. (5认同)
  • @Als:在我看来,给他的实现细节(语言规范无法保证)比仅仅告诉他`它是一个10 int的数组'更令人分心.简单而正确.现在,如果你想给他更详细的信息,那就给他一些语言. (4认同)
  • 第二种方式不是*完全*作为第一种方式.在第一种情况下,`x`本身是数组的基地址,在第二种情况下,`x`是指向数组/块的第一个地址的指针 (3认同)
  • 堆栈和堆?你确定吗?标准不保证. (2认同)
  • @Als:如果有人声称天空是绿色的,那么争论是迂腐还是这个人完全错了?嗯 (2认同)
  • @Jerry:那些实现细节不是吗?标准定义了程序的目标和行为,并且实现尝试使用尽可能最好的方法来实现它.今天,它使用`stack`和`heap`.但明天,它可能会使用其他东西,其他一些数据结构,更好的数据结构,以实现相同的目标和行为. (2认同)
  • @Jerry:你在说什么*界面*?此外,[堆与免费存储不同,并且在一个区域中分配的内存无法在另一个区域中安全地释放.甚至Herb Sutter也区分了两者.请阅读末尾的说明](http://www.gotw.ca/gotw/009.htm). (2认同)
  • @Jerry:Herb Sutter如此区别两者,他写作**指南**:`首选使用免费商店(新/删除).避免在他的书Exceptional C++中使用堆(malloc/free)`. (2认同)

R S*_*ahu 8

唯一相似之处

int x[10];
Run Code Online (Sandbox Code Playgroud)

int* x = new int[10];
Run Code Online (Sandbox Code Playgroud)

是否可以在int*预期的某些上下文中使用:

int* b = x;   // Either form of x will work

void foo(int* p) {}

foo(x);      // Either form will work
Run Code Online (Sandbox Code Playgroud)

但是,它们不能用于int*期望a的所有上下文中.特别,

delete [] x;  // UB for the first case, necessary for the second case.
Run Code Online (Sandbox Code Playgroud)

其他答案中已经解释了一些核心差异.其他核心差异是:

差异1

sizeof(x) == sizeof(int)*10   // First case

sizeof(x) == sizeof(int*)     // Second case.
Run Code Online (Sandbox Code Playgroud)

差异2

类型&xint (*)[10]第一种情况

类型&xint**第二种情况

差异3

给定功能

void foo(int (&arr)[10]) { }
Run Code Online (Sandbox Code Playgroud)

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

foo(x);     // OK for first case, not OK for second case.
Run Code Online (Sandbox Code Playgroud)


Naw*_*waz 6

第一个是int大小的数组10.说它在堆栈上创建是错误的.因为标准不保证.它的实现定义.它的存储持续时间可以是静态的自动的,具体取决于x全局变量还是局部变量.

在第二个中,您创建一个类型的指针int*.不一定是在堆上创建的,标准没有这么说.分配的内存跨越10 * sizeof(int)字节.为此,您需要通过编写以下内容来释放内存:

delete [] x; 
Run Code Online (Sandbox Code Playgroud)

在这种情况下,指针的存储器x被动态分配并动态地解除分配,因此这些对象被称为具有动态存储持续时间.


Dan*_*man 6

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

int x[10];

void method() {
     int y[10];
     int *z = new int[10];
     delete z;
}
Run Code Online (Sandbox Code Playgroud)

第一个声明int x[10]使用静态存储持续时间,由cppreference定义为:"当程序开始时分配对象的存储,程序结束时分配对象的存储.只存在一个对象实例.在命名空间范围内声明的所有对象(包括全局命名空间)具有此存储持续时间,以及使用static或extern声明的持续时间."

第二个,int y[10]使用自动存储持续时间,由cppreference定义为:"对象在封闭代码块的开头分配并在末尾解除分配.所有本地对象都有此存储持续时间,除了那些声明为static,extern或thread_local的存储持续时间".

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

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

正如其他评论中已经提到的,这些类型的声明有其微妙的差异,但最常见的是:

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

  2. 动态分配的内存应由delete程序员明确指定,而静态和自动存储变量由"环境"处理

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

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

  5. (正如@R Sahu已经指出的那样)&x&z不同的类型:

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