I'm familiar with Java and trying to teach myself C/C++. I'm stealing some curriculum from a class that is hosting their materials here. I unfortunately can't ask the teacher since I'm not in the class. My concern is with the section under "dynamically declared arrays":
If you
want to be able to alter the size of
your array at run time, then declare
dynamic arrays. These are done with
pointers and the new operator. For the
basics on pointers, read the pointers
section.
Allocate memory using new, and then
you access the array in the same way
you would a static array. For example,
int* arrayPtr = new int[10]; for
(int i = 0; i < 10; i++) {
arrayPtr[i] = i; }
The memory picture is identical to the
static array, but you can change the
size if you need to. Don't forget you
must deallocate the memory before
allocating new memory (or you will
have a memory leak).
delete [] arrayPtr; // the []
is needed when deleting array pointers
arrayPtr = new int[50]; . . .
When you're completely done with the
array, you must delete its memory:
delete [] arrayPtr;
Dynamic multi-dimensional arrays are
done in a similar manner to Java. You
will have pointers to pointers. For an
example, see a
My understanding is that an array in C is simply a reference to the memory address of the first element in the array.
So, what is the difference between int *pointerArray = new int[10]; and int array[10]; if any?
I've done some tests that seem to indicate that they do the exact same thing. Is the website wrong or did I read that wrong?
#include <cstdlib>
#include <iostream>
using namespace std;
int main(int argc, char** argv) {
// Initialize the pointer array
int *pointerArray = new int[10];
for (int i = 0; i < 10; i++){
pointerArray[i] = i;
}
// Initialize the regular array
int array[10];
for (int i = 0; i < 10; i++){
array[i]= i;
}
cout << *(pointerArray + 5) << endl;
cout << *(array + 5) << endl;
cout << pointerArray[5] << endl;
cout << array[5] << endl;
cout << pointerArray << endl;
cout << array << endl;
return 0;
}
Output:
5
5
5
5
0x8f94030
0xbfa6a37c
I've tried to "dynamically re-size" my pointer array as described on the site, but my new (bigger) pointer array ends up filled with 0's which is not very useful.
int array[10]; declares the array size statically, that means it is fixed - which is the only major difference. It also might be allocated to be inside the function's stack frame, i.e. on the program's stack. You do not need to worry about using delete [] on that kind of array, in fact, you might crash the program if you delete it.
When you use operator new, you allocate memory dynamically which could be slower and the memory usually comes from the heap rather than the program's stack (though not always). This is better in most cases, as you are more limited in the stack space than the heap space. However, you must watch out for memory leaks and delete[] your stuff when you don't need it anymore.
As to your array being filled with zeros, what your class material does not say is that you have to do this:
int *arr = new int[20]; // old array
//do magic here and decide that we need a bigger array
int *bigger = new int[50]; // allocate a bigger array
for (int i = 0; i < 20; i++) bigger[i] = arr[i]; // copy the elements from the old array into the new array
delete[] arr;
arr = bigger;
That code extends the array arr by 30 more elements. Note that you must copy the old data into the new array, or else it will not be there (in your case, everything becomes 0).
My understanding is that an array in C is simply a reference to the memory address of the first element in the array.
So, what is the difference between int *pointerArray = new int[10]; and int array[10]; if any?
What you mention is the reason for much confusion in any C/C++ beginner.
In C/C++, an array corresponds to a block of memory sufficiently large to hold all of its elements. This is associated to the [] syntax, like in your example:
int array[10];
One feature of C/C++ is that you can refer to an array by using a pointer to its type. For this reason, you are allowed to write:
int* array_pointer = array;
which is the same as:
int* array_pointer = &array[0];
and this allows to access array elements in the usual way: array_pointer[3],
but you cannot treat array as a pointer, like doing pointer arithmetics on it (i.e., array++ miserably fails).
That said, it is also true that you can manage arrays without using the [] syntax at all and just allocate arrays by using malloc and then using them with raw pointers. This makes the "beauty" of C/C++.
Resuming: a distinction must be made between the pointer and the memory that it points to (the actual array):
the [] syntax in declarations (i.e., int array[10];) refers to both aspects at once (it gives you, as to say, a pointer and an array);
when declaring a pointer variable (i.e., int* p;), you just get the pointer;
when evaluating an expression (i.e., int i = p[4];, or array[4];), the [] just means dereferencing a pointer.
Apart from this, the only difference between int *pointerArray = new int[10]; and int array[10]; is that former is allocated dynamically, the latter on the stack.
Dynamically allocated:
int * pointerArray = new int[10];
[BTW, this is a pointer to an array of 10 ints, NOT a pointer array]
Statically allocated (possibly on the stack):
int array[10];
Otherwise they are the same.
The problem with understanding C/C++ arrays when coming from Java is that C/C++ distinguishes between the array variable and the memory used to store the array contents. Both concepts are important and distinct. In Java, you really just have a reference to an object that is an array.
You also need to understand that C/C++ has two ways of allocating memory. Memory can be allocated on the help or the stack. Java doesn't have this distinction.
In C and C++, an array variable is a pointer to the first element of the array. An array variable can exist on the heap or the stack, and so can the memory that contains its contents. And they can be difference. Your examples are int arrays, so you can consider the array variable to be an int*.
There are two differences between int *pointerArray = new int[10]; and int array[10];:
The first difference is that the memory that contains the contents of the first array is allocated on the heap. The second array is more tricky. If array is a local variable in a function then its contents are allocated on the stack, but if it is a member variable of a class then its contents are allocated wherever the containing object is allocated (heap or stack).
The second difference is that, as you've realised, the first array is dynamic: its size can be determined at run-time. The second array is fixed: the compiler must be able to determine its size at compile time.
First, I'd look for some other place to learn C++. The page you cite is
very confusing, and has little to do with the way one actually programs
in C++. In C++, most of the time, you'd use std::vector for an array,
not the complex solutions proposed on the page you cite. In practice,
you never use operator new[] (an array new).
In fact, std::vector is in some ways more like ArrayList than simple
arrays in Java; unlike an array in Java, you can simply grow the vector
by inserting elements into it, preferrably at the end. And it supports
iterators, although C++ iterators are considerably different than Java
iterators. On the other hand, you can access it using the []
operator, like a normal array.
The arrays described on the page you cite are usually called C style
arrays. In C++, their use is mostly limited to objects with static
lifetime, although they do occasionally appear in classes. In any case, they are never allocated dynamically.
The main difference is that some operations that are allowed on pointers are not allowed on arrays.
On the one hand:
int ar[10];
is using memory allocated on the stack. You can think of it also locally available and while it is possible to pass a pointer / reference to otehr functions, the memory will be freed as soon as it goes out of scope (in your example at the end of the main method but that's usually not the case).
On the other hand:
int ar* = new int[10];
allocates the memory for the array on the heap. It is available until your whole program exits or it is deleted using
delete[] ar;
note, that for delete you need the "[]" if and only if the corresponding new has had them, too.
There is a difference but not in the area that you point to. *pointerArray will point to the beginning of a block of memory of size 10 bytes. So will array. The only difference will be where it is stored in memory. pointerArray is dynamically assigned memory (at run-time) and hence will go on the heap, while array[10] will be allocated at compile-time and will go to the stack.
It is true that you can get most of array functionality by using a pointer to its first element. But compiler knows that a static array is composed of several elements and the most notable difference is the result of the sizeof operator.
sizeof(pointerArray) = sizeof int*
sizeof(array) = 10 * sizeof int
Related
This question is similar to Problem with delete[], how to partially delete the memory?
I understand that deleting an array after incrementing its pointer is not possible as it loses the track of how many bytes to clean. But, I am not able to understand why one-by-one delete/deallocation of a dynamic array doesn't work either.
int main()
{
int n = 5;
int *p = new int[n];
for(int i=0;i<n;++i){
delete &p[i];
}
}
I believe this should work, but in clang 12.0 it fails with the invalid pointer error. Can anyone explain why?
An array is a contiguous object in memory of a specific size. It is one object where you can place your data in and therefore you can only free/delete it as one object.
You are thinking that an array is a list of multiple objects, but that's not true. That would be true for something like a linked list, where you allocate individual objects and link them together.
You allocated one object of the type int[n] (one extent of memory for an array) using the operator new
int *p = new int[n];
Elements of the array were not allocated dynamically separately.
So to delete it you just need to write
delete []p;
If for example you allocated an array of pointers like
int **p = new int *[n];
and then for each pointer of the array you allocated an object of the type int like
for ( int i = 0;i < n;++i )
{
p[i] = new int( i );
}
then to delete all the allocated objects you need to write
for ( int i = 0; i < n; ++i )
{
delete p[i];
}
delete []p;
That is the number of calling of the operator delete or delete [] one to one corresponds to the number of calling operator new or new [].
One new always goes with one delete. Just as that.
In detail, when we request an array using new, what we actually do is to get a pointer that controls a contiguous & fixed block on the memory. Whatever we do with that array, we do it through that pointer and this pointer associates strictly with the array itself.
Furthermore, let's assume that you were able to delete an elemnent in the middle of that array. After the deletion, that array would fall apart and they are not contiguous anymore! By then, an array would not really be an array!
Because of that, we can not 'chop off' an array into separate pieces. We must always treat an array as one thing, not distinctive elements scattered around the memory.
Greatly simplyfyinh: in most systems memory is allocated in logical blocks which are described by the starting pointer of the allocated block.
So if you allocate an array:
int* array = new int[100];
OS stores the information of that allocation as a pair (simplifying) (block_begin, size) -> (value of array ptr, 100)
Thus when you deallocate the memory you don't need to specify how much memory you allocated i.e:
// you use
delete[] array; // won't go into detail why you do delete[] instead of delete - mostly it is due to C++ way of handling destruction of objects
// instead of
delete[100] array;
In fact in bare C you would do this with:
int* array = malloc(100 * sizeof(int))
[...]
free(array)
So in most OS'es it is not possible due to the way they are implemented.
However theoretically allocating large chunk of memory in fact allocate many smaller blocks which could be deallocated this way, but still it would deallocate smaller blocks at a time not one-by-one.
All of new or new[] and even C's malloc do exactly the same in respect to memory: requesting a fix block of memory from the operating system.
You cannot split up this block of memory and return it partially to the operating system, that's simply not supported, thus you cannot delete a single element from the array either. Only all or none…
If you need to remove an element from an array all you can do is copy the subsequent elements one position towards front, overwriting the element to delete and additionally remember how many elements actually are valid – the elements at the end of the array stay alive!
If these need to be destructed immediately you might call the destructor explicitly – and then assure that it isn't called again on an already destructed element when delete[]ing the array (otherwise undefined behaviour!) – ending in not calling new[] and delete[] at all but instead malloc, placement new for each element, std::launder any pointer to any element created that way and finally explicitly calling the constructor when needed.
Sounds like much of a hassle, doesn't it? Well, there's std::vector doing all this stuff for you! You should this one it instead…
Side note: You could get similar behaviour if you use an array of pointers; you then can – and need to – maintain (i.e. control its lifetime) each object individually. Further disadvantages are an additional level of pointer indirection whenever you access the array members and the array members indeed being scattered around the memory (though this can turn into an advantage if you need to move objects around your array and copying/moving objects is expensive – still you would to prefer a std::vector, of pointers this time, though; insertions, deletions and managing the pointer array itself, among others, get much safer and much less complicated).
I know that arrays can be created on the stack with syntax such as int array[5]; where the size must be known at compile time and array is a non modifiable l-value.
You can also create an array dynamically on the heap with new such as int* array = new int[5]; where it becomes possible to have a size of variable length and resize the array.
But what about something like:
int* array;
array[2] = 3;
cout << array[2] << endl;
Which creates an array on the stack that appears to be resizable because I can continue adding elements. The only other thing that should be kept track of is the size.
I wrote the above code accidentally in a project and I haven't seen it used ever. I not sure if it should be used at all, but I'm also not sure what's incorrect about it.
But what about something like:
int* array;
array[2] = 3;
cout << array[2] << endl;
Which creates an array on the stack that appears to be resizable because I can continue adding elements. The only other thing that should be kept track of is the size.
Nope. Unfortunately, C++ doesn't work like that. You need to allocate the array with new if you want to create a dynamic array with raw pointers.
This is because pointers only hold addresses. They don't actually guarantee that there is memory allocated at that address. Thus, you will need to allocate memory at an address if you want to use it.
If you want a dynamically allocated memory, you have other options including using std::vector, or std::unique_ptr, or std::shared_ptr. You can find more information on this and some examples at this question.
Writing int *array; does not create an array, it declares a pointer to some random memory page, and if you try to dereference this pointer, your program will receive “Segmentation fault” signal and will be shut down. Never use pointers without their proper initialization using addresses of existing objects, or allocated objects (using new), or functions/methods which return valid address.
I am confused about how to create a dynamic defined array:
int *array = new int[n];
I have no idea what this is doing. I can tell it's creating a pointer named array that's pointing to a new object/array int? Would someone care to explain?
new allocates an amount of memory needed to store the object/array that you request. In this case n numbers of int.
The pointer will then store the address to this block of memory.
But be careful, this allocated block of memory will not be freed until you tell it so by writing
delete [] array;
int *array = new int[n];
It declares a pointer to a dynamic array of type int and size n.
A little more detailed answer: new allocates memory of size equal to sizeof(int) * n bytes and return the memory which is stored by the variable array. Also, since the memory is dynamically allocated using new, you should deallocate it manually by writing (when you don't need anymore, of course):
delete []array;
Otherwise, your program will leak memory of at least sizeof(int) * n bytes (possibly more, depending on the allocation strategy used by the implementation).
The statement basically does the following:
Creates a integer array of 'n' elements
Allocates the memory in HEAP memory of the process as you are using new operator to create the pointer
Returns a valid address (if the memory allocation for the required size if available at the point of execution of this statement)
It allocates space on the heap equal to an integer array of size N,
and returns a pointer to it, which is assigned to int* type pointer called "array"
It allocates that much space according to the value of n and pointer will point to the array i.e the 1st element of array
int *array = new int[n];
The new operator is allocating space for a block of n integers and assigning the memory address of that block to the int* variable array.
The general form of new as it applies to one-dimensional arrays appears as follows:
array_var = new Type[desired_size];
In C/C++, pointers and arrays are (almost) equivalent.
int *a; a[0]; will return *a, and a[1]; will return *(a + 1)
But array can't change the pointer it points to while pointer can.
new int[n] will allocate some spaces for the "array"
As of C++11, the memory-safe way to do this (still using a similar construction) is with std::unique_ptr:
std::unique_ptr<int[]> array(new int[n]);
This creates a smart pointer to a memory block large enough for n integers that automatically deletes itself when it goes out of scope. This automatic clean-up is important because it avoids the scenario where your code quits early and never reaches your delete [] array; statement.
Another (probably preferred) option would be to use std::vector if you need an array capable of dynamic resizing. This is good when you need an unknown amount of space, but it has some disadvantages (non-constant time to add/delete an element). You could create an array and add elements to it with something like:
std::vector<int> array;
array.push_back(1); // adds 1 to end of array
array.push_back(2); // adds 2 to end of array
// array now contains elements [1, 2]
I understand that we use this when we need to give a pointer to an array of pointers in the dynamic memory but what I don't understand is that how this works in the stack.
Does this make an array of pointers in the stack too that is pointing to the array of pointers in the heap or does it make a single pointer in the stack that is pointing to the array of pointers in the heap? if yes, then what is the difference between
int **p = new int*[100]
and
int *p = new int[100]
Thanks in advance. I have been trying to understand this for a long time now and have read a lot of documentation online but I still don't understand this.
int **p declares a pointer on the stack which points to pointer(s) on the heap. Each of that pointer(s) point to an integer or array of integers on the heap.
This:
int **p = new int*[100];
means that you declared a pointer on the stack and initialized it so that it points to an array of 100 pointers on heap. For now each of that 100 pointers point nowhere. By "nowhere" I mean that they point neither to a valid chunk of memory, nor they are nullptrs. They are not initialized, thus they contain some garbage value which was in the memory before the pointers were allocated. You should assign something sensible to them in a loop before usage. Note that p[0] - p[99] pointers are not guaranteed to point to adjacent regions of memory if you assign return values of new to them. For example, if you allocate memory for each of them as p[i] = new int[200];, p[0][201] will not reference p[1][2], but will lead to an undefined behavior.
And this:
int *p = new int[100];
is a pointer on the stack which points to an array of 100 integers on the heap.
Don't worry, pointers and arrays in C are always a source of confusion. In general, when you declare an array of, say type int, you create a pointer of type int that points to the first element in a contiguous block of memory that will store ints. For example, if I have a simple array of ints using int *p_to_intarr = new int[3], I get this:
+++++++ <--------- p_to_intarr
| int |
+++++++
| int |
+++++++
| int |
+++++++
In general, if I want an array of type T, I create a pointer to type T like T *ptr_to_Tarr = new T[3].
So what if I want an array of array of ints? Lets just replace the T in with the type of an "array of ints" and this will give us an array of "array of ints". Well we just say in our first example that the type of an array of ints in int *, and so an array of array of ints would be: int* *ptr_to_arrayofintarr = new int*[3]. Note we just replaced the T with int star. This is often written more neatly as int **ptr_to_arrayofintarr = new int*[3].
So int **p could be a pointer to a 2d array. It could also be a reference to a 1d array; depends on the specific case :)
The new expression evaluates to a pointer of some type, pointing to memory that has been allocated in the free store (essentially the heap) but not necessarily in the free store. (It can still be in the free store depending on the context; for instance, consider an initialization-list in a constructor for an object being allocated in the free store.)
The object(s) initialized by new is/are of course in the free store.
In the assignment statements you've shown, you can see the type of the pointer returned by new on the left side of the equals sign, and the type of the free store object(s) to the right of the new. Thus the only object that is locally evaluated (i.e. might be on the stack) is, in the first case, a pointer-to-pointer-to-int, and in the second case, a pointer-to-int. The objects in free space are an array of pointers-to-ints in the first case and a simple array of ints in the second.
Note that just because the array in the first assignment consists of pointers doesn't mean that the pointers themselves actually point to anything yet; new does not magically recursively allocate free space for objects to be targeted by any pointers in an array it creates. (This wouldn't make much sense anyway.)
The ** means that you have a pointer to pointers. In more practical terms, it means you have a two-dimensional array.
Since each element of the array is also a pointer, you need to initialize those pointers as well:
for (int i = 0; i < 100; ++i)
p[i] = new int[200];
This initializes a 100x200 array. You can access the bottom-right corner with p[99][199].
When it's time to delete the pointer you have to reverse the process:
for (int i = 0; i < 100; ++i)
delete [] p[i];
delete [] p;
Say I have an array declared as:
int* array;
and I fill the array with however many integers.
If I later say
array = NULL;
does this free the memory that the numbers in array occupied, or does it just make the array unusable while the memory still lingers?
int* array; is not an array, it's a pointer. You have no array at this point. You can't start doing array[0] = 5; or anything because it doesn't even point at a valid int object, let alone an array of ints.
An array is declared by doing:
int array[5];
This array does have 5 objects ready for you to start assigning to. However, this array must not be deleted. The array was not dynamically allocated.
However, if you were to have done int* array = new int[5];, you would by dynamically allocating an array of 5 ints and getting a pointer to the first element in that array. In this case, you must delete[] array;. If you don't and only set the pointer to NULL or nullptr, you will only leak memory.
If you allocated the memory using new [] (more likely, since the name of the variable is array) or new, this will result in a memory leak.
Setting the pointer to NULL will not release the memory, only reassign the pointer. In other words, you will lose any chance to refer to the previously allocated memory.
Use delete[] to release memory allocated with new[], and delete to release memory allocated with new.
However, consider not using raw pointers and manual memory management at all, they are most often not needed and error-prone. The C++ Standard Library comes with collections and smart pointers that perform memory management under the hood and keep you safe from this kind of mistakes.
When you use the code
int *array;
array = NULL;
you have initialized the pointer. When you assign data to *array
int *array;
array[1] = 3;
you get an undefined behavior, but in most cases an access violation. When you allocate memory before writing and assign NULL to the pointer
int *array;
array = new int[3];
array[0] = 2;
array[2] = 4;
array = NULL;
you get a memory leak. Everything should be fine, when you delete the data:
int *array;
array = new int[3];
array[0] = 2;
array[2] = 4;
delete[] array;
array = NULL;
Setting the array to NULL does not free the memory.
Weather it is usable will depend on the surrounding code and how array is initialized. But you have not provided that information so anything else would be speculation.
Note it is unusual to use pointers in modern C++ code.
You should be looking to use a more appropriate structure. What that is will depend on what your usage us. Based on the name alone array. You should probably be using std::vector<int> (or std::array<int> C++11) or even a plain old C array int array[5].
it will leak the memory and it will only be freed when the process exits.
There is every chance that a segmenation fault may occur.
If you have:
int *array = new int[10];
you need to use
delete [] array;
to free the memory.
Basically follow the rule: Whenever allocating with new XXX deallocate with delete XXXor for array allocation delete [] XXX.
If you just use array = NULL, you only set the pointer to NULL and you will have a memory leak.