Archived

This topic is now archived and is closed to further replies.

Is this correct usage of pointers?

This topic is 5499 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

As I was writing this program I suddenly felt unsure about pointers. I'm not yet in a position to test-build so I'm asking here if this is correct before I write a bunch of code which uses these. These structures will hold animation data. Each animation can move an arbitrary number of objects, and each object can have an arbitrary number of key frames.
    
struct ANIMDATA
{
    CString AnimName;
    int ObjectCount;

    OBJECTDATA* pObjects;
};

struct OBJECTDATA
{
    CString ObjectName;
    int FrameCount;
    bool bRoot;

    FRAMEDATA* pFrames;
};

struct FRAMEDATA
{
    D3DXQUATERNION Rotation;
    D3DXVECTOR3 Translation;
    float fTimeIndex;
};
  
Then after I have a ANIMDATA* pAnims assigned, I figured I'd do this within a loop as it reads from a file...
        
(pAnims+i)->pObjects = new OBJECTDATA[(pAnims+i)->ObjectCount];
  
...and likewise for pFrames. Yes, ObjectCount will have been assigned before this part. Is this the right way to use the -> operator and the right way to create an array of arbitrary size? [edited by - Hollower on November 20, 2002 12:36:28 AM]

Share this post


Link to post
Share on other sites
If your purpose of pointers are just for having a ''dynamic'' array, I would suggest using std::vector (or alike) to reduce fever and stars in your head. eg.


  
struct ANIMDATA
{
CString AnimName;
int ObjectCount;
std::vector<OBJECTDATA> vObjects;
};
struct OBJECTDATA
{
CString ObjectName;
int FrameCount;
bool bRoot;
std::vector<FRAMEDATA> vFrames;
};
struct FRAMEDATA
{
D3DXQUATERNION Rotation;
D3DXVECTOR3 Translation;
float fTimeIndex;
};

std::vector<ANIMDATA> vAnims;
...
vAnims[i].vObjects.resize(vAnims[i].ObjectCount);
// or

vAnims[i].vObjects.reserve(vAnims[i].ObjectCount);

... and remember to look up the doc for more samples and detail explanations.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
yes, you are using them correctly.

the code you provided will not compile though.
you are declaring structs within each before they are defined.
so, you need to rearrange the structs.
FRAMEDATA first.
OBJECTDATA
ANIMDATA last.

also you need to declare them as such..

struct FRAMEDATA {
} FRAMEDATA;

if you do not declare them this way every time you declare
a "new" FRAMEDATA you _must_ put "struct" in front of it.

so in your current code, youd need to do...

struct OBJECTDATA {
.
.
struct FRAMEDATA *pFrames;
};

for it to compile.

yes, you can use the std::vector that DerekSaw suggested,
but if i were you, id learn how to use pointers properly
from the beginning instead of having to rely on something
someone else wrote.

Share this post


Link to post
Share on other sites
Well there are some reasons why a structure may be prefferable to a class.

One unique example is online gaming. Structures have a lot less overhead then classes, so they are more beneficial for transfer over the internet. Less overhead means they will be smaller in size. However, classes do have many more advantages over structures most of the time. It just depends on what you need, and your personal preference.

Share this post


Link to post
Share on other sites
C++ structs and classes are virtually identical. The only difference is that the members are public by default in a struct and private by default in a class. There is no additional overhead in using classes instead of structs, and a class is not more advanced.

Share this post


Link to post
Share on other sites
Thanks Derek I will look into vectors. I've seen them mentioned but never anything in-depth. I'll search but if anyone knows a good vector tutorial link that would be nice.

Thanks Anon, I didn't even realize that. My limited knowledge is becoming apparent with this little animation experiment. I've never tried to build a "tree" structure before. As for the rest of the comments, maybe it's a bad habit but I tend to use struct for simple data, and class for more "functional" things. I know they are identical except for the public/private thing.


