Sign in to follow this  
Jettoz

Pointers, when are they used?

Recommended Posts

Jettoz    288
Hello everyone, I'm doing some reading on pointers and did a small test to see what a pointer can do so far. (I'm still new to learning Pointers)
#include <iostream>

using namespace std;

int main ()
{
	// Vars
	int Number, *NumberPtr;

	// Set Vars
	Number = 100;
	NumberPtr = &Number;

	// Print Number & NumberPtr
	cout << Number; // Displays Number Value
	cout << endl;
	cout << NumberPtr; // Number Address in Memory (HEX)
	cout << endl;
	cout << &Number; // Number Address in Memory (HEX)
	cout << endl;
	cout << *NumberPtr; // Value of NumberPtr

	cin.get();

	return 0;
}



Now all I understand is I made a variable Number with the value 100 and a Pointer NumberPtr which store the address of Number (Hex) and it's value. So I can print out Number which is 100 and than print out it's Memory from NumberPtr which is 0012FF60 and than I printed &Number which also gives it's Memory address just like the pointer did (Which it should) 0012FF60. Than I printed out *NumberPtr which gives that value of Number. Now my question here is what is the real point of doing this? When are pointers really used for example if I made a Console Text Game where would pointers come in use? Or if I made a 2D Pac Man game using an API why would pointers be used? I understand about Hex codes however because I use to do some 'hacking' on single player games before but I'm still confused on why a pointer is used even though I some what understand the basics of what it does. Thanks for any help you can provide!

Share this post


Link to post
Share on other sites
Crypter    748
-Pointers are smaller then objects (They are useually the size of an integer),
so they are much more effeciant when copying

Deep copies accure when an entire object is copied to another.
Shallow copy only copies its 4byte address--much more effeciant.

-Shared objects. Pointers are the only way of sharing an object

-Dynamic memory. You have to use pointers when allocating/deallocating memory

There are many more reasons then this.

It is much easier to pass a 4byte address then a larger object on the
stack when passing parameters.

When programming low level, you will find out pointers are used
virtually everywhere.

Share this post


Link to post
Share on other sites
Telastyn    3777
I need to really document this somewhere...


Generally, pointers are to data what links are to websites.

A link isn't a website, but it tells you where it is. It's far smaller than a website. The website itself is only one instance. If you copy the website, then if it changes the copy doesn't get those changes. A link though always points to the 'current' website. Of course if the website goes down, the link is broken and badness occurs.


