Pointers, seriously.

Whether you're a newbie or an experienced programmer, any questions, help, or just talk of any language will be welcomed here.

Moderator: Coders of Rage

Post Reply
corey__cakes
ES Beta Backer
ES Beta Backer
Posts: 23
Joined: Mon Dec 23, 2013 7:56 pm
Current Project: Canadian Simulator 2017
Favorite Gaming Platforms: GBA, DC, iOS, SNES, WS, 360, N64
Programming Language of Choice: C++, Lua
Location: Your VCR.

Pointers, seriously.

Post by corey__cakes »

My language of choice has always been C++. I've known it for awhile now, although there are still a few things I forget here and there. But there's always been one thing I've never understood: Pointers.

I know how to declare a pointer. I know what it does. I know that it "points to" the address of a variable in memory. I know how to point it. My frustration is not in the definition, but the purpose. Exactly what am I going to do with the address of a variable? Why would I ever need a pointer? It's frustrating not knowing what I can do with "the soul of C++".

Everything I've looked up on pointers has been about how to declare them and point them to something. Nothing about there uses in game development. I've noticed that when loading a bitmap or sfx in Allegro, you would always use a pointer. I'm guessing it has something to do with loading...??? I don't know. I feel my programming skill is lacking behind because of this.

I don't take classes on programming; I'm only in high school. I've learned C++ on my own with no one to learn with. That's why I turn to these forums.

Please help. And please don't tell me what a pointer does, because I already know. I just want to know how they are going to help me.
What do you call a cow with no legs?

Ground beef.
User avatar
Light-Dark
Dreamcast Developer
Dreamcast Developer
Posts: 307
Joined: Sun Mar 13, 2011 7:57 pm
Current Project: 2D RPG & NES Platformer
Favorite Gaming Platforms: NES,SNES,N64,Genesis,Dreamcast,PC,Xbox360
Programming Language of Choice: C/++
Location: Canada

Re: Pointers, seriously.

Post by Light-Dark »

One use of pointers is to save big time on memory. For example, let's say I have two Characters that use the same sprite sheet. I'd allocate the sprite sheet texture in VRAM and I'd simply give the character struct/class a pointer to that texture. I'd then have both characters' texture pointers point to the same texture loaded in VRAM thus saving myself from wasting memory by allocating two instances of the same texture.

Example:
// Generic texture allocator function
void Make_Texture_Blah(const char* fn,void* ptr,const int imagew,const int imageh);
// Generic sprite struct
typedef struct
{
 void* texture;
 int x,y;
}Sprite;

Sprite Twins[2];

... 
Make_Texture_Blah("FILENAME.whatever",Twins[0].texture,256,256); // Allocate the texture, then set the pointer "texture" to point to it
Twins[1].texture = Twins[0].texture; // They now point to the same texture
<tpw_rules> LightDark: java is a consequence of inverse moore's law: every 18 months, the average program will be twice as slow. therefore, computers always run at the same percevied speed. java's invention was a monumental step
Image
User avatar
dandymcgee
ES Beta Backer
ES Beta Backer
Posts: 4709
Joined: Tue Apr 29, 2008 3:24 pm
Current Project: https://github.com/dbechrd/RicoTech
Favorite Gaming Platforms: NES, Sega Genesis, PS2, PC
Programming Language of Choice: C
Location: San Francisco
Contact:

Re: Pointers, seriously.

Post by dandymcgee »

Light-Dark wrote:One use of pointers is to save big time on memory.
Yup, this. A pointer is simply a memory address, as you said. A memory address is (generally) a 32-bit integer, which takes up 4 bytes of memory. Duplicating any static* resource larger than 4 bytes in memory would be a waste, simply store a pointer to the shared resource instead. Just remember, if the resource is not static and you make a change to it, you are changing the only copy and every other pointer to the resource will reflect those changes when dereferenced.

