64

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?

B Faley
  • 17,120
  • 43
  • 133
  • 223
  • 2
    You might also want to check this [answer](http://stackoverflow.com/questions/4810664/how-do-i-use-arrays-in-c/4984228#4984228) from c++ faq. – cpx May 28 '11 at 07:05

8 Answers8

75
#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()

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 global it is accessible globally.

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:

delete[] z;
Ronald Rihoo
  • 98
  • 1
  • 4
Alok Save
  • 202,538
  • 53
  • 430
  • 533
  • 3
    the second way is not *exactly* as the first one. in the first case `x` is itself the base address of the array, and in the second case `x` is the pointer to the first address of the array/block – phoxis May 28 '11 at 06:08
  • 2
    Stack and heap? Are you sure? The Standard doesn't guarantee that. – Nawaz May 28 '11 at 06:13
  • a global x[10] will not be in stack. – phoxis May 28 '11 at 06:16
  • 1
    @Nawaz: Spare me the pedantic rants on that everytime! If OP is asking difference between dynamic and stack allocation its just not right to distract them with pedantic detail of stack and heap not mentioned in standard. – Alok Save May 28 '11 at 06:16
  • @phoxis: I appreciate your well made point. Hope that explains better. – Alok Save May 28 '11 at 06:24
  • 5
    @Als: Its not right to tell him that an array is created `on stack`, and pointer `on heap`. Its wrong. – Nawaz May 28 '11 at 06:28
  • @Downvoter: its riduculous to downvote on something like this. – Alok Save May 28 '11 at 06:34
  • 1
    @Als : There's correct and there's incorrect. Why is it ridiculous to downvote the latter? – ildjarn May 28 '11 at 06:35
  • 1
    @Als: `Creates a array of size of 10 integers on BSS/Data segment.` Its too much. You're writing such stuff as if its written in the language specification. – Nawaz May 28 '11 at 06:35
  • 2
    @Als : If one claims the sky is green, is it pedantic to argue or is the person simply wrong? Hmmm – ildjarn May 28 '11 at 06:42
  • 1
    @Als: Its wrong to be wrong. Its not wrong to be pedantic/correct. – Nawaz May 28 '11 at 06:44
  • 1
    Enough of the rants here..Its just wrong to misdirect a begininner with distracting talks of not stack and not heap. I am refraining myself from any firther comments here and Since you have already expressed your thinking through downvotes i suggest you refrain too. – Alok Save May 28 '11 at 06:47
  • 4
    @Als: In my opinion, its more distracting to give him implementation-details (which is not guaranteed by the language specification) than simply telling him `its an array of 10 int`. Simple and correct. Now if you want to give him more detail, then give him what is in the language. – Nawaz May 28 '11 at 06:51
  • 9
    Even being utterly, pedantically correct, Als is really right. Variables with `auto` storage class are allocated using a last-in/First-out pattern -- which *is* a stack. That stack may or may not be supported in hardware, but it's a LIFO anyway. Likewise, for dynamic allocation the standard uses the phrase "free store", but the defined operations fit those commonly associated with a "heap manager" -- allocate and free arbitrary-sized blocks of memory in an arbitrary order. Again, based on the required operations, it *is* a heap manager. "Stack" and "heap" are perfectly accurate terms. – Jerry Coffin May 28 '11 at 07:26
  • 2
    @Jerry: Aren't those implementation detail? The Standard defines the goal and the behavior of the program, and an implementation tries to achieve it using the best possible available means. Today, it's using `stack` and `heap`. But tomorrow, it might use something else, some other data structure, the better one, to achieve the same goal and the behavior. – Nawaz May 28 '11 at 07:35
  • 1
    @Nawaz: no, not really. It's a stack because it's LIFO, and the standard requires it to be LIFO. It's a heap because it supports arbitrary size and order of allocation/deallocation. The *interface* defined by the standard are those of a "stack" and a "heap manager", so regardless of how you implement them, you get a "stack" and "heap" respectively. – Jerry Coffin May 28 '11 at 07:38
  • 1
    @Nawaz: The stack and heap are the implementations that have been in place and that is what every newbie is taught, to bombard them with a detail which is not even in their mindset, neither relevant(it makes no difference if u call heap a heap or free store as long as they are made to know that new allocates memory there) and distract them from the real Q that they asked. – Alok Save May 28 '11 at 07:39
  • Compare to `std::stack`. On an x86, "the stack" is implemented about like a `std::stack >` (or, if you also look at the VM hardware, a *bit* like a `std::stack >`). On an IBM mainframe, it'll typically be more like a `std::stack >` (lacking hardware stack support, they build a linked list of stack frames). The memory organization varies with the underlying container, but they're all stacks anyway. – Jerry Coffin May 28 '11 at 07:56
  • 2
    @Jerry: What *interface* are you talking about? Also, [the heap is not the same as free store and memory allocated in one area cannot be safely deallocated in the other. Even Herb Sutter distinguishes between the two. Please read the note at the end](http://www.gotw.ca/gotw/009.htm). – Nawaz May 28 '11 at 08:00
  • 2
    @Jerry: Herb Sutter so distinguishes the two, that he writes as **Guideline** : `Prefer using the free store (new/delete). Avoid using the heap (malloc/free)` in his book Exceptional C++. – Nawaz May 28 '11 at 08:11
  • 1
    @Nawaz: I've read what Herb has to say, and he has a valid point: it's reasonable and good to distinguish between the heap managed by `malloc`, `free`, etc., and the one managed by `new` and `delete`. It doesn't hurt a thing to call one the "free store" if you prefer -- but it doesn't change the fact that it's a heap. If you really want to quibble, that does point to one common shortcoming though: people frequently refer to "*the* heap", implying there's only one. @Als has just "on heap" -- which is accurate if less than perfectly grammatical -- "on a heap" would probably be better. – Jerry Coffin May 28 '11 at 14:37
  • @Jerry: How free-store and heap are same? As far as I understand, free-store is a vague and broad term; heap implies a specific set of rules that define what it is. Also, what *interface defined by the standard* were you talking about a while back? Sorry, I'm unaware of any such interface. – Nawaz May 28 '11 at 14:43
  • 1
    As for "what interface", in the case of the "free store", the interface is ultimately `::operator new` and `::operator delete`. On the "stack" side, the interface isn't so cleanly defined as an actual interface, but when you get down to it, §6.7 is basically a long-winded way of saying that `auto` storage duration has the behavior of a stack. – Jerry Coffin May 28 '11 at 14:49
  • 1
    @Nawaz: sorry, but no. While there is a "heap" with a very specific meaning (e.g., a "binary heap"), what a "heap manager" manages is obviously a heap. That sort of heap is defined to allow allocation and deletion of objects of arbitrary size with arbitrary timing. There really aren't any other defining characteristics. – Jerry Coffin May 28 '11 at 14:51
8

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:

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,

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

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

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

Difference 2

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

Type of &x is int** in the second case

Difference 3

Given function

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

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

foo(x);     // OK for first case, not OK for second case.
R Sahu
  • 204,454
  • 14
  • 159
  • 270
8

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 static storage duration, defined by cppreference as: "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."

The second one, int y[10], uses automatic storage duration, defined by cppreference as: "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."

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

  • 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.

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:

    • automatic storage is usually allocated on the stack, which is (generally speaking) a thread-specific pre-allocated memory space using a LIFO mechanism
    • static storage uses pre-allocated memory space reserved inside the executable (more specifically .BSS and .DATA segments, depending if the variable is zero initialized or not)
    • dynamic memory is allocated using heap memory, and is subject to the mercy of the system's RAM management system and other mechanisms such as paging.
  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 &x and &z are different:

    • &x is int (*)[10]
    • &z is int **
Daniel Trugman
  • 8,186
  • 20
  • 41
6

First one is an array of int of 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 static or automatic depending on whether x is global variable or local variable.

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:

delete [] x; 

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

Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • I am sorry I am still not sure if your answer is correct due to less up votes, but I will mark it as the correct answer as soon as I get to know it is. – B Faley May 28 '11 at 06:58
  • @Maysam: Its correct. If you want to know more on *storage duration* types, and what exactly they're, I can explain that as well. – Nawaz May 28 '11 at 07:01
  • @Nawaz pls explain more on storage duration types, and what exactly they're – Eight Jun 28 '12 at 10:02
  • @programmer: In C++03, there are 3 kinds storage duration, viz. 1. *automatic storage duration* (local **non-static** variables), 2. *static storage duration* (global variables, and variables declared with `static` keyword), 3. *dynamic storage duration* (variables which are dynamically allocated, using `new` or `malloc`). C++11 has added fourth one, 4. *thread local storage duration* . You can get good information here : [Storage duration specifiers](http://en.cppreference.com/w/cpp/language/storage_duration) – Nawaz Jun 28 '12 at 10:23
3

The declarations are completely different.

The first case,

int x[10];

declares x as an array of 10 integer, whereas the second case,

int* x = new int[10];

declares x as 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.

Not withstanding the differences, the two can be used in similar ways;

  • array syntax (e.g. x[i], where i is an integral value between 0 and 9 inclusive) 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 + i is equivalent to &x[i] for i between 0 and 10 inclusive. [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 i between 0 and 9 [dereferencing a "one past the end" pointer gives undefined behaviour].

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

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

  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_t with 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.

Lifetime.

  1. In the first case, the lifetime of x depends 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 x has 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 x that 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 x and lifetime of the (dynamically allocated) array it references are decoupled, which brings us to a third difference .....

Result of assignment An array cannot be reassigned, a pointer can (unless appropriately const qualified).

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 x to point at the address of (the first element of) y and to the address of z respectively. Unless the value of x is 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.

Peter
  • 35,646
  • 4
  • 32
  • 74
0

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

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.

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.

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

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.

Just my $.02 worth. :)

Steven S
  • 7
  • 4
0

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.:

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

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

0

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

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

iammilind
  • 68,093
  • 33
  • 169
  • 336