views:

654

answers:

6

Hello,

I notice this has caused confusion for several people, but after reading a couple of posts on here and the cplusplus tutorial my brain is still scrambled.

Suppose I have the following variables in a header file -

int numberOfLinePoints;
D3DXVECTOR3* line;   //confused as to what it is

Then in the implementation C++ file I initialize them as follows -

//both initialized in constructor
numberOfLinePoints = 25;
line = new D3DXVECTOR3[numPoints];   //array of pointers?

What does my line variable now represent?

As far as I can tell from reading links on stackoverflow it should represent an array of pointers. I then read the following however...

(1) Pointers for Beginners

...where (A) arrays of pointers, and (B) pointers to arrays, are both discussed. This left me confused once again as they both seem to work similarly.

The fact that I define my pointers in a seperate location to where I allocate (correct?) them seems to be where my confusion stems from. Am I correct that this is an array of pointers to D3DXVECTOR3 objects?

To finish - if variable line holds information about one line segment, how would I create an array of line segments? I currently have the following -

//HEADER FILE
int numberOfLineSegments;
D3DXVECTOR3** lineCollection;   //array of pointers - each of which
                                //points to an array of pointers?
//CPP FILE
numberOfLineSegments = 8;                            //constructor
for(i = 0; i < numberOfLineSegments; i++)            //initialization
{                                                    //and allocation  CORRECT?
   lineCollection[i] = new D3DXVECTOR*[numPoints];   //of memory for     Y/N
}                                                    //lineCollection

VOID createLineSegments(startPoint, endPoint) //could return array instead
{
//pseudo to generate one line segment
while != numberOfLinePoints
line[sentinel++] = interpolate(startPoint, endPoint, time_T)

//pseudo to generate array of line segments
while != numberOfLines
lineCollection[sentinel++] = line
}

Any help is much appreciated.

+2  A: 
D3DXVECTOR3 line; // Line is a D3DXVECTOR3
D3DXVECTOR3 * line; // Line is EITHER a pointer to D3DXVECTOR3 OR an
                    // array of D3DXVECTOR3
D3DXVECTOR3 ** line; // Line is an array of pointers to D3DXVECTOR3 OR
                     // an array of array of D3DXVECTOR3

This is because an array is no specific structure in memory. It is just a bunch of D3DXVECTOR3 in a row. So pointing to the first element, and you get access to all of the others.

So, having

D3DXVECTOR3** lineCollection; // An array of pointers OR an array of array!
new D3DXVECTOR[numPoints]; // A pointer to an array of D3DXVECTOR
lineCollection[i] // A pointer to an array

You initialize it by:

lineCollection[i] = new D3DXVECTOR[numPoints]; // No extra *

Yet: try to use the STL (like std::vector) instead of ugly C/Java style arrays. If you can, avoid declaring on the heap (using 'new'), but rather declaring on the stack:

D3DXVECTOR a, b, c; // a, b, and c ARE D3DXVECTOR, not pointers
std::vector<D3DXVECTOR> lines;
lines.push_back(a);
lines.push_back(b);
lines.push_back(c);

// equivalently: (you can push_back without temporaries)
std::vector<D3DXVECTOR> lines;
lines.push_back(D3DXVECTOR());
lines.push_back(D3DXVECTOR());
lines.push_back(D3DXVECTOR());

This will avoid manual memory management; it's more readable. You might not be able to always use that comfort (the way your code is organized). And if someone says something about performances, for now, don't worry. First get something working without segfaults nor memory leaks.