* By static I mean unchanging, e.g. a texture or audio file, not the C++ "static" keyword.
Falco Girgis wrote:It is imperative that I can broadcast my narcissistic commit strings to the Twitter! Tweet Tweet, bitches! :twisted:
corey__cakes
ES Beta Backer
ES Beta Backer
Posts: 23
Joined: Mon Dec 23, 2013 7:56 pm
Current Project: Canadian Simulator 2017
Favorite Gaming Platforms: GBA, DC, iOS, SNES, WS, 360, N64
Programming Language of Choice: C++, Lua
Location: Your VCR.

Re: Pointers, seriously.

Post by corey__cakes »

So basically, you're making the texture for both sprites equal to each other, and through some magical hardware magic, it's better for saving memory?
What do you call a cow with no legs?

Ground beef.
User avatar
Light-Dark
Dreamcast Developer
Dreamcast Developer
Posts: 307
Joined: Sun Mar 13, 2011 7:57 pm
Current Project: 2D RPG & NES Platformer
Favorite Gaming Platforms: NES,SNES,N64,Genesis,Dreamcast,PC,Xbox360
Programming Language of Choice: C/++
Location: Canada

Re: Pointers, seriously.

Post by Light-Dark »

corey__cakes wrote:So basically, you're making the texture for both sprites equal to each other, and through some magical hardware magic, it's better for saving memory?
No you're making the pointers(variable holding a memory address) to the location (area in memory/memory address) the texture occupies in memory equal so they point to the same texture thus saving you from having to allocate the texture twice for each instance of the character. There is no magic involved man, it's indirect addressing yo' no big dealio.

EDIT:
Okay so maybe my example of how they save memory/time is not exactly clear. Alright so let's say you want to change a variable using a function. I'm sure your first reaction would be do to do something akin to this:
int add1(int number)
{
  return number+1;
}
int var1 = 0;

...
var1 = add1(var1);
Seems all good and dandy right? Wrong! you could do this a lot more efficiently. How you may ask? well my good sir pointers are the answer! You see the parameter int number is in itself a copy of what you pass to the function so the variable that we pass, var1, is duplicated into the parameter variable. The way around this duplication is to rewrite the function to return void and have the parameter be a pointer to an integer so instead of creating a copy of var2 we just pass a pointer to it so we can therefore indirectly edit the variable without any of the unnecessary copying and what-not that happens. Example:
int var1 = 0;
void add1(const int* ptr)
{
  *ptr = *ptr+1;
}
...
add1(&var1);
Both examples basically do the same thing, the key difference is that the second example that involves pointers does it A lot more efficiently. Some might say the second implementation looks "ugly" but honestly who gives a fuck if it's saving you performance. You may also say "well it's just an integer, it's no big deal not too much memory is wasted!" well then I ask you what happens when you have a class or struct jam packed full of strings,ints,floats and all sorts of large data types? Do you really want that to be temporarily copied? Of course not it's just a waste so instead you just use a nice 4-byte pointer to manipulate it without all the unnecessary copying.

I really hope I've gotten the point across as I am really tired at this point( no puns intended). If I'm not making any sense right now, I'm sorry, just google "what's the use of pointers" or "Why use pointers". I'm sure you'll find someone who can probably explain their advantage a lot better than I can. Goodnight sir.
<tpw_rules> LightDark: java is a consequence of inverse moore's law: every 18 months, the average program will be twice as slow. therefore, computers always run at the same percevied speed. java's invention was a monumental step
Image
User avatar
Falco Girgis
Elysian Shadows Team
Elysian Shadows Team
Posts: 10294
Joined: Thu May 20, 2004 2:04 pm
Current Project: Elysian Shadows
Favorite Gaming Platforms: Dreamcast, SNES, NES
Programming Language of Choice: C/++
Location: Studio Vorbis, AL
Contact:

Re: Pointers, seriously.

Post by Falco Girgis »

Dan wrote:Yup, this. A pointer is simply a memory address, as you said.
Y'know, I get really pissy when people define a pointer as "a memory address."

That is incorrect. It is not a memory address. It is a variable declared whose value CONTAINS a memory address. A pointer is an lvalue. A memory address is an rvalue.

It truly is confusing to newbies who are trying to learn the very subtle differences between operators such as '*' and '&' and pointers and references when you do not use precise definitions.
Benjamin100
ES Beta Backer
ES Beta Backer
Posts: 250
Joined: Tue Jul 19, 2011 9:37 pm