[edited by - Hollower on November 21, 2002 11:17:37 PM]

Share this post


Link to post
Share on other sites
quote:
if you do not declare them this way every time you declare
a "new" FRAMEDATA you _must_ put "struct" in front of it.


Forward declaration might do the trick.
quote:
So why use structs?????

struct still, by default, publicly accepted.
quote:
Structures have a lot less overhead then classes, so they are more beneficial for transfer over the internet

Who say so? Prove it technically, and have the whole world believe it.

Share this post


Link to post
Share on other sites
A std::vector simple sample:

  
#include <iostream>
#include <vector>
int main()
{
std::vector<int> vNumber;

// add to the tail of the vector

vNumber.push_back(7);
vNumber.push_back(5);
vNumber.push_back(11);

// ''read'' access

cout << vNumber[0] << endl; // output: 7

cout << vNumber[1] << endl; // output: 5

cout << vNumber[2] << endl; // output: 11

cout << vNumber.size() << endl; // output: 3


// ''write'' access

vNumber[0] = 13;
cout << vNumber[0] << endl; // output: 13


// clear your vector

vNumber.clear();
cout << vNumber.size() << endl; // output: 0

return 0;
}
[/soure]

Share this post


Link to post
Share on other sites
quote:
Original post by Hollower
While we''re on the topic of structs, I sometimes see people do this:

