Creating arrays on the heap and addressing them with pointers - c++

I'm having trouble understanding the following bit of code that I was hoping would create an array on the heap and fill it with the characters 9 down to 0 (I know I could just index the array like a normal stack array with [] notation to do this but I'm doing it this way to try to understand pointers in more depth):
int *ptrHeapArray = new int[10];
for(int f=9; f>=0 ;f--)
{
*ptrHeapArray = f;
ptrHeapArray++;
}
for(int f=0; f<10; f++)
cout << ptrHeapArray[f] << "\n";
It prints out compleletly unexpected values.
As I understand the above, the 'new' command creates an array on the heap and sends me back a pointer to the address where the array is. Since the pointer I assign (ptrHeapArray) is of int size I assumed I could use pointer post incrementing to navigate through the array. However the results indicate that my assumptions are wrong.
This got me to thinking that perhaps the pointer passed back by the 'new' keyword is just a pointer to the whole array and can't be used to step through the array for some reason.
So I tried creating another pointer to the pointer returned by the 'new' keyword and used that to do my array population:
int *ptrHeapArray = new int[10]; //array to hold FRANK data in 32 bit chunks
int *ptrToHeapArrayPointer = ptrHeapArray;
for(int f=9; f>=0 ;f--)
{
*ptrToHeapArrayPointer = f;
ptrToHeapArrayPointer++;
}
for(int f=0; f<10; f++)
cout << ptrHeapArray[f] << "\n";
This worked fine.
Can anyone explain to me why I had to do this and couldn't just have used the pointer passed backed to me by the 'new' keyword?
Thanks

The line
ptrHeapArray++;
in your first for loop increments the pointer, such that it doesn't point to the beginning of the array anymore.
The line
int *ptrHeapArray = new int[10];
allocates the memory for 10 integers and points ptrHeapArray to the beginning of that memory. In your for loop you then move this pointer. When ptrHeapArray points to the third of the integers:
[0] [1] [2] [3] [4]
^ ^ ^
orig. | |
| +-- ptrHeapArray[2]
|
+-- ptrHeapArray now points here
then ptrHeapArray[2] would give you the integer at the position orignally numbered with 4.

You are modifying the pointer in code. After the first loop in the first snippet, the pointer will point to the end of the array rather than the beginning. To make things clearer, this would work too (not suggested but demonstrates the behavior):
int *ptrHeapArray = new int[10];
for(int f=9; f>=0 ;f--)
{
*ptrHeapArray = f;
ptrHeapArray++;
}
ptrHeapArray -= 10; // reset the pointer to its original location
for(int f=0; f<10; f++)
cout << ptrHeapArray[f] << "\n";

Your ptrToHeapArrayPointer is misnamed, it is just a standard int ptr that you've pointed to the same place as ptrHeapArray. If you renamed it to currentPositionPtr your code might make more sense to you.

When you do ptrHeapArray++ it inscrements ptrHeapArray. When you come to print out the data ptrHeapArray no longer points to the start of the array.

The problem is that in your first example ptrHeapArray is initially set to the beginning of the array. As you iterate through your loop you are incrementing the pointer, and by the end of the for loop you are pointing to the last element in the array. When you go through the for loop to display all of your values, you are indexing to values past the end of the array since ptrHeapArray is pointing to the last element in the array you allocated.
It is also important to remember, that you should probably make sure not to loose the original pointer you got back from using the new operator so that you can properly free up the memory that was allocated on the heap.

In the first loop you incremented your pointer ptrHeapArray until the end of array. So after executing the first for loop your pointer is pointing to end of the array and not at the beggining. Hence, when you are trying to print the contents of the array, you are accessing invalid memory allocations and the behavior will be unexpected. In the second case, you are taking a copy of your starting address before assigning values to the array. So when you try to print the contents using the copy, it will be pointing to the beginning of the array.

Related

Unable to understand what is happening in a two-dimensional array pointer

