For the following code:
foo(int n){
int array[n];
}
I understand that this is invalid syntax and that it is invalid because the c++ sta
In the first case you are allocating the memory space statically to hold the integers. This is done when the program is compiled and so the amount of storage is inflexible.
In the latter case you are dynamically allocating a memory space to hold the integers. This is done when the program is run, and so the amount of storage required can be flexible.
The second call is actually a function that talks to the operating system to go and find a place in memory to use. That same process does not happen in the first case.
In the expression
new int[n]
int[n]
is not the type. C++ treats "new
with arrays" and "new
with non-arrays" differently. The N3337 standard draft has this to say about new
:
When the allocated object is an array (that is, the noptr-new-declarator syntax is used or the new-type-id or type-id denotes an array type), the new-expression yields a pointer to the initial element (if any) of the array.
The noptr-new-declarator refers to this special case (evaluate n
and create the array of this size), see:
noptr-new-declarator:
[ expression ] attribute-specifier-seqopt
noptr-new-declarator [ constant-expression ] attribute-specifier-seqopt
However you can't use this in the "usual" declarations like
int array[n];
or in the typedef
typedef int variable_array[n];
This is different with C99 VLAs, where both are allowed.
Should I be using vectors instead?
Yes, you should. You should use vectors all the time, unless you have a very strong reason to do otherwise (there was one time during the last 7 years when I used new
- when I was implementing vector
for a school assignment).
No, the second is not declaring an array. It's using the array form of operator new
, and that specifically permits the first dimension to be variable.
You can allocate memory statically on the stack or dynamically on the heap.
In your first case, your function contains a declaration of an array with a possible variable length, but this is not possible, since raw arrays must have fixed size at compile time, because they are allocated on the stack. For this reason their size must be specified as a constant, for example 5
. You could have something like this:
foo(){
int array[5]; // raw array with fixed size 5
}
Using pointers you can specify a variable size for the memory that will be pointed, since this memory will be allocated dynamically on the heap. In your second case, you are using the parameter n
to specify the space of memory that will be allocated.
Concluding, we can say that pointers are not arrays: the memory allocated using a pointer is allocated on the heap, whereas the memory allocated for a raw array is allocated on the stack.
There are good alternatives to raw arrays, for example the standard container vector, which is basically a container with variable length size.
Make sure you understand well the difference between dynamic and static memory allocation, the difference between memory allocated on the stack and memory allocated on the heap.
That's because the former is allocated on the stack and the latter on the heap.
When you allocate something on the stack, knowing the size of the object is essential for correctly building it. C99 allows the size to be specified at run time, and this introduces some complications in building and dismantling the aforementioned stack, since you cannot calculate its size at compile time. Machine code must be emitted in order to perform said calculation during the execution of the program. This is probably the main reason why this feature wasn't included in the C++ standard.²
On the contrary, the heap has no fixed structure, as the name implies. Blocks of any size can be allocated with no particular order, as long as they do not overlap and you have enough (virtual) memory¹. In this case, knowing the size at compile time is not that relevant.
Also, remember that the stack has a limited size, mostly to detect infinite recursions before they consume all the available memory. Usually the limit is fixed around 1MB, and you rarely reach that. Unless you allocate large objects, which should be placed in the heap.
As of what you should use, probably a std::vector<int>
. But it really depends on what you are trying to do.
Also note that C++11 has a std::array
class, whose size must be known at compile time. C++14 should have introduced std::dynarray
, but it was postponed because there is still much work to do concerning compile-time unknown size stack allocation.
¹ blocks are usually allocated sequentially for performance reasons, but that's not required.
² as pointed out, knowing the size at compile time is not a hard requirement, but it makes things simpler.
int array[n]
allocates a fixed-length array on the call stack at compile-time, and thus n
needs to be known at compile-time (unless a compiler-specific extension is used to allow the allocation at runtime, but the array is still on the stack).
int *array = new int[n]
allocates a dynamic-length array on the heap at run-time, so n
does not need to be known at compile-time.