Having trouble getting my head around pointers

Started by
28 comments, last by rip-off 16 years, 10 months ago
I've been reading quite a bit on pointers recently and I still can't get my head around them. Why are they so powerful? Are there any good examples which can be given? I'm aware they point to a place in memory, so does this mean they can be used as a sort of global variable? Like, say I create a variable in one class, can a variable in another class be a pointer, and point to that variable in the other class...?
Advertisement
They allow you to allocate memory during run-time.

int n_names;std::string names[ ??? ]


How many names do we allocate? We don't know at compile time, since we'll read them from a file. We can allocate 100 names, but then we'll either waste memory, or not have enough, if there are 17,331 names in the file.

Dynamic memory allocation allows you to decide that during run-time. Pointers are the supporting syntax.

Another aspect is sharing data. Consider an Image object (1 Mb in memory). Now you need to use this image as texture on 500 different models. Without pointers, you need to make 500 copies of the same image. With pointers, you just pass the pointer around, and use the same image object.

Last use, the most dangerous one, is direct memory access. Variables, and even code, are stored in memory as a sequence of bytes. If the system you're using supports the concept of memory pointers (Java doesn't), then you can manipulate these bytes manually, creating code on the fly (self-modifying program) or you access the data your application uses directly (pixels of an image).
Quote:Original post by AntheusAnother aspect is sharing data. Consider an Image object (1 Mb in memory). Now you need to use this image as texture on 500 different models. Without pointers, you need to make 500 copies of the same image. With pointers, you just pass the pointer around, and use the same image object.


And this is good because instead of having to pass around that 1MB object, you pass around that 4 Byte / 8 Byte / Whatever size pointer instead. Smaller and faster.

Oh ok, so for a 2D tile game, it's pretty much necessary to use pointers for the image tile being used? What about my last question, about pointers between two classes?
Quote:Original post by Side Winder
Oh ok, so for a 2D tile game, it's pretty much necessary to use pointers for the image tile being used? What about my last question, about pointers between two classes?


Sure. As long as you're perfectly clear on who and when allocates/de-allocates memory.

Let's say you pass a pointer from class A to class B. What happens if class A is de-allocated? Will B aware that it needs to de-allocate that pointer? What if A is still alive, and is using that variable?

Or, simply put, make sure you understand dynamic allocation mechanisms, then use it very sparingly. In C++ that's the biggest challenge of all, managing object life-cycle.

If you're using C# or Java, then this is a non-issue (most of the time), since VM will do the de-allocation for you.

For object references, you should also look into smart pointers once you'd want to use dynamically allocated objects on a larger scale.

It's just a very big and complex topic with thousands of pitfalls.

But generally, you do not *need* to use pointers. In C++ you can use references (the & syntax). They give you most of the functionality of pointers, but with almost no problems.
Hmm, yeah it does seem quite complicated.

OK, let's say, for example, that I'm making a Win32 program and I have two classes. In the first class I have the window handle. I want to get a hold of that window handle from the second class.

class Window{HWND hwnd;};


class Yes{...};


Something like that. What would I have to do to get that window handle? And what would be the syntax...? Would I have to use inheritance and have an accessor function, or could it all be done with references (or pointers)?
A pointer is a variable that contains the memory address of another variable or a block of RAM. They allow you to access that space without having to copy the original variable or memory block. There are many reasons why this is useful:
1) Polymorphic behavior is only possibly through reference types (references or pointers)
2) Coping a pointer is often cheaper than copying a structure/object/block of RAM
3) Since they are reference types they can also allow a function to return multiple variables by referencing a user created object and filling it with data. For example:
void Add2to3(int *one,int *two,int *three){  *one+=2;  *two+=2;  *three+=2;}void main(){  int a=8;b=11;c=5;  Add2to3(a,b,c);  // now a=10, b=13, and c=7}


Pointers are not only powerful but they are dangerous, here are some of the pitfalls:
1) Dynamic memory allocation can lead to a memory leak: If you assign a pointer to the value of "new" or "malloc" you have to call "delete" or "free" on that same pointer before it exists scope. If you do not, you have just leaked memory. Failing to do this consistently is so notoriously common that we now have things like smart pointers to help us. Unfortunately, smart pointers are even more complex than ordinary pointers, but they are much safer.
2) Dangling pointer: Sometimes you do remember to call "delete" or "free" on the pointer data but forget to stop using pointers that were referencing that same data. Other times this happens when you have a pointer to data on the stack, and that data goes out of scope before all of the pointers to it do. This results in a dangling pointer referring to data that can no longer be safely accessed. Trying to access that data can cause all sorts of weird errors, although often times it will just crash your program.
3) Null pointer: If are really smart, after freeing or deleting your pointer you assigned it a null value (0=null) indicating that it no longer points to anything. However, you must still be careful because trying to access the data from a null pointer when there is none (because it's null) will cause a crash (although it's usually safer than a dangling pointer crash).
4) Buffer overrun: This is just like a dangling pointer except worse. Occasionally doing pointer arithmetic ( *(pointer+x) OR array[x] ) can result in a reference to data that you did not allocate. Trying to access this data could crash your program for an access violation right there, or if you are really unlucky it could corrupt data elsewhere in RAM and possible cause a crash in some random place that has nothing to do with the buffer overrun.

Smart pointers can fix problems 1 & 2 and often times 3, and smart programmers using safe methods can correct number 4.

Smart pointers are safer but they are also complex. If you want to try them I would suggest the boost version.

Whatever you decide, use pointers but do so carefully. Also avoid "void *" at all costs.
Programming since 1995.
Quote:Original post by Side Winder
Hmm, yeah it does seem quite complicated.

OK, let's say, for example, that I'm making a Win32 program and I have two classes. In the first class I have the window handle. I want to get a hold of that window handle from the second class.

*** Source Snippet Removed ***

*** Source Snippet Removed ***

Something like that. What would I have to do to get that window handle? And what would be the syntax...? Would I have to use inheritance and have an accessor function, or could it all be done with references (or pointers)?


You don't want to do that.

HWND is a handle, and as such has lifecycle beyond your control.

The proper solution in your case would be to pass the reference to instance of Window object to other classes. Alternative would be to just pass HWND itself into classes that need it.

class Window {public:  Window( HWND hwnd )    : m_hwnd( hwnd )  {}  HWND GetHWND() { return m_hwnd; }private:  HWND m_hwnd;};typedef Window * WindowPtr;class Yes{public:  Yes( WindowPtr wPtr )    : m_window( wPtr )  {}  void foo()  {    m_window->GetHWND();  }private:  WindowPtr m_window;};


Of course, you now need to ensure that Window will get properly allocated and de-allocated, and that Yes will not use the pointer once it's no longer valid.

...WindowPtr wPtr = new Window( hwnd );Yes y( wPtr );y.foo();delete wPtr;y.foo(); <-- Here there be dragons


But bad things will happen if you delete wPtr while Yes can still use it. On second call to foo, the behaviour of foo() is undefined. It might work as before, it might crash, it might do weird things.
Ah ok... Hmm.. Maybe I should switch to C# so I wouldn't be having these problems :p
Quote:Original post by Side Winder
Ah ok... Hmm.. Maybe I should switch to C# so I wouldn't be having these problems :p


++rating, for enlightenment and being one of the few beginners to have not to be beaten to death to gain such enlightenment.

Beginner in Game Development?  Read here. And read here.

 

This topic is closed to new replies.

Advertisement