Tristram Gräbener
AFAIK compilers can decide to allocate objects on the stack even when new is used, if program behavior does not change. Just a side-note though.
Space_C0wb0y
I missed this post. Actually this along with Donnie's helps a lot. Shame I can't set two correct answers. Thank you.
Happy it could help.@Space_cowboy : I don't know much about the compiler optimizations, and I looking for some nice term to explicitly tell name both means of allocation, as I more interested from the programmer side. Heap and stack will confuse new users (and apparently advanced also). Any suggestion here ?
Tristram Gräbener
+1 for stl::vector over arrays
Donnie
Roger Pate
Space_C0wb0y: While true, using the "as-if rule" in the standard, that is incredibly hard to arrange in practice and I don't know of any implementations that try. (The compiler would have to do global analysis to make sure you don't write your own operator new, for one.) If there are such implementations, I would be very interested in seeing how they do it.
Roger Pate
@Roger Pate: no problem, you did right! :) a shame I don't double-check what I write... About performances, I just didn't want to enter in any performances or limited stack size considerations I often see; you're right again ;)
Tristram Gräbener
+1  A: 
line = new D3DXVECTOR3[numPoints];

line holds the memory address of the first element of the array of D3DXVECTOR3.

I.e. line is a pointer to the first element of the array.

This article should clarify it.

Brian R. Bondy
Thanks for the link.
+2  A: 
int numberOfLinePoints;
D3DXVECTOR3* line;   //confused as to what it is
//both initialized in constructor
numberOfLinePoints = 25;
line = new D3DXVECTOR3[numPoints];   //array of pointers?

line is an array of D3DXVECTOR3. It would be an array of pointers if D3DVECTOR3 is itself a pointer, however. Since I don't know the C++ D3D headers very well, I'm not sure.

D3DXVECTOR3** lineCollection;

Is an array of pointers, each pointer likely being a pointer to a line (that is, an array of D3DXVECTOR3).

You have two options. Memorywise, the best would be to set each entry in lineCollection to just point to the corresponding line. This is safe if you either know the lines aren't going to change (and aren't going to be freed), or if they do change you want the changes to be reflected immedaitely inside your collection.

The other option would be to create a new array for each entry in lineCollection, and copy the points from each line into this new array.

There is no correct answer, it depends on the functionality you want.

Donnie
Thanks Donnie this is exactly what I wanted to know. All other replies were helpful also, but this was probably the clearest in the way I could comprehend it.
A: 

Just look at this simple example :

case 1:

int *p = new int [N];

Here p is pointer to array of N integers and p stores starting address of the array.

case 2:

int **p = new int *[N]; //p is a pointer to pointers holding integers used for 2D array.


for(int i=0 ; i<N ; i++)
{

    p[i] = new int [N]; // each element is pointer to array of integers.

}

It is applicable to all kinds of user defined types.

Ashish
+4  A: 

Your first example:

int numberOfLinePoints;
D3DXVECTOR3* line;   //confused as to what it is

Declares a simple pointer to a D3DXVECTOR3. A pointer can be initialized in two ways. First:

line = new D3DXVECTOR3;

This creates a single D3DXVECTOR3 and makes line point to that object. Second:

line = new D3DXVECTOR3[numberOfLinePoints];

This creates an array of D3DXVECTOR3s and makes line point to the first element of that array. You can then use pointer arithmetics to access other elements in that array.

If you declare you pointer as double pointer:

D3DXVECTOR3** line;

You simply create another level of indirection.

Space_C0wb0y
+3  A: 

(Attempting to answer the first part of the question as succinctly as possible without introducing other issues.)

C++ (and C) uses pointers to a single item in an array as a handle for the full array. However, some pointers don't point to items in an array! You have to make the distinction between points-to-single-item and points-to-item-in-array yourself.

int length = 8;
D3DXVECTOR3* line = new D3DXVECTOR3[length];

The new[] operator returns a pointer to the first item in the array it allocates, and this assigns that value to line. Notice that because pointers don't make the distinction of single-item vs. item-in-array:

  • you have to store the length separately
  • you have to be careful you use correct indices with pointers ("line" above)
  • you are better off using a "real" container type, such as:
    • std::deque, std::vector, etc.
    • std::tr1::array (aka boost::array)

(The last bullet point doesn't mean you never use pointers, you just don't use them when these containers are more appropriate.)

Roger Pate