C++ 声明 int 数组

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6159968/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 19:34:33  来源:igfitidea点击:

Declaring array of int

c++arrayspointersinitialization

提问by Meysam

Is there any difference between these two declarations?

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

int x[10];

vs.

对比

int* x = new int[10];

I suppose the former declaration (like the latter one) is a pointer declaration and both variables could be treated the same. Does it mean they are intrinsically the same?

我想前一个声明(像后一个一样)是一个指针声明,两个变量可以被同等对待。这是否意味着它们本质上是相同的?

回答by Alok Save

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

- Creates an array of size 10 integers on stack.
- You do not have to explicitly delete this memory because it goes away as stack unwinds.
- Its scope is limited to the function doSomething()

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

int y[10];

- Creates an array of size 10 integers on BSS/Data segment.
- You do not have to explicitly delete this memory.
- Since it is declared globalit is accessible globally.

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

int *z = new int[10];

- Allocates a dynamic array of size 10 integers on heap and returns the address of this memory to z.
- You have to explicitly delete this dynamic memory after using it. using:

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

delete[] z;

回答by R Sahu

The only thing similar between

之间唯一相似的东西

int x[10];

and

int* x = new int[10];

is that either can be used in some contexts where a int*is expected:

是可以在需要 a 的某些上下文中使用int*

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

void foo(int* p) {}

foo(x);      // Either form will work

However, they cannot be used in all contexts where a int*is expected. Specifically,

但是,它们不能用于需要 a 的所有上下文int*。具体来说,

delete [] x;  // UB for the first case, necessary for the second case.

Some of the core differences have been explained in the other answers. The other core differences are:

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

Difference 1

差异1

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

sizeof(x) == sizeof(int*)     // Second case.

Difference 2

差异2

Type of &xis int (*)[10]in the first case

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

Type of &xis int**in the second case

类型&xint**第二种情况

Difference 3

差异3

Given function

给定函数

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

you can call it using the first xnot the second x.

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

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

回答by Daniel Trugman

According to the standard, we should actually distinguish between three different types of array declarations:

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

int x[10];

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

The first declaration, int x[10], uses staticstorage duration, defined by cppreferenceas: "The storage for the object is allocated when the program begins and deallocated when the program ends. Only one instance of the object exists. All objects declared at namespace scope (including global namespace) have this storage duration, plus those declared with static or extern."

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

The second one, int y[10], uses automaticstorage duration, defined by cppreferenceas: "The object is allocated at the beginning of the enclosing code block and deallocated at the end. All local objects have this storage duration, except those declared static, extern or thread_local."

第二个,int y[10]使用自动存储持续时间,由cppreference定义为:“对象在封闭代码块的开头分配并在结束时释放。所有本地对象都有这个存储持续时间,除了那些声明为 static、extern 或 thread_local 的对象.”

The third one, int *z = new int[10], is usually referred to as dynamicmemory allocation, and is actually a two-step sequence:

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

  • First, the operator new is called, which allocated memory dynamically using either the default allocation methods of the standard library or a user defined implementation (since new can be overridden during run-time). The allocated memory will be sufficient to fit the N elements allocated, plus any additional memory required to keep metadata for the given allocation (so that it can be later successfully freed).
  • Second, if the first step is successful, we then proceed to initialize or construct each object in the array.
  • 首先,调用运算符 new,它使用标准库的默认分配方法或用户定义的实现动态分配内存(因为 new 可以在运行时被覆盖)。分配的内存将足以容纳分配的 N 个元素,以及为给定分配保留元数据所需的任何额外内存(以便以后可以成功释放)。
  • 其次,如果第一步成功,我们将继续初始化或构造数组中的每个对象。