typedef struct SOMETHING {
...

Does that make something different happen?



This was how you had to do things in C. If you didn''t you have to do this:

struct SOMETHING mystruct;

in order to create an instance of the struct.

With the typedef, you can just do:
SOMETHING mystruct;

You no longer have to do this in C++.


________________________
Grab your sword, and get prepared for the SolidSteel RPG engine, coming soon...(i.e. when it''s done)

Share this post


Link to post
Share on other sites
quote:
Original post by Hollower
While we're on the topic of structs, I sometimes see people do this:
typedef struct SOMETHING {
...
Does that make something different happen?

That was some classic C coding practices...

    
// the "good'ol days"

typedef struct tagSOMETHING // or just "typedef struct {"

{
...
}SOMETHING, *LPSOMETHING;
SOMETHING s1;
LPSOMETHING pSomething;
//-------------------------------

// now...

struct SOMETHING
{
...
};
SOMETHING s1;
SOMETHING *pSomething;


[EDIT]
Cold_Steel already explained: C++ won't need it.
I believe the newer C won't need it too.


[edited by - DerekSaw on November 21, 2002 11:35:53 PM]

Share this post


Link to post
Share on other sites
All caps is kinda only suppose to be used for #define macros as well. C & C++ prefer lower case identifiers.

I would also like to urge you to *not* use CString - it's a Microsoft specific MFC string class. #include and use std::string instead if you want a class to manage your strings.

While (pAnims+i) is technically correct, it is stylistically uncommon (unless you look at ioccc code); consider using pAnims[ i ] instead.

pAnims[ i ]->pObjects = new OBJECTDATA[pAnims[ i ]->ObjectCount];

This will also do the same thing:
(*pAnims[ i ]).pObjects = new OBJECTDATA[(*(pAnims+i))->ObjectCount];

p-> translates into (*p). for "raw" pointers. The issue is that the . operator has the highest precedence. So if you do *p.pObject it wants to do the . before the *. So to make it work right you have to put in ( ) to tell it the order you want it done in, (*p).pObject; This is clumsy, so K&R added -> as a short-cut.


...
It's already been stated, but I want to reinforce the fact that class and struct are extremely similar and have no performance differences.

A class or struct with no public elements is quite rare, so the question becomes why use class? It's simply a matter of style (i.e. personal preference) on which you use.

[edited by - Magmai Kai Holmlor on November 21, 2002 11:56:34 PM]

Share this post


Link to post
Share on other sites
Magmai is wrong. Bad Magmai. This:

(pAnims+i)->pObjects = ...

is equivalent to this:

pAnims[ i].pObjects = ...

Magmai mistakenly used the reference operator ->, but [] dereferences a pointer.

Hollower, your code would compile and work perfectly correctly except that you need to add this:

struct OBJECTDATA;

right before the ANIMDATA definition. This just tells the compiler ahead of time that there is a struct called OBJECTDATA so it doesn't get confused when it sees the "OBJECTDATA* pObjects" bit.

~CGameProgrammer( );

[edited by - CGameProgrammer on November 21, 2002 12:06:32 AM]

[edited by - CGameProgrammer on November 22, 2002 6:21:09 AM]

Share this post


Link to post
Share on other sites
Any more help will probably just confuse me. And Magmai will probably dislike this but I''m doing this in Visual C++ using the "AppWizard". So it''s already dependant on MFC and using CString isn''t going to make it moreso. It doesn''t need portability...this IS the beginners forum after all.

Share this post


Link to post
Share on other sites
I agree that you should use CString and MFC if you''re comfortable with it. I used them as a stepping-stone before moving up (to creating my own string class, incidentally; I don''t use STL). They are perfectly good for beginners. You are not concerned with porting your Hello World program to different platforms

~CGameProgrammer( );

Share this post


Link to post
Share on other sites
Basically, there is no right or wrong reason to use a class, as they are identical in implementation - so a person can use just classes OR just structs and everything would work just the same ... but ... the most common convention is this:

use class when you will access data members throught member function calls - ie:

x = myObject.NumChildren();

use struct when you will access data members directly:

x = myStruct.NumChildren;

about vectors ... do you know how to use arrays? if so ... vectors are easy:

the most basic things to know are:

the subscript operator acts just like an array (returns a reference to the element ...

myVector.size() - returns the number of elements in the vector (so your won''t need to store this seperately anymore).

myVector.resize(int) -
myVector.resize(int, obj) -
makes the list the specified size, the top one uses the default constuctor when making objects, the bottom uses the copy constructor ...

myVector.push_back(obj) - add the object to the end
myVector.pop_back() - remove the object at the end

ITERATORS ... are easy for people who know pointers ...


  
std::vector<MyType> myVector;
myVector.resize(20);
for(std::vector<MyType>::iterator pos = myVector.begin(); pos != myVector.end(); ++pos)
{
*pos = someValue;
}

// is the same as


MyType myArray[20];
for(MyType *pos = myArray; pos != (myArray + 20); ++pos)
{
*pos = someValue;
}


think of the iterator as just a pointer ...
this of begin() as the address of the first element ...
think of end() as the address ONE PAST the last element ... so the address of first element plus the size.

IF you use a typedef for your vector, like this:

typedef std::vector MyTypeVector;

then the iterator type is:

MyTypeVector::iterator, much better than std::vector::iterator

Share this post


Link to post
Share on other sites
quote:
Original post by CGameProgrammer
(pAnims+i)-&gtpObjects = ...
&gt is not a valid character entity unless it''s followed by whitespace or a html tag. Most browsers won''t display it the way you intended. You need to type &gt; instead.

Share this post


Link to post
Share on other sites
as for CString vs. std::string ... here''s the thing -

IF you are using GUI widgets with MFC in windows, then go ahead and use CString ...

BUT you will need to know std::string soon anyway ... to use std::c++ functions.

the only critical thing a newbie needs to know about a std::string is this:

when you need a c style "const char *" use the member function c_str() ...

like this:


  
const char *string2= "c string version";
std::string string3 = "std::string version";
CString string4 = "CString version";

MessageBox(hWnd, "Message Box 1", "immediate version", MB_OK);
MessageBox(hWnd, "Message Box 2", string2, MB_OK);
MessageBox(hWnd, "Message Box 3", string3.c_str() , MB_OK);
MessageBox(hWnd, "Message Box 4", string4.GetBuffer() , MB_OK);


hope that makes it all clear ...

Share this post


Link to post
Share on other sites