I am a newbie to pointers and am facing some problems while trying to understand them.
Now I looked up this problem over here. I was not 100% satisfied with the solution. So I did some checking on my own to see what happens.
I wanted a pointer to a two-dimensional array so I tried:
int arr[2][3] = {{12,23,4},{323,43,3}};
int (*ptr)[3] = arr; // A pointer to the first element of array.
// The first element of array is an array of three ints.
I ran the following code:
std::cout<<ptr<<std::endl;
std::cout<<*ptr<<std::endl;
Now the results I got were a bit confusing for me:
0x61fdc0
0x61fdc0
Both times the same output is shown. How can the address of the pointer and value after the referencing be the same? Is this behavior similar to double pointers? An explanation like this will be very helpful.
Arrays can decay to pointers. Actually you used that fact when you wrote:
int (*ptr)[3] = arr;
ptr is "a pointer to the first element of array". The 2D array arr did decay to a pointer to its first element when you used it to initialize ptr.
When you dereference ptr you get the first element (of arr), a one-dimensional array, and when you print it via
std::cout << *ptr << std::endl;
you get its address printed, because the array decays to a pointer to its first element.
As the answer you link explains, the address of an array and the address of its first element are identical:
The following are equivalent ways to point to the first of the two
items.
int (*p)[3] = a; // as before
int (*p)[3] = &(a[0]);

C++ Dereferencing Null ptr error?

I looked before posting, but pardon me if my answer is elsewhere. As part of my homework, I need to create an array of pointers to objects (of different types, but they share a base class). Once the pointers are in the array I need to be able to call member functions on the objects to which they point. I'm able to do this for the first object, but after my program goes through the loop once, I get the following exception: "0xC0000005: Access violation executing location 0x00000000"
Below is my code. Thanks
int main()
{
Sales * publications[5]; //declare an array of pointers
for (int i = 0; i < 5; i++) {
if (i < 3)
publications[i] = new Book();
else
publications[i] = new Tape();
std::cout << std::endl << publications[i] << std::endl;
(*publications)[i].readData();
(*publications)[i].displayData();
}
for (int i = 0; i < 5; i++) { //delete the array to avoid memory leak
delete publications[i];
}
std::cout << std::endl;
system("pause");
return 0;
}
I have already tested the readData and displayData functions and they work just fine.
This:
(*publications)[i].readData();
Should be:
publications[i]->readData();
publications is an array of pointers.
(*publications)[i].readData();
In this code snippet, the order of operations is out of order. The * dereference operator is going to take precedence over the [] array syntax operator due to the parenthesis.
The first thing that is going to happen is publications (the array) is going to be dereferenced - not the element located at index i. This will always give you the first element in the array, as an array variable is just the address of the first element.
The second operation that takes place is that a byte offset (sizeof(Sales) * i)) is added to the memory address returned by the dereference. When the index i is 0, this is not a problem since there is no offset to add and an object exists at the calculated memory location. However, once you have an index not equal to 0, the calculated memory address does not point at a valid Sales object, so you may or may not crash, depending on what actually lies at the memory location.
The correct order of operations using the given operators is this:
(*(publications[i])).readData();
Using the -> operator is preferred instead:
publications[i]->readData();
Now, the [] array-syntax operator takes precedence, offsetting the address of the array to an element within the array, and then either *. or -> is used to dereference that element's pointer to reach the object, as expected.

Initializing a multidimensional array

I am trying to initialize a multidimensional array in batches and can't seem to make it work or find an example!
The dimensions I am working with are big enough that I don't want to specify them by hand!
More precisely :
int test[5][192];
for(int i = 0; i < 5; i++){
int temp[192] = {...};
test[i] = temp;
}
// use variable test here..
I want to use this method because the temp array is dynamicaly defined depending on variable i.
Is this type of initialization possible?
Should the temp array be in dynamic memory?
Since after the initialization I pass a reference to the first element of test to another function and I am not in control of how the other function passes over the elements I need to keep the data type of an array!
If you want to copy the values of temp array , instead of "=", you should use memory copy
memcpy( test[i], temp, sizeof(temp[192]));
Arrays do not have the copy assignment operator. So this is impossible with arrays.
If you will dynamically allocate each row then in any case you have to store somewhere the number of their elements. So even dynamically allocated arrays are not suitable in this case when the numbers of elements in each row can differ.
You should use standard container std::vector<std::vector<int>> instead.
You dont use the second dimension in the array for the test array. you just write test[], but you must write test[][].
I thing you don't must use the temp array. You can initialize you array direct, without using a temp array.
I'm not absolutly sure, but memcpy are just using for one diemnsionalarrays ant not for multidimensional arrays
if you know, Temp and test[i] are two pointer which point to memory
so if you print temp or test[i] you will see the address of where they start on memory.
in your code you lose the address of test[i] because you changed pointer test[i] to temp
and now both of them are pointing to the same place where temp begin on there!

How to access the array from the pointer?