As already mentioned by other comments, these types of declaration have their subtle differences, but the most common ones are:

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

  1. On most modern operating systems:

  2. Dynamically allocated memory should be explicitly delete-ed by the programmer, whereas static and automatic storage variables are taken care of by the "environment"

  3. Static and automatic storage variables are limited to a specific scope, whereas dynamically allocated memory has no bounds, meaning, a variable declared in one module, can be passed to any other module that operates in the same address space

  4. When allocating an array using new[], the size can be 0

  5. (As already pointed out by @R Sahu) The types of &xand &zare different:

    • &xis int (*)[10]
    • &zis int **
  1. 在大多数现代操作系统上:

    • 自动存储通常是在栈上分配的,也就是(一般来说)使用LIFO机制预先分配的线程特定的内存空间
    • 静态存储使用在可执行文件内部保留的预分配内存空间(更具体地说是 .BSS 和 .DATA 段,取决于变量是否初始化为零
    • 动态内存是使用堆内存分配的,受制于系统的 RAM 管理系统和其他机制(如分页)的摆布。
  2. 动态分配的内存应该delete由程序员显式设置,而静态和自动存储变量由“环境”处理

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

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

  5. (如已经由@R萨胡指出)的类型&x&z是不同的:

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

回答by Nawaz

First one is an array of intof size 10. Saying that its created on stack is wrong. Because the Standard doesn't guarantee that. Its implementation-defined. Its storage duration could be staticor automaticdepending on whether xis globalvariable or localvariable.

第一个是int大小为 的数组10。说它在堆栈上创建是错误的。因为标准并不能保证这一点。它的实现定义。根据是全局变量还是局部变量,其存储持续时间可以是静态的自动的x

In the second one, you create a pointer of type int*. Not necessarily created on heap, the Standard doesn't say that. The allocated memory spans over 10 * sizeof(int)bytes. For this you've to deallocate the memory yourself, by writing:

在第二个中,您创建一个类型为 的指针int*。不一定在堆上创建,标准没有这么说。分配的内存跨越10 * sizeof(int)字节。为此,您必须自己释放内存,通过编写:

delete [] x; 

In this case, the memory of the pointer xis dynamically allocated, and dynamically deallocated, so such objects is said to have dynamic storage duration.

在这种情况下,指针的内存x是动态分配的,然后是动态释放的,所以说这样的对象具有动态存储期

回答by Peter

The declarations are completely different.

声明完全不同。

The first case,

第一种情况,

int x[10];
int x[10];

declares xas an array of 10integer, whereas the second case,

声明x10整数数组,而第二种情况,

int* x = new int[10];
int* x = new int[10];

declares xas a pointer to int- a variable with value equal to an address of an int, and initialises that pointer to the result of a new expression (new int [10]) that dynamically allocates an array of ten integers.

声明x为指向int- 值等于 an 地址的变量的指针int,并将该指针初始化为new int [10]动态分配十个整数数组的新表达式 ( )的结果。

Not withstanding the differences, the two can be usedin similar ways;

不能承受的差异,两者可以使用类似的方法;

  • array syntax (e.g. x[i], where iis an integral value between 0and 9inclusive) can be used to set or retrieve values of the respective arrays in the above syntax;
  • pointer arithmetic can be used to obtain an address of an element of the array (e.g. x + iis equivalent to &x[i]for ibetween 0and 10inclusive. [yes, it is possible to obtain "one past the end" address];
  • Pointer dereferencing and array access are equivalent. i.e. *(x+i)and x[i]are equivalent, for ibetween 0and 9[dereferencing a "one past the end" pointer gives undefined behaviour].
  • 数组语法(例如x[i],其中i是介于0和之间的整数值9)可用于设置或检索上述语法中各个数组的值;
  • 指针算术可用于获取数组元素的地址(例如x + i,相当于&x[i]for ibetween 0and 10inclusive。[是的,可以获取“最后一个”地址];
  • 指针解引用和数组访问是等效的。即 *(x+i)x[i]是等价的,因为i0和之间9[取消引用“结束后的一个”指针会给出未定义的行为]。

However, there are also some key differences, for example;

但是,也存在一些关键差异,例如;

Results of the sizeofoperator. sizeof(x)gives different values in the two cases.

该结果sizeof操作sizeof(x)在两种情况下给出不同的值。

  1. In the first case sizeof(x) == sizeof(int)*10. sizeof(int)gives an implementation-defined balue, but sizeof(x)/sizeof(*x)will always give the number of elements in the array (i.e. a std::size_twith value 10).
  2. In the second, sizeof(x) == sizeof(int *)- which is an implementation-defined value. The value of sizeof(x)/sizeof(*x)is practically exceedingly unlikely to yield a value of 10. Which means this technique cannot be used to obtain the number of elements.
  1. 在第一种情况下sizeof(x) == sizeof(int)*10sizeof(int)给出一个实现定义的 balue,但sizeof(x)/sizeof(*x)总是给出数组中元素的数量(即 astd::size_t与 value 10)。
  2. 在第二个中,sizeof(x) == sizeof(int *)- 这是一个实现定义的值。的值sizeof(x)/sizeof(*x)实际上极不可能产生 的值10。这意味着该技术不能用于获取元素数量。

Lifetime.

终身

  1. In the first case, the lifetime of xdepends on the scope in which the declaration occurs. If the declaration occurs at file scope (i.e. in a compilation unit, outside any function block), then xhas static storage duration (so exists for as long as the program is running). If the declaration occurs in a block, x- and all its elements - ceases to exist when the block ends. For example

    {
        int x[10];
    
    }    //  x and all its elements cease to exist here
    
  2. In the second case, it is only the pointer xthat has a lifetime that depends on scope. The dynamically allocated memory (the result of new x[10]) is never deallocated. This means the lifetime of xand lifetime of the (dynamically allocated) array it references are decoupled, which brings us to a third difference .....

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

    {
        int x[10];
    
    }    //  x and all its elements cease to exist here
    
  2. 在第二种情况下,只有指针x的生命周期取决于作用域。动态分配的内存( 的结果new x[10])永远不会被释放。这意味着x它引用的(动态分配的)数组的生命周期和生命周期是解耦的,这给我们带来了第三个区别......

Result of assignmentAn array cannot be reassigned, a pointer can (unless appropriately constqualified).

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

Consider a context of

考虑一个上下文

 // x as previously defined in one or the other form

 int y[10];
 int z;

 x = y;
 x = &z;

In the first case, both assignments will result in a compiler diagnostic - the assignments are invalid. In the second case, the assignments are valid and cause xto point at the address of (the first element of) yand to the address of zrespectively. Unless the value of xis stored in another pointer before reassignment, the memory allocated by the new expression (new int [10]) is leaked - it is no longer accessible by the program, but is not released either.

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

回答by Steven S

They are the same as far as both x's point to the first memory address in the array of 10 integers, however very different in that

就两个 x 指向 10 个整数数组中的第一个内存地址而言,它们是相同的,但是非常不同

int x[10] 

declares the memory in static random access memory, and the keyword 'new' creates them dynamically with the heap, and is about the same as using malloc in c to dynamically create an array.

声明静态随机存取内存中的内存,关键字new是用堆动态创建的,和c中用malloc动态创建数组差不多。

Not only that, but (I believe, haven't tested the theory) there is a chance that:

不仅如此,而且(我相信,还没有测试过该理论)还有可能:

int* x = new int[10];

could fail, and depending on the compiler, could return an error or a null pointer. If the c++ compiler adheres to ANSI/ISO standards, then it supports a "no-throw" form of new which returns a null if allocation fails, rather than throwing an exception.

可能会失败,并且取决于编译器,可能会返回错误或空指针。如果 c++ 编译器遵守 ANSI/ISO 标准,那么它支持 new 的“不抛出”形式,如果分配失败则返回 null,而不是抛出异常。

The other difference being that the 'new' operator can be overloaded.

另一个区别是“new”运算符可以重载。

What I'm not sure of, however, is if either one (in c++) creates a null terminated array. I know that in c, in the compiler I use at least, you must make sure to always append a \0 to any strings or arrays if you expect to be able to iterate over them without overextending the bounds.

然而,我不确定的是,是否有任何一个(在 C++ 中)创建了一个空终止数组。我知道在 c 中,至少在我使用的编译器中,如果您希望能够在不过度扩展边界的情况下迭代它们,则必须确保始终将 \0 附加到任何字符串或数组。

Just my $.02 worth. :)

只是我的 0.02 美元。:)

回答by William H. Hooper

If you want to size an array dynamically, e.g.:

如果要动态调整数组大小,例如:

void doSomething(int size)
{
    int x[size];               // does not compile
    int *z  = new int[size];
    //Do something interesting ...
    doMore(z, size);
}

then x will not compile in C++, so you have to use z. The good news is that you can now use z, in most cases, as though it were statically allocated, e.g.:

那么 x 不会在 C++ 中编译,所以你必须使用 z。好消息是,在大多数情况下,您现在可以使用 z,就好像它是静态分配的一样,例如:

void doMore(int anArray[], int size)
{
    // ...
}

takes z as an argument, treating the pointer as an array.

将 z 作为参数,将指针视为数组。

回答by iammilind

First case: xis created on stack/data segment based on whether it's non-static local variable or static/global variable. And address of xis not modifiable.

第一种情况:x根据它是非静态局部变量还是静态/全局变量在堆栈/数据段上创建。并且地址x不可修改。

Second case: 'x' is a pointer pointing to an array created generallyon heap (free store). You can change xpointing to something else also. Moreover, you need to take care of deallocating it by using delete[] x;

第二种情况:'x' 是指向通常在堆(自由存储)上创建的数组的指针。您也可以更改x指向其他内容。此外,您需要注意使用delete[] x;