Re: Pointers, seriously.

Post by Benjamin100 »

The pointer issue confused me for a while too. I think you can find a post on this forum from me a while back asking about the same thing.
It still confuses me a bit, even though I basically know how and when to use it. I'm still not sure exactly how it works on a machine code level. Perhaps it would help to learn assembly. I have tried to learn assembly, but struggled in doing so.
User avatar
dandymcgee
ES Beta Backer
ES Beta Backer
Posts: 4709
Joined: Tue Apr 29, 2008 3:24 pm
Current Project: https://github.com/dbechrd/RicoTech
Favorite Gaming Platforms: NES, Sega Genesis, PS2, PC
Programming Language of Choice: C
Location: San Francisco
Contact:

Re: Pointers, seriously.

Post by dandymcgee »

Falco Girgis wrote:
Dan wrote:Yup, this. A pointer is simply a memory address, as you said.
Y'know, I get really pissy when people define a pointer as "a memory address."
Thank you for the correction. What I meant was "A pointer simply contains a memory address". Even that is a bit vague though.
As you said, a pointer is a variable, it's value is an integer which represents a location in memory.

Here's a simplified visualization of the state of memory when loading a sizable resource then copying vs. pointing:

Image

If "memory address" is still something you can't seem to wrap your head around, the following helped me quite a bit:
http://ideone.com/Ol326t
Falco Girgis wrote:It is imperative that I can broadcast my narcissistic commit strings to the Twitter! Tweet Tweet, bitches! :twisted:
User avatar
superLED
Chaos Rift Junior
Chaos Rift Junior
Posts: 303
Joined: Sun Nov 21, 2010 10:56 am
Current Project: Engine
Favorite Gaming Platforms: N64
Programming Language of Choice: C++, PHP
Location: Norway

Re: Pointers, seriously.

Post by superLED »

An easy example where pointers can be neat to have:

Code: Select all

void handleCollision(Rect *a) {
Rect newPos;

// do collision calculation stuff...

a->x = newPos->x;
a->y = newPos->y;
}
Now you can alter the variables itself, instead of having the function return the "newPos" struct/class and assign your player's rect to that.
Fillius
ES Beta Backer
ES Beta Backer
Posts: 11
Joined: Fri Feb 01, 2013 7:53 am

Re: Pointers, seriously.

Post by Fillius »

I might be rather late to the party, yet having read this just now i noticed some errors in the explanations and examples which could not be left uncommented and I thought i could point out some pitfalls, too.

The second example, at least imho, does not constitute a meaningful use of pointers at all:
Light-Dark wrote:

Code: Select all

int add1(int number)
{
  return number+1;
}
int var1 = 0;
 
...
var1 = add1(var1);
[...]

Code: Select all

int var1 = 0;
void add1(const int* ptr)
{
  *ptr = *ptr+1;
}
...
add1(&var1);
Both examples basically do the same thing, the key difference is that the second example that involves pointers does it A lot more efficiently.
The real key difference between them is that the first compiles and runs, whereas the second does not, which illustrates one of the major flaws of dealing with raw pointers directly: it can be tricky.
This

Code: Select all

const int* ptr
does not declare ptr to be a constant pointer, but a pointer to const, meaning the value pointed to can not be changed through it, which leads to a compiler error when this line

Code: Select all

*ptr = *ptr+1;
tries to assign to it.

I furthermore highly doubt the claim of efficiency, especially when the pointed to value is of type int, for on most systems the effort of copying a pointer is at least as costly as copying an integer and the extra indirection is most certainly more expensive than the (propably rvo-optimized away) second copy. In addition, the pointer access does prevent certain compiler optimizations, because it has to expect aliasing.

You do have somewhat of a point when claiming its worth the effort for bigger objects. I would, however, like to stress the fact that references are another and (in most cases) less error prone option for those cases:

Code: Select all