Thus, a pointer behaves like a web link. It's not data, but tells you where it is. You actually have to follow (dereference) it to get the data. If it's wrong (a null pointer, typo'd link) stuff will break. If the data is gone (deleted data, webserver goes down) stuff will break.


So, think to yourself when you would pass around web links rather than copying an entire website. Think when you'd place links in a webpage rather than copying a(n) image/movie/text.

[edit: and this isn't so important now, but there are better ways than pointers to do what pointers do in 98% of modern C++]

Share this post


Link to post
Share on other sites
Kaze    948
the real use of pointer is dynamic memory allocation
instead of setting a pointer to &another_variable you can create a new area of memory with the new keyword, you can create primitive types like ints, objects or arrays of either and set the size at runtime

also sometime its usefully to give two different areas of code access to a single variable or object

Share this post


Link to post
Share on other sites
Kaze    948
Quote:
Original post by Telastyn
I need to really document this somewhere...

that or someone needs to make a gdnet article on "practical uses for pointers" for linking to

Share this post


Link to post
Share on other sites
gunning    749
Quote:
Original post by Telastyn
snip


That's a great description! ++

OP-

The misuse of pointers is one of the main causes (if not the main cause) of program crashes. Not trying to scare you, but it's something you should be aware of. I suggest you learn the difference between pass-by-pointer and pass-by-reference early on because it'll save you some debugging headaches later. Basically unless your data is dynamic memory, pass-by-reference is the safer way to go, and has the benefit of being a lot more comfortable to use too.

Share this post


Link to post
Share on other sites
Jettoz    288
Alright thanks everyone, I'll keep reading more about Pointers and check online for some examples of Pointers being used. Unless I'm wrong it wouldn't be that big of problem to make a Text RPG without using pointers just for learning for now. I've done one Text RPG so far and didn't use any Pointers so I'm going to make another one and use Pointers to help me learn them later down the road.

Share this post


Link to post
Share on other sites
Crypter    748
Quote:

I've done one Text RPG so far and didn't use any Pointers

A string, as being an array of characters, is essentially a pointer:

char str[]="Hello!";

// *str == 'H'; str points to first char in string

...Just another place pointers are used[smile]

As being a text RPG Im sure theres pointers..

Share this post


Link to post
Share on other sites
Koobazaur    1264
I am working on a program right now which will find pointers invaluable. Let me illustrate.

In my world I am going to have all sorts of 3D objects - crates, chairs lamps etc. Now, you see, each object will have to have a 3D mesh, textures, normal maps, light maps etc. that define what the object looks like. Now considering that I may have multiple instances of a single object (i.e. 50 crates on one map), each object will have to have the same mesh and textures. So imagine copying fifty times - that's a LOT of memeory usage!
But instead of each object having its own mesh, it will merely have a POINTER to a mesh. This way, each of the 50 crates would point to the exact same mesh instead of creating copies of it.

And thus, pointers have cut my memory usage 50 times (not exactly as pointers themselves take memory, but that memory is neglibile compared to how much memory the meshes take themselves).

Share this post


Link to post
Share on other sites
Jettoz    288
Wow thanks, now I understand the reason for Pointers! Right now because I'm still using Console for my text games pointers are not a big issue for memory until I get into Graphics. Thanks again everyone!

Share this post


Link to post
Share on other sites
DevFred    840
Quote:
Original post by Crypter
A string, as being an array of characters

std::string is a string
char[] is an array of characters

Share this post


Link to post
Share on other sites
Zahlman    1682
People commonly say things like "the *real* purpose of pointers is..." and then cite one of their possible uses. The thing is, there are several things they can be used for, and none is really dominant. But more to the point, in modern C++, we have tools to avoid interacting with them directly. And you *shouldn't* normally interact with them directly, because you get into thinking at a lower level than is necessary.

The natural starting point for discussion is the reference. I mean that in an abstract, non-C++-specific way. The idea is, we want to have some kind of variable that doesn't directly store a value (well, not one that we directly *care about*, anyway), but instead can "stand in" for another variable, i.e. alias it. This way, we could share a value between two different data structures, or let called functions affect local variables, by passing a reference instead. (Note the subtle distinction between passing *a* reference and passing *by* reference; the former implies that we're responsible for creating the reference, whereas the latter is more commonly seen in discussion of how the language is implemented.)

In some languages, objects are actually represented by references to "hidden" data structures that you don't actually access directly. For example, Java treats values of object type (i.e. everything except primitives like 'int') in this way, and Python treats everything this way (even simple numbers). These references get passed around as they are, which can allow called functions to modify the variables of their callers. (In Python, however, many built-in types are fundamentally non-modifiable - "immutable".) In Java, when you pass a primitive value, it gets copied across, so the called function *cannot* modify the caller's variable of a primitive type, even though it could with an object - this is because it's not actually the variable that's modified (since the variable "of an object type" actually holds a reference), but the hidden data. For this reason, it is commonly asserted that Java is a pass-by-value language; it doesn't pass by reference, but it instead *passes references* by value. Python, OTOH, could be implemented either way (at least this far), and you'd never have any way to find out which (and you shouldn't care, anyway - it does what it is supposed to do and that's what matters).




Which brings us to C++. C++ provides variables of reference type. An 'int&' is a "reference-to-int". There are a few things in the above description of references that are unspecified, i.e. could be done in different ways:

- Whether or not there is a "null". In Java, object-type variables can also be set to null, meaning that they don't actually refer to an object, but instead to a magical stand-in "there isn't anything here right now". The variable becomes a placeholder. If you try to use the object while it's null, you'll (except for very trivial uses) get a NullPointerException. Hmm - pointer - implementation details leaking through? :s We'll worry about that later, though. In Python, this concept is absent: an object is always an object and there are no such placeholders. If you think it would be useful to have one, then you need to create a workaround. However, it so happens that creating a workaround is often the best solution *anyway* from a software design perspective, because with a bit of cleverness, you can avoid lots of special-case logic to deal with those placeholders.

For example, in Java you might have a String type variable that is set to null. But there is already a value for a String that does a pretty good job of representing "absence of a string": the empty string, i.e. "". If we set the variable to that, instead, then trying to get its length, for example, won't throw the exception, but instead return 0 - a reasonably-expectable value. In Python, of course, you don't have the option of null, so you just use "". If for some reason you actually need to distinguish "this string is 0 characters long" from "this string doesn't actually exist at all", then you will need to make some kind of wrapper - but you should probably rethink your design on a bigger scale first!

C++ takes the Python approach, and does not provide a null for its references. It does for pointers, which is one reason they are sometimes useful.

- Whether or not the reference can be "rebound". That is, whether we are allowed to pick up a variable of reference type and cause it to start referring to another one.

In both Java and Python, this works. After all, the "variable of reference type" is pretending to hold the actual object, and it would be quite annoying if all our variables were 'const'. ;) In fact, Python gets around a lot of limitations by implicitly rebinding references behind the scenes. For example, objects of 'int' type are actually immutable in Python - the value in the hidden data can't be changed from Python. So when you write 'x += 5', what it actually does is to translate that into 'x = x + 5', perform the addition (creating a brand new 'int' hidden-data structure), and then rebind x to point to the result. (The old hidden-data structure will then get garbage-collected later.)

