Pointer arrays on heap


Thanks for everyone's help in the past and an advanced thanks.
I just have one QUESTION and some ANALYSIS to make sure I understand this entirely.

1) ANALYSIS:
It just dawned on me that every time I saw something created on the heap, which I believe was always created with a pointer. This is probably because "new" always returns a pointer to the address that was created. So, it is fair to say that anytime you want to create something on the heap (using new/delete), a pointer is REQUIRED, and you cannot create on the heap without a pointer. Which I believe to be correct.

2) ANALYSIS:
Here the "new" creates memory on the heap. The array is a pointer to a pointer of objects, and the array creates copies of the pointer address to the object. Which I believe is correct.


1
2
3
4
5
6
	//______________________________________________
	//2) Car array on heap, method 1
	Car* myCar1 = new Car();
	Car* myCar2 = new Car();

	Car* myCarColl1[ARRAY_SIZE] = {myCar1, myCar2 };


Below also creates a pointer to an array, of pointers to objects.

1
2
3
4
5
	//______________________________________________
	//3) Car array on heap, method 2
	Car* myCarColl2[ARRAY_SIZE] = { NULL };
	myCarColl2[0] = new Car();
	myCarColl2[1] = new Car();


3) QUESTION:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
	//2) Car array on heap, method 1
	Car* myCar1 = new Car();
	Car* myCar2 = new Car();

	Car* myCarColl1[ARRAY_SIZE] = {myCar1, myCar2 };

	
	(*myCarColl1)[0].GetCarID();	//WORKS
	myCarColl1[0]->GetCarID();		//WORKS	
	myCarColl1[1]->GetCarID();		//WORKS
	cout << ">>>>>";
	(*(myCarColl1 + 1))[0].GetCarID();
	//(*myCarColl1)[1].GetCarID();		//DOES NOT WORK
	//(*(myCarColl1 + 1))[1].GetCarID();	//DOES NOT WORK
	//(*myCarColl1 + 1)[1].GetCarID();		//DOES NOT WORK
	//(*(myCarColl1 + 1)).GetCarID();		//DOES NOT WORK 


Now I am kicking myself on this one.

The, above 3 "//WORKS" as I expected them to and let me just analyze them to make sure I understand why they are working.

(*myCarColl1)[0].GetCarID();

(*myCarColl1) <----That part says the thing that I am pointing to, which is the whole array, and more specifically the address of index [0], which holds the pointer to the address of the object.

[0].GetCarID(); <----This part resolves the index that has a pointer to the object, which is the object itself & then runs the function.

So, why would the below not work?

 
//(*myCarColl1)[1].GetCarID();		//DOES NOT WORK 

(*myCarColl1) <----The thing that I am pointing to, which is the array at index[0]

[1].GetCarID(); <----Does not resolve the next address value of (object itself).

Not even below works.
 
//(*(myCarColl1 + 1))[1].GetCarID();	//DOES NOT WORK 


But below works with an index of [0]....what???? Now I am totally mystified???
Is there any other way to write/resolve an array index of pointer to a pointer?

 
(*(myCarColl1 + 1))[0].GetCarID();





1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
#include <iostream>

using namespace std;

class Car
{
public:
	static int CarID;
	int myCarID = 0;

	Car()
	{
		cout << "Honk, honk!!!\n";
		++CarID;
		myCarID = CarID;
	}

	~Car(){}

	void GetCarID() const
	{
		cout << myCarID << endl;
	}
};

int Car::CarID = 0;

int main()
{
	const int ARRAY_SIZE = 2;

	//1) Car array on stack
	Car myCar[ARRAY_SIZE] = { Car(), Car() };
	myCar[0].GetCarID();
	myCar[1].GetCarID();
	cout << "\n\n";

	//______________________________________________
	//2) Car array on heap, method 1
	Car* myCar1 = new Car();
	Car* myCar2 = new Car();

	Car* myCarColl1[ARRAY_SIZE] = {myCar1, myCar2 };

	(*myCarColl1)[0].GetCarID();
	myCarColl1[0]->GetCarID();
	myCarColl1[1]->GetCarID();
	cout << ">>>>>";
	(*(myCarColl1 + 1))[0].GetCarID();
	//(*myCarColl1)[1].GetCarID();			//DOES NOT WORK
	//(*(myCarColl1 + 1))[1].GetCarID();		//DOES NOT WORK
	//(*myCarColl1 + 1)[1].GetCarID();		//DOES NOT WORK
	//(*(myCarColl1 + 1)).GetCarID();		//DOES NOT WORK

	delete myCar1;
	delete myCar2;
	myCar1 = NULL;
	myCar2 = NULL;
	
	cout << "\n\n";

	//______________________________________________
	//3) Car array on heap, method 2
	Car* myCarColl2[ARRAY_SIZE] = { NULL };
	myCarColl2[0] = new Car();
	myCarColl2[1] = new Car();

	(*myCarColl2)[0].GetCarID();
	myCarColl2[0]->GetCarID();
	myCarColl2[1]->GetCarID();
	(*(myCarColl2 + 1))[0].GetCarID();
	//(*myCarColl2)[1].GetCarID();			//DOES NOT WORK

	delete myCarColl2[0];
	delete myCarColl2[1];
	myCarColl2[0] = NULL;
	myCarColl2[1] = NULL;

	//delete[] myCar;

	cout << "\n\n";

	return 0;
}
(*myCarColl1)[1].GetCarID();

