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];
Related
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;
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".
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.
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.
I'm just beginning to get into C++ and I want to pick up some good habits. If I have just allocated an array of type int with the new operator, how can I initialise them all to 0 without looping through them all myself? Should I just use memset? Is there a “C++” way to do it?
It's a surprisingly little-known feature of C++ (as evidenced by the fact that no-one has given this as an answer yet), but it actually has special syntax for value-initializing an array:
new int[10]();
Note that you must use the empty parentheses — you cannot, for example, use (0) or anything else (which is why this is only useful for value initialization).
This is explicitly permitted by ISO C++03 5.3.4[expr.new]/15, which says:
A new-expression that creates an object of type T initializes that object as follows:
...
If the new-initializer is of the form (), the item is value-initialized (8.5);
and does not restrict the types for which this is allowed, whereas the (expression-list) form is explicitly restricted by further rules in the same section such that it does not allow array types.
There is number of methods to allocate an array of intrinsic type and all of these method are correct, though which one to choose, depends...
Manual initialisation of all elements in loop
int* p = new int[10];
for (int i = 0; i < 10; i++)
p[i] = 0;
Using std::memset function from <cstring>
int* p = new int[10];
std::memset(p, 0, sizeof *p * 10);
Using std::fill_n algorithm from <algorithm>
int* p = new int[10];
std::fill_n(p, 10, 0);
Using std::vector container
std::vector<int> v(10); // elements zero'ed
If C++11 is available, using initializer list features
int a[] = { 1, 2, 3 }; // 3-element static size array
vector<int> v = { 1, 2, 3 }; // 3-element array but vector is resizeable in runtime
Assuming that you really do want an array and not a std::vector, the "C++ way" would be this
#include <algorithm>
int* array = new int[n]; // Assuming "n" is a pre-existing variable
std::fill_n(array, n, 0);
But be aware that under the hood this is still actually just a loop that assigns each element to 0 (there's really not another way to do it, barring a special architecture with hardware-level support).
Possible ways of initializing the plain dyanmic array. Choose the one as per your requirement.
int* x = new int[5]; // gv gv gv gv gv (gv - garbage value)
int* x = new int[5](); // 0 0 0 0 0
int* x = new int[5]{}; // 0 0 0 0 0 (Modern C++)
int* x = new int[5]{1,2,3}; // 1 2 3 0 0 (Modern C++)
If the memory you are allocating is a class with a constructor that does something useful, the operator new will call that constructor and leave your object initialized.
But if you're allocating a POD or something that doesn't have a constructor that initializes the object's state, then you cannot allocate memory and initialize that memory with operator new in one operation. However, you have several options:
Use a stack variable instead. You can allocate and default-initialize in one step, like this:
int vals[100] = {0}; // first element is a matter of style
use memset(). Note that if the object you are allocating is not a POD, memsetting it is a bad idea. One specific example is if you memset a class that has virtual functions, you will blow away the vtable and leave your object in an unusable state.
Many operating systems have calls that do what you want - allocate on a heap and initialize the data to something. A Windows example would be VirtualAlloc().
This is usually the best option. Avoid having to manage the memory yourself at all. You can use STL containers to do just about anything you would do with raw memory, including allocating and initializing all in one fell swoop:
std::vector<int> myInts(100, 0); // creates a vector of 100 ints, all set to zero
Yes there is:
std::vector<int> vec(SIZE, 0);
Use a vector instead of a dynamically allocated array. Benefits include not having to bother with explicitely deleting the array (it is deleted when the vector goes out of scope) and also that the memory is automatically deleted even if there is an exception thrown.
Edit: To avoid further drive-by downvotes from people that do not bother to read the comments below, I should make it more clear that this answer does not say that vector is always the right answer. But it sure is a more C++ way than "manually" making sure to delete an array.
Now with C++11, there is also std::array that models a constant size array (vs vector that is able to grow). There is also std::unique_ptr that manages a dynamically allocated array (that can be combined with initialization as answered in other answers to this question). Any of those are a more C++ way than manually handling the pointer to the array, IMHO.
std::fill is one way. Takes two iterators and a value to fill the region with. That, or the for loop, would (I suppose) be the more C++ way.
For setting an array of primitive integer types to 0 specifically, memset is fine, though it may raise eyebrows. Consider also calloc, though it's a bit inconvenient to use from C++ because of the cast.
For my part, I pretty much always use a loop.
(I don't like to second-guess people's intentions, but it is true that std::vector is, all things being equal, preferable to using new[].)
you can always use memset:
int myArray[10];
memset( myArray, 0, 10 * sizeof( int ));
For c++ use std::array<int/*type*/, 10/*size*/> instead of c-style array. This is available with c++11 standard, and which is a good practice. See it here for standard and examples. If you want to stick to old c-style arrays for reasons, there two possible ways:
int *a = new int[5]();
Here leave the parenthesis empty, otherwise it will give compile error. This will initialize all the elements in the allocated array. Here if you don't use the parenthesis, it will still initialize the integer values with zeros because new will call the constructor, which is in this case int().
int *a = new int[5] {0, 0, 0};
This is allowed in c++11 standard. Here you can initialize array elements with any value you want. Here make sure your initializer list(values in {}) size should not be greater than your array size. Initializer list size less than array size is fine. Remaining values in array will be initialized with 0.
Typically for dynamic lists of items, you use a std::vector.
Generally I use memset or a loop for raw memory dynamic allocation, depending on how variable I anticipate that area of code to be in the future.