C++中两种数组声明方法的区别

5

这是在c++中声明数组(并为它们分配内存)的两种可能方法之一。

1. int a[3];

2. int *b = new int[3];

我想了解c++如何区别对待这两个不同的数组。

a. 在两种情况下,我都可以使用以下语法访问数组:a[1]b[1]

b. 当我尝试输出 cout<< acout<< b 时,它们都打印各自数组第一个元素的地址。

在我看来,似乎a和b都被视为指向数组第一个元素的指针。

c. 但奇怪的是,当我尝试执行 cout << sizeof(a)sizeof(b) 时,它们分别打印出不同的值 - 4 和 12。

我不明白为什么在 sizeof(b) 的情况下,会打印整个数组的大小。


4
静态分配与动态分配,一个被分配在栈上,另一个被分配在堆上。 - K Mehta
5
@Kshitij:那是自动分配,不是静态的。静态是指在加载时为全局对象分配内存。 - Kerrek SB
@Kerrek SB - 你能详细解释一下自动分配和静态分配的含义和区别吗?我试着在谷歌上搜索,但没有找到什么好的资料。 - Nitin Garg
4个回答

8

a是一个数组(类型为int [3]
b是一个指针(类型为int*)。

在C++中,它们是完全不同的东西。

sizeof操作符用于计算数组的大小,其大小为元素数量乘以每个元素的大小。
而指针的sizeof操作结果与数组的大小无关(通常为4或8字节)。

数组和指针唯一相似之处在于,在几种情况下,数组通常会“退化”为指针。这就是当您打印它们的值时发生的情况。


1
除了 p[n] 被视为 *(p + n) 的约定外,您也可以像处理数组一样处理指针。 - Kerrek SB
4
b不是指向数组的指针,而是指向int的指针。int (*b)[N]是一个指向数组的指针。 - Armen Tsirunyan
1
@Armen:是这样的。它的类型是int*,但你必须使用delete[]来清除它,因此它显然指向一个数组。我会澄清这一点。 - Peter Alexander
据我所知,标准将数组衰减的结果描述为数组的“第一个元素的指针”。当然,它的类型是指向元素的指针,而不是指向数组的指针,但同样显然,它所包含的地址是数组的地址,因为数组的开头与其第一个元素的开头相同,所以从这个意义上说,它确实指向数组。同样地,char*可以“指向”以空字符结尾的字符串,尽管就类型而言,它只是指向字符串的第一个字符的指针。 - Steve Jessop
1
@Dev Kanchen:是的,这是原帖中的一个错别字。 - Peter Alexander
显示剩余5条评论

3
正如你所指出的那样,看起来ab都是指向数组开头的指针。但实际上只有b是指针,a实际上是一个数组。
在编写(或阅读)代码时,这两者之间的区别微妙。变量a被视为常规变量(就像intdouble一样),因为它具有自动分配的内存部分。举个例子,假设你声明了int i。变量i是给定一组连续字节的名称,用于保存整数值(在你的机器上为4个字节)。同样,a是给定一组连续字节的名称,用于保存数组(在你的情况下为12个字节)。
相比之下,b仅是指向单个内存位置的指针。在你的情况下,有一个12字节的块是通过new int[3]动态分配的。b本身是自动分配的4字节指针,指向该12字节块中的第一个int值。
因此,它们确实是两种不同的东西。这对于C++程序员来说并不明显。其中一个原因是你可以在这两种类型上使用[]运算符。另一个原因是数组在几种情况下会隐式退化为指针(例如,在函数void Foo(int a[3]);中,a实际上不是数组,而是指向数组开头的指针)。但别被愚弄了 - 数组不是指针(正如许多人所说),指针也绝对不是数组。

0

1 在堆栈上分配。在堆栈上的数组必须在编译时知道大小。

2 在堆上分配。在堆上的数组没有这样的要求。请记住,如果您使用 new[] 分配内存,则需要稍后使用 delete[] 进行释放:

int* b = new int[3];
delete[] b;

4
如果一个数组是类的成员变量,并且该类的实例被分配在堆上,那么该数组并不一定在栈上。不要混淆"栈"和自动存储。请注意,自动存储不一定等同于栈。 - Peter Alexander
这有点正确,但是像alloca或可变长度数组之类的东西实际上也允许您分配可变长度的自动对象。 - Kerrek SB
不错的观点,尽管我只是假设他的例子在堆栈上。 - user802003
同时,第一个示例可以是全局的,因此既不在堆栈上也不在堆上,而是静态的。 - Kerrek SB

0

C++中堆栈数组有一个限制

int array[10];
sizeof(array) needs to be compile-time constant and
sizeof(array[0])==sizeof(array[1])==...==sizeof(array[9])

C++堆中的数组只有第二个限制,而没有第一个限制。(这允许在运行时确定数组大小)


只是为了澄清:动态分配数组的大小必须在实际分配之前确定,并且可能也会存储在变量中。无法查看数组本身并推断其大小。 - Ken Wayne VanderLinde

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接