you have confused yourself about what is what.
(*myCarColl1)
what is that? myCarColl1 is an array of pointers.
a pointer isnt special in general. A pointer has special syntax and methods associated with it, but it isnt special.
if you had this:
int x[1000];
do you think
(*x)[1] = 42; //is this correct?!
no, not really.
the compile can convert x into a pointer (array names can be collapsed into a pointer), but *x is the first location when you do that. treating x as a pointer, *x is the same as x[0]. but you asked for x[0][1] ... that is nonsense.
the same is true for yours, it just happens to have type pointer instead of type int.

(*myCarColl1)[1].GetCarID();
you probably want
(*myCarColl1[1]).GetCarID(); //go into the array, get a pointer out, dereference it, and tap its method. it may need an extra (): (*(myC..)). ... I don't use * syntax a lot anymore.
or a little more friendly, but same thing:
myCarColl1[1]->GetCarID(); //lose the * notation. it is almost always uglier when dealing with more than one item (when the pointer is an array/block of items).

I think your understanding of the concepts is FINE. You just tripped over syntax there.
Last edited on
1) ANALYSIS:
It just dawned on me that every time I saw something created on the heap, which I believe was always created with a pointer. This is probably because "new" always returns a pointer to the address that was created. So, it is fair to say that anytime you want to create something on the heap (using new/delete), a pointer is REQUIRED, and you cannot create on the heap without a pointer. Which I believe to be correct.

Perhaps a different way to think about this is, "new" creates an object, and returns its address. That address is the pointer.

Regarding your indexing examples that work/don't work, have you tried printing the addresses that result from your various dereferencing efforts?

Regarding:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Car* myCar1 = new Car();
Car* myCar2 = new Car();

Car* myCarColl1[ARRAY_SIZE] = {myCar1, myCar2 };

(*myCarColl1)[0].GetCarID();	//WORKS
myCarColl1[0]->GetCarID();		//WORKS	
myCarColl1[1]->GetCarID();		//WORKS

(*(myCarColl1 + 1))[0].GetCarID();
//(*myCarColl1)[1].GetCarID();		//DOES NOT WORK
//(*(myCarColl1 + 1))[1].GetCarID();	//DOES NOT WORK
//(*myCarColl1 + 1)[1].GetCarID();		//DOES NOT WORK
//(*(myCarColl1 + 1)).GetCarID();		//DOES NOT WORK 


(*myCarColl1 + 1) is the same as &myCarColl1[1]
and
(*myCarColl1) is myCarColl1[0]

So:
(*myCarColl1)[0] is myCarColl1[0][0], is nonsense
(*myCarColl1 + 1)[1].GetCarID() is myCarColl1[1][1].GetCarID(), and its variants are also nonsense

You need to read more about pointer arithmetic.
Last edited on
part 2:
(*(myCarColl1 + 1))[0].GetCarID();
more syntax. I would recommend you forget that this works and stay far, far away from it unless you want to write for the convoluted C competition.

(*(myCarColl1 + 1))
added one to the pointer. fine, this cooks up a new address...
(*) in front of an address dereferences it.
so now you have effectively said
myCarColl1 [1]
and that^^ IS a pointer. so [0] works there ... and gets to the actual object where you can then get to its method...

kbw wrote:
(*myCarColl1 + 1) is the same as &myCarColl1[1]

Typo:
(*(myCarColl1 + 1)) is the same as myCarColl1[1], but
(*myCarColl1 + 1) is the same as myCarColl1[0] + 1

jonnin wrote:
The convoluted C competition
The IOCCC: https://www.ioccc.org/
Last edited on
 
(*myCarColl1)[1].GetCarID();


Good explanations, I get it. Not only does (*myCarColl1) mean a dereference of the pointer to the array (the array itself), and specifically the first index of the array, but it literally/actually translates to myCarColl1[0].
It is as if I am trying to access a 2-dimensional array myCarColl1[0][0].



So my line below works by sheer coincidence because it is the first member of the non-existing 2-D array "myCarColl1[0][0]":

 
(*myCarColl1)[0].GetCarID();	//WORKS 



So now after the change this works:
1
2
        (*myCarColl1[0]).GetCarID();
        (*myCarColl1[1]).GetCarID();


Because the operator precedence first grabs this "myCarColl1[1]" and gets the address of the pointer stored in index [1] and then the * dereferences it to get the object.GetCarID();

@kbw
I printed out the addresses in another simpler example of just int/string in an array, and I was able to traverse them with incrementing addresses and then resetting them just fine. I did not try to print them here though. Thanks for reaffirming "myCarColl1[0][0]".

@jonnin
So below, because we don't have the [] subscript operator, "myCarColl1 + 1" is still the pointer to the array + 1 object address over.
Then "(*(myCarColl1 + 1))" dereferences that new pointer address to the actual array at index [1], but then we need to dereference that pointer stored in index [1] to the object using the pointer operator
"->GetCarID();"

 
	(*(myCarColl1 + 1))->GetCarID();


I think I get it now and it is best that I review all the sample programs that I have from scratch to see how much more clearly it all fits in now.

Thanks again!
@mbozzi
Yea, I saw that too. I think he implied that the pointer points to the address of the object at index [1], which has the address of the 2nd object.

C++ is such a brain twister.

"(*myCarColl1 + 1) is the same as &myCarColl1[1]"
Topic archived. No new replies allowed.