However, C++ references *do not* do this. There is a subtle distinction: C++ references are pretending to be *other names for* the actual referred-to thing (not always an object, i.e. instance of a class type ;) ), rather than the things themselves. Therefore, when you "assign to" a variable of reference type, you actually assign to the referred-to thing. There is no legal way to cause the reference to re-bind to another thing, and any attempt to hack around this (based on your knowledge of how the compiler is implementing references) invokes undefined behaviour. I.e., even if you think you know perfectly what is going on, it could *still* do anything, because the compiler's optimizer is specifically allowed to assume that you are not doing anything like this, because it's not allowed for you.




As a consequence the above design decisions, C++ references *must be initialized*. The language won't let you get away with an uninitialized reference, because (a) since there is no "null", the reference has to refer to *something*, and at this point the compiler doesn't know what to refer to; and (b) you can't just make the decision later, because that would require binding the uninitialized reference, and binding is simply a special case of rebinding, which is not allowed.

This is a good thing. It forces you to initialize at least some of your variables, and initializing variables is good because they are never in an invalid state (this makes it easier to reason about program correctness). It also forces you to take advantage of the C++ language feature whereby variables don't have to be declared at the top of their scope. That means you can find out what is necessary in order to initialize the reference first, and then go ahead and initialize it.

In fact, those ideas are applicable to variables not of reference type, too, so let's try them out on your original code :)


