dynamic array declaration in different ways - c++

I know that int* array = new int [n]; allocates memory space in heap.
But if I declare something like that: int array[n]; in codeblocks it compile successfully, but if I move it to visual studio, it comes out of error.
What I want to ask is:
What does int[n] really do and how does it compare to heap allocation? What is the difference between them?
What the error may come out if I use int array[n] instead of int* array = new int [n];?

int array[n] declares an array on the stack, not the heap. In standard C++ n must be a compile time constant, however some compilers have an extension that allows for variable length arrays declared in this form without a compile time constant n. It's not standard and probably shouldn't be used.
int array[n] can cause a couple problems over int* array = new int [n];:
If n is big enough you can cause a stack overflow. Or if the array is a class member and you create a large array of the class.
If array is a class member moving could be as expensive as copying
If array is a class member and you have given out pointers to the array and move the class, the pointers now refer to a post-moved object, or if random memory if the object was also destroyed. Either way, bad.

GCC has an extension in C++ that allows int array[n] where n is not a compile time constant value. The standard language doesn't allow you to use non-constant value for n in such a case (it is allowed in C99).

If I understand your questions correctly, then I can answer both.
int array[10] is allocated on the stack, whereas int *array = new int[10] is allocated on the heap. Usually, stack arrays only work with a constant number of elements, so int array[n] is not allowed in C90 (as long as n is not constant).
MinGW (which is the version of the GCC compiler that codeblocks uses on windows) has an extension which does allow you to write int array[n] in C90 mode, where n is not constant. Visual C++ does not allow this.

when you write int array[n], that means you are performing a static allocation. i.e. memory will be allocated at the compile time. So using a variable length here will result in a compile time error.

Related

C++, order of computation for the following code

