5

These of 2 of the probably many ways of declaring arrays (and allocating memory for them) in c++

1. int a[3];

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

I want to understand how c++ is treating the two differently.

a. In both cases, i can access array with the following syntax: a[1] and b[1]

b. When i try cout<< a and cout<< b, both print the addresses of first element of respective arrays.

It looks to me as if both a and b are being treated as pointers to first elements of arrays.

c. But strangely, when i try to do cout << sizeof(a) and sizeof(b) they print different values - 4 and 12 respectively.

I don't understand why in case of sizeof(b), the size of entire array is being printed.

K Mehta
  • 10,323
  • 4
  • 46
  • 76
Nitin Garg
  • 2,069
  • 6
  • 25
  • 50
  • 4
    static allocation vs dynamic allocation, one is allocated on the stack, the other on the heap – K Mehta Jul 05 '11 at 22:02
  • 5
    @Kshitij: That's **automatic** allocation, not static. Static is load-time allocation (for global objects). – Kerrek SB Jul 05 '11 at 22:06
  • @Kerrek SB - can you elaborate the meanings and difference between automatic allocation and static allocation? I tried googling but dint found anything good. – Nitin Garg Jul 06 '11 at 19:19

4 Answers4

8

a is an array (type int [3])
b is a pointer (type int*)

In C++ they are completely different things.

The sizeof an array is the number of elements times the size of each element.
The sizeof a pointer is independent of the size of the array (usually 4 or 8 bytes).

The only thing that arrays and pointers have in common is that arrays often "decay" to pointers in several situations. That's what's happening when you print out their value.

Peter Alexander
  • 53,344
  • 14
  • 119
  • 168
  • 1
    Along with the convention that `p[n]` is treated as `*(p + n)`, so you can treat pointers like arrays, too. – Kerrek SB Jul 05 '11 at 22:07
  • 4
    -1: b is ***not*** a pointer to an array. b is a pointer to int. `int (*b)[N]` is a pointer to an array – Armen Tsirunyan Jul 05 '11 at 22:10
  • 1
    @Armen: It's both. Its type is `int*`, but it clearly points to an array as you must use `delete[]` with it. I'll clarify that. – Peter Alexander Jul 05 '11 at 22:11
  • @Peter Alexander: I removed my downvote and I know that you mean good, but terminologically, "pointer to array" is still incorrect, IMHO – Armen Tsirunyan Jul 05 '11 at 22:15
  • @Armen: Thanks for removing the down vote. I have changed it to just be a pointer. – Peter Alexander Jul 05 '11 at 22:16
  • IIRC the standard describes the result of array decay as a "pointer to the first element" of the array. Of course its type is pointer-to-element, not pointer-to-array, but equally of course, the address it contains is the address of the array, since the beginning of an array is the same location as the beginning of its first element, so in that sense it does point to the array. Similarly, a `char*` can "point to" a nul-terminated string, despite the fact that as far as type is concerned it is just a pointer to the first character of the string. – Steve Jessop Jul 05 '11 at 22:22
  • I think one can say that `b` points to an array without being ashamed. it just hasn't got the type "pointer to array". In real formal terms though, I don't know whether the "points to" relation can apply here though. The spec says at one time "a void* can be used to point to objects of unknown type", using "points to" as a colloquial term too I think. – Johannes Schaub - litb Jul 06 '11 at 05:38
  • Sorry but I'm still a little confused as to why sizeof(b) is returning 12, rather than 4, since b is just a pointer and it should really just return the size of the pointer alone, not of the entire array. Unless it was a typo by the OP and he really meant 'sizeof(a) returns 12 and sizeof(b) returns 4' which would actually make sense. – Dev Kanchen Aug 17 '11 at 11:58
  • 1
    @Dev Kanchen: Yes, it's a typo in the OP. – Peter Alexander Aug 17 '11 at 12:18
  • Ah. Makes sense. @Peter Alexander, Thanks for clearing it up. – Dev Kanchen Aug 17 '11 at 12:20
3

As you noted, it seems as though both a and b are pointers to the start of the array. But in reality, only b is a pointer. a is actually an array.

The difference between the two is subtle when writing (or reading) code. The variable a is treated as a regular variable (just like an int or double) in that it has an automatically allocated portion of memory assigned to it. For comparison, suppose you had declared int i. The variable i is the name given to a certain set of contiguous bytes in memory to hold an integer value (4 bytes on your machine). Similarly, a is the name given to the set of contiguous bytes which holds your array (12 bytes in your case).

In contrast b is only a pointer to a single memory location. In your case, there is a block of 12 bytes which is dynamically allocated (via new int[3]). b itself is an automatically allocated 4-byte pointer which points to the first int value in that 12 byte block.

So they really are two different kinds of things. This is made less clear to C++ programmers. One reason for this is the fact that you can use the [] operator on both types. Another reason is that arrays implicitly degenerate to pointers in several situations (e.g. in the function void Foo(int a[3]);, a is not actually an array, but a pointer to the beginning of the array). But don't be fooled - arrays are not pointers (as many people claim), and pointers are definitely not arrays.

Ken Wayne VanderLinde
  • 18,915
  • 3
  • 47
  • 72
0

1 is allocated on the stack. Arrays on the stack must have a size known at compile-time.

2 is allocated on the heap. Arrays on the heap have no such requirement. Remember if you allocate with new[] you need to deallocate it later with delete[]:

int* b = new int[3];
delete[] b;
  • 4
    1 isn't necessarily on the stack. If it's a member of a class and an instance of that class is allocated on the heap then the array will be in the heap. Do not confuse "the stack" with automatic storage. – Peter Alexander Jul 05 '11 at 22:06
  • 1) is sort of true, but things like `alloca` or variable-length arrays effectively allow you to allocate automatic objects of variable length, too. – Kerrek SB Jul 05 '11 at 22:08
  • Good point, although I just assumed that in his example it was on the stack. –  Jul 05 '11 at 22:09
  • Also the first example could be global, hence neither on the stack nor on the heap, but static. – Kerrek SB Jul 05 '11 at 22:11
0

C++ arrays in the stack have a limitation that

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

C++ arrays in the heap only have the 2nd limitation, but not the first one. (this allows array size to be determined on runtime)

tp1
  • 1,197
  • 10
  • 17
  • Just to clarify: the size of a dynamically-allocated array must be determined before the actual allocation, and will probably also be stored in a variable. There is no way to look at the array itself and deduce its size. – Ken Wayne VanderLinde Jul 06 '11 at 02:30