int main ()
{
int Number = 100;
int* NumberPtr = &Number;


The rest has some other style issues, but we can worry about those some other time. For now, the point is to illustrate how the variables are initialized, and see the benefits:

- The code is shortened, and we avoid redundancy in mentioning the variable names. More to the point, we don't have pairs of statements that have to be kept in sync (declaration and initial-assignment): if we decide to rename one of the variables, there's only one line of code that changes. This is the Don't Repeat Yourself principle on a micro scale.
- There is no point in time at which the variable contents are unknown. Even though there was "obviously" nothing done with the unknown contents in the previous code, it is vastly more obvious now, because the situation simply never occurs.
- In order to make the initialization work, we are forced to highlight the dependancy between NumberPtr and Number by initializing Number first. Without initialization, we could have put the variable declarations in the other order (BTW, declaring variables of different type in the same line like that is seen as pretty sketchy by most C++ folk - it works because the C designers thought it would be convenient, but it tends to lead to confusion) and the reader of the code would have been left wondering about the lack of parallelism.




I'll just sum up about references before moving on to the next major concept. There's only one more thing to point out, really, which is how references are used *practically* in C++. Well, most of the time, they are used as function parameters. They *can* be used as data members of an object, but you have to be very careful that way, because (a) they *must* be initialized in *all* constructors *from the initialization list* (assigning to members inside a constructor body is *still* assignment and not really initialization), and (b) the default copy-constructor and assignment operator won't work, and you'll probably need to think really hard about how these should be handled (often, the correct handling is to disallow those operations completely).

But you probably won't have to worry about such things for a while. Instead, here's a more practical use: creating a local variable of a reference type in order to avoid repeated "lookup" operations within a complex data structure.

In C, we used to do this kind of thing with pointers. Naturally, doing things directly with pointers is tricky, and writing code this way was error-prone - unfortunate, since the goal is to avoid errors by avoiding copy-pasted code (which of course, tends to get messed up when it's maintained, due to one of the copies not being altered properly). It also led to people creating structures that pointed all over the place when it was possible to just use local data, actually making performance worse. (I still see this a lot in C++, unfortunately, because old bad habits are hard to break.) The idea there was to make it easier to get the syntax right by making *everything* a pointer, so you wouldn't have to think about which things were pointers and which weren't. :s

Of course, the reason you can't just create a *value* from the looked-up data member is that you want to change the data member, not simply your local variable. In other words, we want the variable to act as another name for this deeply-nested data member... hmm, "another name"... sounds like a job for a reference to me!

Let's see the technique in action:


void wibble(Thing& foo) {
// ORIGINAL - bad; repeats the lookup procedure, which makes the code harder
// to maintain and longer than it should be
// foo.bar.baz.x += 1;
// foo.bar.baz.y *= 2;
// foo.bar.baz.z %= 3;

// C-STYLE, without changing the data structure - tricky and "not clean",
// i.e. things are not symmetric. Remember, in C we can't pass a "Thing&", so
// we would normally pass a Thing* instead, so we have to dereference that...
// Member* m = &(foo->bar.baz); <-- eww!
// m->x += 1;
// m->y *= 2;
// m->z %= 3;

// C-STYLE, assuming changes to data structure - symmetrical, but we end up
// adding huge amounts of code elsewhere to dynamically allocate and
// deallocate the 'bar' and 'baz' members and make sure everything is
// consistent. Plus we add extra data and spread our struct around all over
// memory. Horrible!
// Member* m = foo->bar->baz;
// where 'baz' is now of type Member* instead of Member, and similarly for
// foo and bar. Also, the function would again take a Thing* parameter.
// m->x += 1;
// m->y *= 2;
// m->z %= 3;

// GOOD C++ STYLE, using a reference. (Of course, better C++ *design* might
// involve giving Member a member function that makes the changes and then
// just calling that ;) )
Member& m = foo.bar.baz;
m.x += 1;
m.y *= 2;
m.z %= 3; // everything is just .'s again, and the original problem is solved.
}

// When we *call* wibble(), we can use a variable of type Thing, rather than
// Thing& - and this is what we normally do (although a Thing& will also work,
// exactly as you'd expect). The compiler simply matches up the types, says
// "I know how to convert a Thing to a Thing&, and that conversion is legal",
// and everything runs smoothly. The net effect is that we can pretend to pass
// *by* reference when we really pass *a* reference, by relying on an implicit
// conversion.
int main() {
Thing t;
wibble(t);
// t.bar.baz.x has now been incremented, etc. The changes done in wibble()
// are "seen" at this point.
}



Of course, you're not required to understand the "C-style" techniques at this point in the lesson. After all, the whole point is that we *don't* want to use them ;) But I put them in for comparison.

Share this post


Link to post
Share on other sites
Crypter    748
Quote:

std::string is a string
char[] is an array of characters

std::string encapsulates the array of characters as an ADT.

Of course, in C++, std::string is the better choice for alot
of reasons[smile]

Share this post


Link to post
Share on other sites
trick    152
Just a quick note...I had a program once that dealt with a large amount of data. I wasn't using pointers to begin with, and the program actually crashed due to running out of memory. I'm sure there could have been other fixes for what I was doing, but as it was it used a function that called itself, and passed an object as an argument. Without using pointers, the object was copied each time, and since the object contained a LOT of data, the program very quickly used all available memory (and still needed more).

Final State: pointers! instead of passing massive amounts of data, multiple times (nested), there was only a 4-byte value passed each time.


This program was not graphics-heavy, so pointers can be dramatically helpful even in a non-graphics program (depending on what the program does, and how it does it of course...).

Share this post


Link to post
Share on other sites
MrRage    127
It would be good idea to make mention of smart pointers. These pointers mange their own instances and garbage collect after they leave scope. Knowing which one to use and when takes a little bit of time but once you get the hang of it, you start to gain that time back by not having to debug as much or write more code than you need to.

I was reading this at work today, highly recommend it to people wanting to know more about smart pointers.
http://www.codeproject.com/vcpp/stl/boostsmartptr.asp

Another good class to have a look at is the boost::array class. It’s a light wrapper on top of an array structure. Arrays are a very common application for pointers.

http://www.boost.org/doc/html/array.html

Share this post


Link to post
Share on other sites
dashurc    236
Useless textbook examples often confuse new programmers about what pointers are.

I think you get the gist of WHAT they are, but you are asking about why you should use them.

Essentially, pointers store a memory address. That's it. They can be used to allocate/deallocate memory and therefore store the address of the allocation.

Since you know this stuff, the first thing I would advise you to read up on would be passing function parameters by reference VS passing function parameters by value (any C++ textbook should suffice). This should give you a little bit more insight into how and (some of the reasons) why we use pointers in C++. Something to keep in mind is that languages such as Java and C# still behave the same way, however they do all the "pointer work" behind the scenes.

As for textbook examples... rarely are they useful in demonstrating why we do anything, but often they are good enough to explain how. Keep on reading and you should pick up on things fast. Just remember that pointers are usually what seperate a lot of would be programmers from the real programmers, and it's usually from a conceptual standpoint. When you understand them, you'll understand other languages that don't use explicit pointers better. Take your time, and know that you're probably already slightly ahead of the game.

Share this post


Link to post
Share on other sites
Glak    315
trick, what you are describing is a situation in which you should be using references rather than pointers.

Share this post


Link to post
Share on other sites
My post is a response to this post - not a response to the OP (Zahlman's post is a must read). You can view it as an enhancement to Glak's answer.

Quote:
Original post by trick
Just a quick note...I had a program once that dealt with a large amount of data. I wasn't using pointers to begin with, and the program actually crashed due to running out of memory. I'm sure there could have been other fixes for what I was doing, but as it was it used a function that called itself, and passed an object as an argument. Without using pointers, the object was copied each time, and since the object contained a LOT of data, the program very quickly used all available memory (and still needed more).

Final State: pointers! instead of passing massive amounts of data, multiple times (nested), there was only a 4-byte value passed each time.

This program was not graphics-heavy, so pointers can be dramatically helpful even in a non-graphics program (depending on what the program does, and how it does it of course...).


It's more likely because you exhausted the stack (stack overflow exception).

When you call a function, the parameters of this functions are (most of the time) stored on the stack.

The stack is also used to "allocate" automatic storage duration variables (variables that will destroy themselves when you go out of scope) and a bunch of other information (return address of the caller, and so on).

  • If you use a function signature such as:
    void function(Class obj1, Class obj2);

    Then you will create copies of obj1 and obj2 on the stack. If Class is farily big, you'll run in trouble very quickly.


  • If your function declaration looks like:
    void function(Class *pobj1, Class *pobj2)

    Then you will store copies of pobj1 and pobj2 on the stack as well. But in this cases, these two variables are pointers, and don't take much memory. So it appear to be a good solution to the problem above, but both pobj1 and pobj2 can now be NULL (so you must check that in your called code) and you have the possibility to modify the underlying objects). But it's not the best solution.


  • If your function declaration looks like
    void function(Class& obj1, Class& obj2)

    You will create copies of references to obj1 and obj2 on the stack. These references are (most of the time) implemented as pointer (internally; but you don't have to deal with such kind of detail), and as a consequence it takes the same stack space than the solution above. The good thing is that references are not supposed to be NULL - so you can remove the checks that you had to add in the pointer version. The bad thing is that you can still modify both obj1 and obj2 inadvertedly.


  • So our next solution is to consider a correct use of the const keyword:
    void function(const Class& obj1, const Class& obj2)
    Got it! These are references, so they don't take much stack space, and const references to object makes these objects immutable (unless you use the mutable keyword internally, but that's kind of rare). From a caller point of view, this is very similar to the first (bad) solution - it behaves in the same way (minus some very tiny details).

What I want to say is that instead of using pointers in this case, you should have used const references. They are safer, less error prone, and far easier to deal with.

Of coursse, you can also play with constant pointer to constant objects. The syntax would be
void function(const Class const* obj1, const Class const* obj2)

I'm pretty sure you prefer the const reference version [smile].

The rule of thumb is: whenever you want oto use a pointer, try to see if a reference is not a better solution.

Regards,

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this