Messing with memory

Started by
20 comments, last by Zahlman 18 years, 4 months ago
Quote:Original post by Niddles
Okay so what this does is it creates an array of 50 objects, and a function pointer to return the address of one of those 50 objects. Ugh, that's confusing.


No, it doesn't. The class has an array of 50 instances of the object. Because it is private, you normally cant touch them. Returning a pointer to the start of them, however, allows to do mess around with all 50.

Edit: I'm a little tired and whatnot, see my post two posts down for the correct answer.
Advertisement
Okay, I thought I had it, but now I don't understand.
Sorry: I was a little wrong. Let me explain again.

THe class simply has 50 of the instances. The function returns the address of the one you pass to it. That way you can mess around with the one you ask for.
Quote:Original post by Niddles
Okay so what this does is it creates an array of 50 objects, and a function pointer to return the address of one of those 50 objects. Ugh, that's confusing.


That's exactly what it does. It's a way of keeping the objects encapsulated while still allowing access to an object when you need it. You could work around this by making the objectlist array global but then that defeats the purpose of using a class at all (use a structure).

What is more common is to have an array of pointers to gameobjects and then allocate them at runtime and return that pointer in the function. Technically you'd be returning a pointer to a pointer. Think about that one for a moment.

The reason why a list of pointers is more common is because it saves memory. When you use the new command on a pointer to an object, it creates that object at the location of the pointer which consumes that much memory. By not allocating (new'ing) memory, you save it for use for other things. Of course nowadays prebuilt computers come standard with 512mb of ram so you can probably argue so what. =)

EDIT: I read it as a function returning a pointer in my haste... a function pointer is something different. For clarification.
Most of our obstacles would melt away if, instead of cowering before them, we should make up our minds to walk boldly through them.- Orison Swett Marden
Here, I wrote this.. is it right?
#include <iostream>#include <string>using namespace std;class weapon {  private:    int id;    string name;  public:    void setid(int fid) { id = fid; }    void setname(string fname) { name = fname; }    int *getwid();    string *getwname();  };class object {  private:    weapon oweapon[10];  public:    void setoweapon();    int *getwid(int num);    string *getwname(int num);  };void object::setoweapon() {  for(int a=0; a<10; a++) {    oweapon[a].setid(a);  }  oweapon[0].setname("gun");  oweapon[1].setname("club");  oweapon[2].setname("axe");  oweapon[3].setname("bat");  oweapon[4].setname("chicken");  oweapon[5].setname("crobar");  oweapon[6].setname("whip");  oweapon[7].setname("seven");  oweapon[8].setname("bloop");  oweapon[9].setname("dog");}int* weapon::getwid() {  return &id;}string* weapon::getwname() {  return &name;}int* object::getwid(int num) {  return &oweapon[num].getwid();}int* object::getwname(int num) {  return &oweapon[num].getwname();}int main() {  object o;  o.setoweapon();  for(int a=0; a<10; a++) {    cout<<o.getwid(a)<<endl;  }  for(int b=0; b<10; b++) {    cout<<o.getwname(a)<<endl;  }  return 0;}
Commented improved version:
#include <iostream>#include <string>using namespace std;class weapon {  private:    int id;    string name;  public:    void setid(int fid) { id = fid; }    // this is not a good practise - the parameter will be copied, e.g.    // "fname" will allocate memory internally each time you pass a string//    void setname(string fname) { name = fname; }    // try using a const reference instead, this will only pass the address    // and also tells the compiler that "fname" won't be modified, so no    // additional memory will be allocated if you pass a string object    void setname(string const & fname) { name = fname; }    // returning pointers is dangerous - don't do it unless it is your intention    // to mess with memory. a pointer can not be distinguished from an array in C++//    int *getwid();    // the "const" tells the compiler that the internal state of the class instance    // won't be modified by the method - we only want to return something    int getwid() const;    // same as above//    string *getwname();    // by returning a const reference we avoid unnecessary copies    string const & getwname() const;  };class object {  public:    // this constant is public so that users can query the number of entries    static int const MaxWeapon = 10;  private:    // avoid magic numbers!    weapon oweapon[MaxWeapon];    // this should be private and get called in the constructor       void setoweapon();  public:    // in this constructor we setup the names automatically.    object();    // this is a constant that indicates an invalid weapon id.    static int const InvalidWeaponId = -1;    // this is a dummy we return if the user passes an invalid id to getwname()    static string const EmptyName;    int getwid(int num) const;    string getwname(int num) const;  };void object::setoweapon() {  for(int a=0; a<MaxWeapon; a++) {    oweapon[a].setid(a);  }  oweapon[0].setname("gun");  oweapon[1].setname("club");  oweapon[2].setname("axe");  oweapon[3].setname("bat");  oweapon[4].setname("chicken");  oweapon[5].setname("crobar");  oweapon[6].setname("whip");  oweapon[7].setname("seven");  oweapon[8].setname("bloop");  oweapon[9].setname("dog");}// initialise the weapon names on constructionobject::object() {   setoweapon();}// just return the idint weapon::getwid() const {  return id;}// just return the namestring const & weapon::getwname() const {  return name;}// we want to protect the class from invalid calls and check the index for validity:int object::getwid(int num) const {  if ( num >= 0 && num < MaxWeapon )      return oweapon[num].getwid();  else     // we also want the caller to know that she messed up :)      return InvalidWeaponId;}// same as abovestring const & object::getwname(int num) {  if ( num >= 0 && num < MaxWeapon )      return oweapon[num].getwname();  else      return EmptyName;}int main() {  object o;  // not necessary anymore - the constructor does that // o.setoweapon();  // use the MaxWeapon constant  for(int a=0; a<object::MaxWeapon; a++) {    cout<<o.getwid(a)<<endl;  }    // use the MaxWeapon constant  for(int b=0; b<object::MaxWeapon; b++) {    cout<<o.getwname(a)<<endl;  }  return 0;}


If you have questions, let me know.

HTH,
Pat
I couldn't imagine not using pointers in c++. They are so incredibly powerful and useful. I would recommend trying to find a use for them so you will feel comfortable with them. Your programming will never be the same.
Well there are a number of programming errors. First off, you changed the return type of your object::getwname(int num) from string* to int* when you declared it. The second and third errors are in returning pointers to pointers in your object class when you declared you would be returning a single pointer. See below.

int* object::getwid(int num) {  return oweapon[num].getwid();}string* object::getwname(int num) {  return oweapon[num].getwname();}


I removed the & in front of the variables because you do not want to return the adress of the variable because you previously defined in getwid() and getwname() that you would already be returning the address already.

The next errors aren't compile errors but runtime errors.

for(int a=0; a<10; a++) {    cout<<o.getwid(a)<<endl;  }  for(int b=0; b<10; b++) {    cout<<o.getwname(a)<<endl;  }


Because you are dealing with pointers to variables you can't simply output their values with cout. You must dereference them using the * symbol. Like so. Also note that in your for loop that increments 'b' you should put o.getwname(b) instead of 'a' as you are incrementing that and 'a' already = 10.

for(int a=0; a<10; a++) {    cout<< *o.getwid(a)<<endl;  }  for(int b=0; b<10; b++) {    cout<< *o.getwname(b)<<endl;  }


It should run as expected now. However, in terms of coding this to make it easier to understand and even save you some typing, I would avoid returning pointers of variables that there is only one instance of (eg. returning int* getwid() in class weapon). Instead of having to create duplicate functions in your object class for each weapon function you create. You can simply return a pointer to a specific weapon and then use the pointer to call functions from that class.

class weapon{private:    int id;    string name;public:    int getwid()    {        return id;    }    string getwname()    {        return name;    }};class object{private:    weapon oweapon[10];public:    weapon *getweapon(int num)    {        return &oweapon[num];    }};


Then in main you would call..

for (int a=0;a < 10;a++){    weapon *currentweapon = o.getweapon(a);    cout << currentweapon->getwid() << endl;    cout << currentweapon->getwname() << endl;    //or even o.getweapon(a)->getwid() will work but may look confusing.}


Hope that helps. Good luck in your programming.
Most of our obstacles would melt away if, instead of cowering before them, we should make up our minds to walk boldly through them.- Orison Swett Marden
Pointers are a great tool for a lot of things:

o Polymorphism (access of classes via base classes and derived classes)
o Working on memory (image data, sound data, etc.)
o Callbacks/Delegates

Just imagine the memory as one huge array:

unsigned char ucArray[2000000];

Now imagine the bytes from array position from 1024 up to 2048 would be a image. Another feature: This image is not fixed at position 1024, it can be anywhere inside that array.

How to have a piece of code to access the bytes of the image? Either you need to store the index and have the code know about the array. Or you pass a pointer to the function: Here, you don't need to know anything about an array or offsets. Just use the pointer; it points to the start of a 1024 byte sized block of memory with the image inside.

The pointer can locate the block inside array ucArray, but as well in any other array.

Hm, probably not the best example but it should clarify things a bit.

Fruny: Ftagn! Ia! Ia! std::time_put_byname! Mglui naflftagn std::codecvt eY'ha-nthlei!,char,mbstate_t>

Quote:Original post by Endurion
Pointers are a great tool for a lot of things:

o Polymorphism (access of classes via base classes and derived classes)
o Working on memory (image data, sound data, etc.)
o Callbacks/Delegates

Just a quick note: you can exercise polymorphism using references as well.
:stylin: "Make games, not war.""...if you're doing this to learn then just study a modern C++ compiler's implementation." -snk_kid

This topic is closed to new replies.

Advertisement