void do_something(big_object &obj)
{
	expensive_operation(obj);
	another_expensive_operation(obj);
}
Whilst a reference has to be initialized with an existing object, the pointer version does allow user code to pass in addresses pointing to non-existing, no longer existing or invalid objects(for instance a null pointer). In some use cases this might be desired, yet if there is no explicit need for it i would suggest using references(or well designed value types with move semantics, which could replace pointers in most of those use cases(and deal with everything neeeded(maybe pointers) internally without affecting and complicating user code). See also this excellent article: http://cpp-next.com/archive/2009/08/wan ... -by-value/)


One use case for which pointers really are indispensable is dealing with dynamic memory directly, for there is simply no other way to handle an address returned from new or malloc/calloc/realloc/or_whatever_c_functions_eluded_me_in_my_sleep_deprived_state. In this case all bets are off and you will have to use a pointer and excercise extra caution, because you are now forced to deal with ownership issues. Every resource, once aquired, must be released again, exactly once. To use the example already present in this thread:

Code: Select all

// Generic texture allocator function
void Make_Texture_Blah(const char* fn,void* ptr,const int imagew,const int imageh); //with this signature, the function takes a copy of the pointer, therefore will not change the one passed in and the texture is lost ;_;. It should take either a void** or a void*& or simply return the pointer
// Generic sprite struct
typedef struct
{
 void* texture;
 int x,y;
}Sprite;
 
Sprite Twins[2];
 
...
Make_Texture_Blah("FILENAME.whatever",Twins[0].texture,256,256); // Allocate the texture, then set the pointer "texture" to point to it
Twins[1].texture = Twins[0].texture; // They now point to the same texture
In this code, the call to Make_Texture_Blah allocates(aquires) a new texture and stores its address(the only available handle to this portion of memory) in the texture pointer of Twins[0]. Since Twins[1] is supposed to use the same, unchanged texture it is reasonable to assign its pointer to the same address. This avoids the propably significant waste of memory a copy would incur, yet not without a price: it intruduces extra complexity because it is no longer clear which object(Twins[0] or Twins[1] or something completly different) "owns" the real texture, which object is both responsible and authorized to delete(release) it.
There are now 2 different handles to the same texture, and as long as one of them is still in use, the other may not delete it. In this example, if we were talking about C code, this would not be problem at all because Twins[0] and Twins[1] have (almost )the same lifetime and you could simply call a Free_Texture_Blah(void*) function before leaving the current scope, however, C++ does not allow your life to be that easy, assume this:

Code: Select all

Sprite Twins[2];
Make_Texture_Blah("FILENAME.whatever",Twins[0].texture,256,256); // Allocate the texture, then set the pointer "texture" to point to it
Twins[1].texture = Twins[0].texture; // They now point to the same texture
...
some_unknown_cpp_fun(); //maybe from a closed source library
...
Free_Texture_Blah(Twins[0]);
For all we know, some_unknown_cpp_fun could be this:

Code: Select all

void some_unknown_cpp_fun()
{
	throw std::runtime_error("got you");
}
that is, it might throw an exception and prevent the code from ever reaching the Free_Texture_Blah call. One could try avoiding this by wrapping all unknown code in try{}catch(...) blocks and do the necessary cleanup following the catch, which would overly complicate everything and lead to lots of code duplication, which is why the usual way of dealing with this is utilizing the fact that destructors of completly constructed objects are guaranteed to run, even in the face of exceptions, the RAII Idiom(http://www.stroustrup.com/bs_faq2.html#finally). In short, this idiom binds every resource to an object, allocating it in the constructor and releasing it in the destructor. For instance the code could be changed to:

Code: Select all

typedef struct
{
 void* texture;
 int x,y;
}Sprite;
 
struct Texture
{
	void *ptr;

	Texture(const char *fn, int w, int h)
	{
		Make_Texture_Blah(fn,ptr,w,h); // Allocate the texture, then set the pointer "ptr" to point to it
	}

	~Texture()
	{
		Free_Texture_Blah(ptr);
	}
}
...
Texture tex("FILENAME.whatever",256,256);
Sprite Twins[2];
Twins[0].texture = tex.ptr;
Twins[1].texture = tex.ptr;
// They now point to the same texture
This solves the immediate problem described above, yet has some of its own: It wont work if it is copied, assigned to, its pointer passed to some object surviving the tex Object itself etc. etc.., which is why some clever people defined the Rule of Three(http://en.wikipedia.org/wiki/Rule_of_th ... ramming%29), which had to be extended to the Rule of Five due to move semantics. Sounds complicated? Thats propably because it is.
Fortunately this is such a common use that "smart pointers" were intruduced in C++11, classes that work almost exactly like normal pointers, only they deal with ownership issues internally: std::unique_ptr, std::shared_ptr and std::weak_ptr. I highly recommend reading up on those.
(See also: http://flamingdangerzone.com/cxx11/2012 ... -zero.html, http://akrzemi1.wordpress.com/2013/07/1 ... t-feature/, http://isocpp.org/blog/2013/07/cs-best- ... krzemieski)

Granted, this is less of a problem with the pointer itself (but rather of dynamic resource management), yet the question was regarding the purpose/usage of pointers and considering that dynamic memory management is one of the major uses i deemed it worth mentioning.

I am not claiming (raw) pointers do not have their uses(i did not mention runtime polymorphism for instance), yet the number of those is rather small and diminishing. In many places where (raw) pointers were traditionally the best option in C code, modern C++ offers better(read: safer and at least as efficient) alternatives worth considering(and teaching to newbies, who are much more likely to run into errors and frustration when using pointers they could have avoided).

I am sorry for the wall of text, hope i managed to avoid offending anyone and would also recommend a reading of this article: http://meetingcpp.com/index.php/br/item ... inter.html ;-)
D-e-X
Chaos Rift Newbie
Chaos Rift Newbie
Posts: 39
Joined: Tue Dec 28, 2010 6:49 pm

Re: Pointers, seriously.

Post by D-e-X »

So the usefulness of the pointer might still be a bit unclear for newcomers, even when the concept has been understood. Basically, they just let you re-use something that is at wherever it's "pointing to" already and being completely negligible as far as resources go. It's really handy for when you're dealing with huge data-types, amongst a lot of other things ofc, but for the sake of ease let's just deal with this one example.

Say you have a complete 3D world object, it contains a truckload of information, and by declaring a pointer to it, this horny information just wanting to be used by something else, can be used without creating a completely new copy of it.

Now that's useful! Plus, depending on the context of the pointer, they're re-assignable and you can perform arithmetic on them, in difference to references (there's no "ref arithmetic" in the sense of pointers). You can also not take the address of the reference, nor set the reference to NULL. Pointers also offer multiple levels of indirection (e.g., a pointer pointing to a pointer pointing to some data) while references do not. I guess the important distinction to make here when thinking about pointers and references is that references are just "nicknames" or alternatives to the original data, while pointers are just variables holding some memory address. These things might confuse you more or less about pointers, either way, my example should be easily digested.
I remember when I used to be into nostalgia.
User avatar
Light-Dark
Dreamcast Developer
Dreamcast Developer
Posts: 307
Joined: Sun Mar 13, 2011 7:57 pm
Current Project: 2D RPG & NES Platformer
Favorite Gaming Platforms: NES,SNES,N64,Genesis,Dreamcast,PC,Xbox360
Programming Language of Choice: C/++
Location: Canada

Re: Pointers, seriously.

Post by Light-Dark »

Fillius wrote: I am sorry for the wall of text, hope i managed to avoid offending anyone and would also recommend a reading of this article: http://meetingcpp.com/index.php/br/item ... inter.html ;-)
Hey man it's cool, you have enlightened me and you have not only corrected my examples but made them far better :lol:! Thanks!
<tpw_rules> LightDark: java is a consequence of inverse moore's law: every 18 months, the average program will be twice as slow. therefore, computers always run at the same percevied speed. java's invention was a monumental step
Image
User avatar
Falco Girgis
Elysian Shadows Team
Elysian Shadows Team
Posts: 10294
Joined: Thu May 20, 2004 2:04 pm
Current Project: Elysian Shadows
Favorite Gaming Platforms: Dreamcast, SNES, NES
Programming Language of Choice: C/++
Location: Studio Vorbis, AL
Contact:

Re: Pointers, seriously.

Post by Falco Girgis »

Fillius, I am a fan of your walls of text. :D
Post Reply