In the following code, im trying to build 2 arrays. The first one is an array given by the user, the second one is an array which has been sorted among other things, although kept short since the actual implementation is not nescessary :
int main()
{
int size = 0;
cout << "Please enter size: ";
cin >> size;
int array[size];
int newArray[size] = doSomething(array,&size);
return 0;
}
int* doSomething(int array[],int *size)
{
*size+=1;
int newArray[size];
//do something with the array and store it in the newArray
return newArray;
}
So my question is this:
My teacher told me that most compilers work differently, and the order of some operations might differ among them.
At the line int newArray[size] = doSomething(array,&size); I am expecting the size variable to be changed inside doSomething before it is used to initialize newArray. Once the doSomething method is finished running, it should return an array (WHICH I ASSUME It IS JUST RETURNING THE ADRESS OF THE FIRST ELEMENT OF THE ARRAY, PLEASE CORRECT ME IF THIS IS WRONG). Once it returns I want to store that address into my newly array, where the variable size is used to initalize the array's size. This variable should be according to my logic, equal to the original size entered by the user +1. So if the user enters a size of 4, the size of newArray should be 5. Is this a good way of going about it, or would it produce unreliable results for different compilers?
For the purpose of this exercise, I can only use built in array and pointers. So I cannot use vectors. Furthermore, in this example, the newArray is one element larger, but the actual code has a size which is dynamic, and therefore might be different each time. I can therefore not hard code the +1 inside the declaration.
If this is wrong, can someone point me in the right direction and help me to find a way where I can pass a built in array (no vectors or array<>), modify the contents and size of it and then return that array and store it in a variable in the caller method?
Thank you very much
First, standard C++ does not allow so-called variable-length arrays (VLAs); the size of the array in the declaration must be a compile-time constant. Standard C does allow them and both gcc and clang implement them as an extension. So technically, your code is ill-formed C++.
Let's accept the extension, for argument's sake. Now we have another problem, which is that arrays cannot be used as initializers for arrays. (An array could be used to initialize a pointer because the array will decay to a pointer in that context, but the pointer doesn't have a size at all. If you did tgat, though, you would introduce a different problem: the returned array has automatic storage duration which means that it is destructed and deallocated immediately. It is, therefore, a "dangling pointer" and using it is undefined behaviour.) You could work around that restriction a bit awkwardly by wrapping the array in a struct.
None of that touches the order of evaluation issue you are curious about. The answer is that the order is unspecified; the compiler might evaluate the function call before or after allocating space for the array. So even if your compiler allows VLAs, the size of this one is unspecified.
You have a problem here:
cin >> size;
int array[size];
Unless you use new you can't do that. The compiler creates the array container before the program runs, so you can't give it a custom size once it is running.
You must allocate your array as a new object on the heap:
cin >> size;
int* array = new int[size];
Maybe this will point you in the right direction, but I have no idea exactly what classes you are trying to call as you haven't included all of your source code.
I edited my previous answer, because I believe you are trying to simply call an array of ints, not a class called "array". If you just want a C-style array of integers, the above example is how you do it properly.
Keep in mind once you are done using the data you should call
delete[] array;

C++ array sizes without constant expressions

I'm reading Stroustrup's A Tour of C++. On page 9, he states:
"The size of an array must be a constant expression."
Yet later, on pg. 16, he uses the following code sample:
void vector vector_init(Vector& v, int s)
{
v.elem = new double[s]; // Allocate an array of s doubles
v.sz = s;
}
Here s is not a constant expression, so how is initializing v.elem to new double[s] legal?
There is a differentiation between allocated arrays (i.e. those created with a new[] expression, like new double[s]), whose lifetimes must be managed by the code (via delete[]) and declared arrays, whose lifetimes are managed by their scope alone:
int* p = new int[s]; // allocated array, p has type int*
int q[10]; // declared array, q has type int[10]
std::vector<int> u; // has member allocated array
std::array<int, 5> v; // has member declared array
The differentiation is not based on stack/heap. A declared array can be heap allocated (e.g. new array<int,5>) or not on the stack (e.g. static double x[100];)
With an allocated array, the size does not have to be a constant expression. The size will simply be encoded into the block of memory yielded by the allocator somehow (for instance the four leading bytes before the actual data starts) so that the corresponding delete[] knows how many elements to delete.
With a declared array (or non-allocated array, no new/malloc/etc.), the size must† be coded into the type, so that the destructor knows what to do. The only allowed, standard array declaration is:
T D[constant-expression_opt];
(where D is a declarator that could be a name or another array declaration, etc.) Declared arrays are not limited to the stack. Note that, for added confusion, the constant-expression is optional.
Arrays offer many sources of confusion in C++. Allocated and declared arrays have different size rules, different management practices, but you can assign a T* to either and they're equivalently indexed. An allocated array is a pointer (that's all you get), but a declared array decays to a pointer (but is an array!).
†Note that there is a concept of a Variable Length Array (VLA). gcc, for instance, supports them as an extension, but they are non-standard C++. It gets periodically proposed though, and you can see this question for more information about them.
When creating an array whose memory is managed by compiler, its size must be (compile time) constant. For ex:
int a[5];
const int sz = 7;
int b[sz] = {0};
(Some languages for ex: C (C99 onwards) support dynamic array size)
If you want a dynamically sized array (Example snippet given by you), you need to allocate memory for it by yourself you'll also need to free it with delete when you're done. Size of such arrays can be non-const also. Moreover you need to manage the memory by yourself, allocation may fail and operators (for example sizeof) would operate on the pointer rather than array.
In modern C++ (C++11 onwards), even stl container std::array must have a constant size.
The quote
The size of an array must be a constant expression.
is talking about an array declaration, such as
double a[EXPR];
where EXPR must indeed be a constant or constexpr (C has variable-length arrays, but they're not part of standard C++).
The expression you mention as a counter-example,
new double[s]
is not an array, despite the []. It is a new-expression, and yields a pointer, not an array. You didn't show the definition of v.elem, but I can tell it's a pointer-to-double.
Note from the linked discussion on new expressions that
If type is an array type, all dimensions other than the first must be specified as positive {something like an integral constant - detail elided}.
So the type referred to above is double[s], which is explicitly allowed.
Admittedly the difference between an array, and the array type passed to a new expression is a little subtle, but you can't conflate them just because of the [], any more than you can claim that
map["key"]
violates something by declaring an array with length "key".

How can I declare an array inside a function according to the size of a parameter?

Here is what I have tried:
int fun1(vector<int> s)
{
const int n = s.size();
int arr[n]; //<----want to declare an array of length s.size()
}
But this tells me that n is not a constant expression, so I cannot use it to declare the array size. But if I try:
int fun1(vector<int> s)
{
const int n = 10;
int arr[n]; //<-----this works
}
then it's fine. Even if I make the vector s of type const, it still won't recognize the size as a constant expression. How do I go about this?
Declaring array by int arr[N]; the size N must be determined in compile-time (except for some compiler extensions which allow you to define them in run-time too). By the way, you can make it:
std::unique_ptr<int[]> arr (new int [n]);
// ... or ...
std::vector<int> arr(n);
When you declare an array like this
int arr[n];
the compiler will allocate memory on the stack for it. In this case the C++ standard requires that n is known at compile time, i.e. it must be const.
The answer to your question is to get the memory from the heap at run time like this:
int* arr = new int[n];
In this case the memory is allocated at run time and so the value of n doesn't need to be known until run time. If you use this approach don't forget to free up the memory when you're done with:
delete [] arr;
However, as the comments suggest, using a std::vector<int> would almost certainly be a better approach. Unless you've got a good reason not to, I'd go with that.
For this, C++ has std::vector<int>(n), which retains most of the semantics of a traditional C array but also adds a lot of benefits (dynamic allocation being one, resizing is another, algorithm support is yet another one). Even when your underlying code requires a C array, you can still use the vector and pass an address of the first element down (they are guaranteed to be contiguous).
Typically, std::vector uses heap for underlying storage, so on one hand you are better protected from stack overflows (pun intended), on the other hand, your code now uses dynamic allocation.

Creating a user-inputted sized Array using new operator

I have a few array-related questions. I've studied that array-size must be constant on declaration/compiler must know its value. But using the GNU GCC compiler (C++11 standard filter) and I am able to perfectly compile and run a program using a variable as array size, when declaring said array dynamically (using new)
int num;
cout << "How big an array? ";
cin >> num;
int *arr = new int [num];
Ques1) Is this considered standard? My profs are contradictory.
Ques2) If it is standard, in that case, is it possible to extend the size of the array (or any array) after creation?
Ques3) Again, if this expression is standard, then is it possible to use it within a function - eg. using a function to create such an array? (if so, how?)
(PS: Hi, I'm new here and also still a novice in C++)
Ques1) Is this considered standard? My profs are contradictory.
Yes, this is completely valid. Note that you need to explicitly delete the memory pointed by arr using operator delete[]. It is much better to use a std::vector<int> which will perform the memory management for you.
You might be mistaken with variable length arrays(VLAs), which are not allowed in C++:
// same num as the one in your example
int arr[num]; // ERROR
This is valid in C but invalid in C++(C++14 will include VLAs, although they will have some differences with C VLAs).
Ques2) If it is standard, in that case, is it possible to extend the
size of the array (or any array) after creation?
No, you can't extend it. You can allocate a bigger array, copy the elements and delete the previous one. Again, this is done automatically if you're using std::vector<int>.
Ques3) Again, if this expression is standard, then is it possible to
use it within a function - eg. using a function to create such an
array? (if so, how?)
Yes, of course:
int *allocate(size_t size) {
return new int[size];
}
But again use std::vector:
int num;
cout << "How big an array? ";
cin >> num;
std::vector<int> arr(num); // num elements, all of them initialized to 0
// insert 42 at the end. reallocations(if any) are done automatically
arr.push_back(42);
I've studied that array-size must be constant on declaration/compiler must know its value.
Well, that's true, but only for static or automatic arrays. You are allocating a dynamic array on the heap, which is different.
Static array
An array declared at global scope must have a constant size.
int arr[5];
Automatic array
An array allocated automatically within a function must have constant size (with exception, see below).
void f() {
int arr[5];
}
Dynamic array
A dynamic array allocated on the heap with new can have any size, constant or variable.
new int[5];
new int[n * 4];
GCC extension
The exception is that GCC allows one to use a variable to declare the size of an automatic array:
void f(int n) {
int arr[n];
}
However, this usage is not standard.
Question 1 - operator 'new' is used to make dynamic allocation, I mean, when you don't know previously what is the size of the array, so, there is no problem, you can do it! I think your profs are confusing with C sintax, where new neither exists and is not allowed to make things like: int p[n]; for instance.
Question 2 - No, it is not possible increase the size of an array created using operator new. You have to alocate another array and copy the data. You can consider use vector in order to do it easily.
Question 3 - I don't see why to do it, but it is possible..
int* createarray(int size)
{
return new int[size];
}
int main()
{
int *p = createarray(10);
}
Q1:Is this considered standard?
Given the definition int n = 42, new float[n][5]
is well-formed (because n is the expression of a
noptr-new-declarator), but new float[5][n] is ill-formed (because n is
not a constant expression).
--5.3.4.6,N3242
If the allocated type is an array type, the allocation function’s
name is operator new[] and the deallocation function’s name is
operator delete[].
--5.3.4.8,N3242
new T[5] results in a call of operator new[](sizeof(T)*5+x)
Here, x and y are non-negative unspecified values representing array allocation overhead;
--5.3.4.12,N3242
Q2:If it is standard, in that case, is it possible to extend the size of the array (or any array) after creation?
Partially no, or not recommended.
when the allocation function returns a value other than null, it must be a pointer to a block of storage
in which space for the object has been reserved. Mostly allocation happened in heap, and there may not have more contiguous memory left which is important for array.
If you have to do this and have a memory poll, use placement new operator you can do this partially, but what you do now is what the designer of allocator do, and have risk ruin the inner memory storage.
Q3: using a function to create such an array? (if so, how?)
Entities created by a new-expression have dynamic storage duration
(3.7.4). [Note: the lifetime of such an entity is not necessarily
restricted to the scope in which it is created. — end note ]
--5.3.4.1,N3242
The rest of things are how to design such function to meet your need, even use template.
1 template<typename T>T* foo(std::size_t size){
2 return new T[size] ;
3 }
As a complement to other answers :
Vectors
(Agreed with vector for dynamic resize) :
std::vector<int> v;
v.push_back(1);
v.push_back(1);
v.resize(v.size()+10, 5); // Greater resized
v.resize(v.size()-1); // Lower resized
If the new size is greater than the old one, additional elements will be initialized to 5 (or 0 in case of int, if the second parameter is not used) and ancient elements remain unchanged.
If the new size is lower than the old one, it is truncated.
Arrays
Side note : (about stack and heap allocation)
The way an array is handled can lead to significantly different results (See this very interesting discussion):
// Create 500 bytes on the heap
char *pBuffer = new char[500]; // or malloc in C
// Create 500 bytes on the stack
char buffer[500];

How are dynamic arrays implemented in C++?

While creating an array, the compiler has to know the size of it? For example, the following code snippet does not compile.
class A
{
int n;
int arr[n];
};
But, the following compiles.
int main()
{
int n;
std::cin >> n;
int arr[n];
}
Why?
Standard C++ does not support variable-length arrays.1
If you want this behaviour, I would suggest using a std::vector rather than a raw C-style array.
1. However, you can find them in C99, or in non-standard language extensions.
(1)
The first thing that happens when you create an instance of A is allocating the memory, at that point the member n does not exist so it is impossible to know how much memory arr needs.
(2) Creates an array on the stack, this only moves the stackpointer a bit.
If you want to create an array of variable size you must do it on the heap using new. The only way that you can use it the way you have would be if you had declared your integer as a constant.
At the moment of compilation the value of variable n is unknown (it's just what've been in memory under the address it was given), so you can't make a variable of unknown size.
and in second case, you know the size, as you've used cin (not sin).