I am trying to understand how pointers work but I do not know how a pointer to only the first element can be used to access all the array
int myArray[10];
for(int i=0; i<10; i++)
{
myArray[i] = 11*i;
}
int *p;
p = myArray;
//Now how do I access the complete array using the variable p
cout<<*p; //This only prints the first value, how to print all the values
You have to use while or for.
int i = 0;
while (i < 10)
{
cout << p[i];
i += 1;
}
Pointers and arrays are working in the same way. An array is nothing else than a pointer to the first element you allocated.
If you for example want to access pos 5, you can just write:
...
int *p;
p = myArray;
cout << p[5];
Since the compiler know that p is a pointer to an int, it will add the size of an int for each step (4 bytes in this case).
As long as you don't use pointers to void, the compiler does this for you.
You still have to keep track of the length of the array so you do not exceeds it since a pointer don't do that.
except for thr declaration, arrays and pointers con be used using the same syntax
(They are different in memory, meaning they still need to be treated differently)
Use like this,
int *p;
p = myArray;
for(int i=0;i<10;i++)
{
cout<<*(p+i);
}
The first element points to the first memory location of the elements in the array. So this:
myArray[0];
and
myArray;
point to the same location. You can use indexes on the pointer, just like you did to fill the array. So this:
int *p = myArray;
cout << p[0];
cout << p[1];
would access your other elements. You can use a for loop to access all the elements in the array, just like you did to populate it in the first place.
You can think of the name of an array as a pointer to its first element.
So, the line p = myArray; is simply copying the address of the first element of the array myArray into p.
Now the line cout<<*p; is obviously displaying the value of what's pointed by p, which is the first element of your array.
To display all the elements, you can simply use a for loop like you did before.

Is it necessary to delete elements as an array shrinks?

I'm a student writing a method that removes zeros from the end of an array of ints, in C++. The array is in a struct, and the struct also has an int that keeps track of the length of the array.
The method examines each element starting from the last, until it encounters the first non-zero element, and marks that one as the "last element" by changing the value of length. Then the method walks back up to the original "last element", deleting those elements that are not out of bounds (the zeros).
The part that deletes the ith element in the array if i is greater than the updated length of the array, looks like this:
if (i > p->length - 1) {
delete (p->elems + i); // free ith elem
That line is wrong, though. Delete takes a pointer, yes? So my feeling is that I need to recover the pointer to the array, and then add i to it so that I will have the memory location of the integer I want to delete.
Is my intuition wrong? Is the error subtle? Or, have I got the entirely wrong idea? I've begun to wonder: do I really need to free these primitives? If they were not primitives I would need to, and in that case, how would I?
have I got the entirely wrong idea?
I'm afraid so.
If you make one new[] call to allocate an array, then you must make one delete[] call to free it:
int *p = new int[10];
...
delete[] p;
If your array is in a struct, and you make one call to allocate the struct, then you must make one call to free it:
struct Foo {
int data[10];
};
Foo *foo = new Foo;
...
delete foo;
There is no way to free part of an array.
An int[10] array actually is 10 integers, in a row (that is, 40 bytes of memory on a 32 bit system, perhaps plus overhead). The integer values which are stored in the array occupy that memory - they are not themselves memory allocations, and they do not need to be freed.
All that said, if you want a variable length array:
that's what std::vector is for
#include <vector>
#include <iostream>
struct Foo {
std::vector<int> vec;
};
int main() {
Foo foo;
// no need for a separate length: the current length of the vector is
std::cout << foo.vec.size() << "\n";
// change the size of the vector to 10 (fills with 0)
foo.vec.resize(10);
// change the size of the vector to 7, discarding the last 3 elements
foo.vec.resize(7);
}
If p->elems is a pointer, then so is p->elems + i (assuming the operation is defined, i.e. i is of integral type) - and p->elems + i == &p->elems[i]
Anyhow, you most likely don't want to (and cannot) delete ints from an array of int (be it dynamically or automatically allocated). That is
int* ptr = new int[10];
delete &ptr[5]; // WRONG!
That is simply something you cannot do. However, if the struct contains the length of the array, you could consider the array "resized" after you change the length information contained by the struct - after all, there is no way to tell the size of the array a pointer points to.
If, however your array is an array of pointers to integers (int*[]) and these pointers point to dynamically allocated memory, then yes, you could delete single items and you'd do it along the lines of your code (you are showing so little code it's difficult to be exact).