Pointer for C++ dummies (like me)
by Berserk · in Technical Issues · 08/18/2005 (12:25 am) · 18 replies
Who's afraid about pointers? Me, in example.
What's the right sintax to use? When do I have to use &, when *, when ->, and when combinations such as **, object.member->pointer, something->(*pointer) and so on?
If you are experienced C++ developer post here your tips&tricks about how to recognize what sintax to use on a certain situation.
If you are instead a C++ dummy, keep an eye on this thread to learn the most tricky side of C/C++.
(trust me, OOP is nothing in comparision with pointers. Classes, object and so on are plain like oil once mastered the pointers).
Thanks in advance to anyone will write here his thoughts about this and hopefully I'll finally learn these DxxxxD pointers.
Bye, Thc.
.
What's the right sintax to use? When do I have to use &, when *, when ->, and when combinations such as **, object.member->pointer, something->(*pointer) and so on?
If you are experienced C++ developer post here your tips&tricks about how to recognize what sintax to use on a certain situation.
If you are instead a C++ dummy, keep an eye on this thread to learn the most tricky side of C/C++.
(trust me, OOP is nothing in comparision with pointers. Classes, object and so on are plain like oil once mastered the pointers).
Thanks in advance to anyone will write here his thoughts about this and hopefully I'll finally learn these DxxxxD pointers.
Bye, Thc.
.
About the author
#2
Yeah, pointers are my undoing as well, but from my experience, this is what I've come to understand about them:
Objects, when created as pointers, are created on the heap instead of the stack. This makes it so you don't have to use the C calls for memory management (malloc and free), and instead, create your object like so:
The only time you have to use the pointer prefix is when declaring a pointer, as seen above. Afterward, you can just reference the variable.
Pointers are "passed by reference" (aka "reference parameters") when you send them to a function or assign them to another variable. Because the pointer is a memory address, changing it in one location changes it EVERYWHERE.
For example:
This would type "OMG" to the console. Even though you called a function, you passed "obj" by reference. Changing obj2 changes obj because obj2 IS obj.
This compares to the standard "value parameter":
This will echo out 0, because changing it did not affect myint because it is passed by value. So, how do we pass by reference on a value parameter? Easy:
This will change myint to 4. Why? The ampersand means "address of". You are literally asking for the "address of an integer", thereby making aint equivalent to myint.
This can be expressed in pointers like so:
You can make one object a pointer to another by setting a pointer equal to the address of the object. This is accomplished through the use of the ampersand. We could have easily done this, too:
This means myobj2 has become myobj.
So, when to use "->"? -> is called the "pointer dereference operator". It accesses the members of a pointer. This is the same thing as using dot (".") on a non-pointer.
** pointers are pointers-to-pointers. While I've had absolutely no experience with these, from what I know, they are used for pointer arrays (as in a pointer to an array of pointers).
I hope that helped some. I invite the more advanced members to clear up what I have here!
08/18/2005 (1:27 am)
I'm not a C++ expert ... I can read code and hack it up, but I don't think I've ever completed a complex project in C++ from scratch.Yeah, pointers are my undoing as well, but from my experience, this is what I've come to understand about them:
Objects, when created as pointers, are created on the heap instead of the stack. This makes it so you don't have to use the C calls for memory management (malloc and free), and instead, create your object like so:
// Create the object ("malloc")
MyObject *myobj = new MyObject();
// Delete the object ("free")
delete myobj;The only time you have to use the pointer prefix is when declaring a pointer, as seen above. Afterward, you can just reference the variable.
Pointers are "passed by reference" (aka "reference parameters") when you send them to a function or assign them to another variable. Because the pointer is a memory address, changing it in one location changes it EVERYWHERE.
For example:
MyObject *obj = new MyObject();
DoStuffToMyObject(obj);
void DoStuffToMyObject(MyObject *obj2) {
obj2->Text = "OMG";
}
cout << obj->Text;This would type "OMG" to the console. Even though you called a function, you passed "obj" by reference. Changing obj2 changes obj because obj2 IS obj.
This compares to the standard "value parameter":
int myint = 0;
DoStuff(myint);
void DoStuff(int aint) {
aint = 3;
}
cout << myint;This will echo out 0, because changing it did not affect myint because it is passed by value. So, how do we pass by reference on a value parameter? Easy:
int myint = 0;
DoStuff(myint);
void DoStuff(int &aint) {
aint = 4;
}
cout << myint;This will change myint to 4. Why? The ampersand means "address of". You are literally asking for the "address of an integer", thereby making aint equivalent to myint.
This can be expressed in pointers like so:
MyObject myobj;
DoStuff(&myobj);
void DoStuff(MyObject *aobj) {
aobj->CallAFunc();
}You can make one object a pointer to another by setting a pointer equal to the address of the object. This is accomplished through the use of the ampersand. We could have easily done this, too:
MyObject myobj; MyObject *myobj2; myobj2 = &myobj;
This means myobj2 has become myobj.
So, when to use "->"? -> is called the "pointer dereference operator". It accesses the members of a pointer. This is the same thing as using dot (".") on a non-pointer.
** pointers are pointers-to-pointers. While I've had absolutely no experience with these, from what I know, they are used for pointer arrays (as in a pointer to an array of pointers).
I hope that helped some. I invite the more advanced members to clear up what I have here!
#3
someone correct me if I'm wrong, but as far as i understand, unless you are using constructor arguments you do not need the parenthesis following the 'new' command, just like 'delete'.
its important to understand that the parameter this function takes is separate from pointers and other datatypes. this is a reference object type. a reference object is basically an alias for another variable. it can be used the same way as pointers so for this situation a pointer would(and should) be used. references should probably be reserved for cases where you only want to access data while avoiding a constructor call. if the point of a function is to modify its parameter, a regular pointer should probably be used. but this is getting away from pointers....
/////////////////////////////////////pointers///////////////////////////////
ok starting with the basics:
int*a; this is a pointer declaration.
this says that 'a' is a pointer variable which will hold the address of an integer.
int*a;
int b;
b=5;
a=&b;
this sequence creates two variables, an int pointer (a), and a regular int (b). b is set to the value 5 and a is set to the address of b. this is the most basic usage of a pointer so understanding the above code is crucial to understanding pointers in general.
cout< cout<<*a<<"\n";
given the previous code, these two lines will both print '5' to the screen. notice the * in front of 'a'. this is the operator for "dereferencing" a pointer, which means we're accessing the data the pointer points to. so theres actually 2 instances where * operator is used, once for declaring a pointer, and again for dereferencing a pointer.
one more thing, pointers can be cascaded as follows:
int *a;
int **b;
int c;
c=5;
a=&c;
b=&a;
this sequence creates 3 variables, an int(c), an int pointer(a), and a pointer to an int pointer(b). dont let this syntax intimidate you, stare at it for a second and realize its as simple as 1-2-3. =)
cout<
cout<<*a<<"\n"; //prints 5
cout<<**b<<"\n"; //prints 5 as well!
08/18/2005 (9:56 am)
A couple of things about Sam's post:MyObject *myobj = new MyObject();
// Delete the object ("free")
delete myobj;someone correct me if I'm wrong, but as far as i understand, unless you are using constructor arguments you do not need the parenthesis following the 'new' command, just like 'delete'.
DoStuff(myint);
void DoStuff(int &aint)
{ aint = 4;}its important to understand that the parameter this function takes is separate from pointers and other datatypes. this is a reference object type. a reference object is basically an alias for another variable. it can be used the same way as pointers so for this situation a pointer would(and should) be used. references should probably be reserved for cases where you only want to access data while avoiding a constructor call. if the point of a function is to modify its parameter, a regular pointer should probably be used. but this is getting away from pointers....
/////////////////////////////////////pointers///////////////////////////////
ok starting with the basics:
int*a; this is a pointer declaration.
this says that 'a' is a pointer variable which will hold the address of an integer.
int*a;
int b;
b=5;
a=&b;
this sequence creates two variables, an int pointer (a), and a regular int (b). b is set to the value 5 and a is set to the address of b. this is the most basic usage of a pointer so understanding the above code is crucial to understanding pointers in general.
cout< cout<<*a<<"\n";
given the previous code, these two lines will both print '5' to the screen. notice the * in front of 'a'. this is the operator for "dereferencing" a pointer, which means we're accessing the data the pointer points to. so theres actually 2 instances where * operator is used, once for declaring a pointer, and again for dereferencing a pointer.
one more thing, pointers can be cascaded as follows:
int *a;
int **b;
int c;
c=5;
a=&c;
b=&a;
this sequence creates 3 variables, an int(c), an int pointer(a), and a pointer to an int pointer(b). dont let this syntax intimidate you, stare at it for a second and realize its as simple as 1-2-3. =)
cout<
cout<<**b<<"\n"; //prints 5 as well!
#5
int b;
int *a=&b;
this is exactly the same as the very first example i gave in the previous post. here, a is declared as a pointer initialized to the address of b. but whats the value of b? well 'b' has no value yet, thus, a points to an undefined int. attempting to print b or *a would lead to a compiler error.
b=5; // now 'b' has a value which means *a now equals 5
*a=7; // now *a equals 7 which means 'b' now equals 7 as well
take a second to let that sink in. theres no precedence in this situation. for all intents and purposes, b and *a are exactly the same. its not a dependent relationship its an equality. changing one will alter the other as well.
this begs the question, whats the point of this crap? why use pointers at all? all will be understood in time grasshoppa...
struct two_ints
{
int first=1;
int second=2;
};
two_ints a;
two_ints *b;
b=&a;
cout<
cout<
cout<first<<"\n"; //prints 1
cout<second<<"\n"; //prints 2
here b is a pointer to a two_ints data type. Use the '->' arrow thing to access members of a structure thru a pointer. again, changing 'b->first' will also change 'a.first' and vice versa.
in C++ you could also do:
two_ints *b;
b=new two_ints;
here, rather than having b simply point to a pre-existing structure, we've created b's very own structure to point to. the only way you can access this new structure is through b using b->first and b->second.
void five(int *a) //five takes an int pointer as its parameter
{
a=5; // make the int equal to 5
}
int *b; //b is an int pointer
five(b);
theres one thing wrong with this code do you know what it is?
a=5;
this is WRONG! in the function, 'a' is an int pointer which should only be set to an ADDRESS.
*a=5;
this is what we really want.
got it? if youve understood everything explained so far then congratulations! you understand everything there is to know about pointers.
that's pretty much all you need to know about pointers in terms of definition. i think everything else can best be explained by addressing questions most will have at this point.
08/18/2005 (11:23 am)
Now for a little more advanced and useful stuff...int b;
int *a=&b;
this is exactly the same as the very first example i gave in the previous post. here, a is declared as a pointer initialized to the address of b. but whats the value of b? well 'b' has no value yet, thus, a points to an undefined int. attempting to print b or *a would lead to a compiler error.
b=5; // now 'b' has a value which means *a now equals 5
*a=7; // now *a equals 7 which means 'b' now equals 7 as well
take a second to let that sink in. theres no precedence in this situation. for all intents and purposes, b and *a are exactly the same. its not a dependent relationship its an equality. changing one will alter the other as well.
this begs the question, whats the point of this crap? why use pointers at all? all will be understood in time grasshoppa...
struct two_ints
{
int first=1;
int second=2;
};
two_ints a;
two_ints *b;
b=&a;
cout<
cout<
here b is a pointer to a two_ints data type. Use the '->' arrow thing to access members of a structure thru a pointer. again, changing 'b->first' will also change 'a.first' and vice versa.
in C++ you could also do:
two_ints *b;
b=new two_ints;
here, rather than having b simply point to a pre-existing structure, we've created b's very own structure to point to. the only way you can access this new structure is through b using b->first and b->second.
void five(int *a) //five takes an int pointer as its parameter
{
a=5; // make the int equal to 5
}
int *b; //b is an int pointer
five(b);
theres one thing wrong with this code do you know what it is?
a=5;
this is WRONG! in the function, 'a' is an int pointer which should only be set to an ADDRESS.
*a=5;
this is what we really want.
got it? if youve understood everything explained so far then congratulations! you understand everything there is to know about pointers.
that's pretty much all you need to know about pointers in terms of definition. i think everything else can best be explained by addressing questions most will have at this point.
#6
Something flashed in my mind reading this, I supposed in example using a pointer to pointer in a matrix would allow the programmer
to bind an entire row of the matrix itself to another row, like in:
**mymatrix //this contains a pointer matrix
*mymatrix[3] = *substitutive_row;
Bad coding here by me, I know, but was just to explain. Is it right?
However, thanks for help: I greatly appreciate it.
Bye, Thc.
08/18/2005 (3:53 pm)
Well, I'm getting more known to these.Something flashed in my mind reading this, I supposed in example using a pointer to pointer in a matrix would allow the programmer
to bind an entire row of the matrix itself to another row, like in:
**mymatrix //this contains a pointer matrix
*mymatrix[3] = *substitutive_row;
Bad coding here by me, I know, but was just to explain. Is it right?
However, thanks for help: I greatly appreciate it.
Bye, Thc.
#7
1) what's the difference between...
2) whats the main difference between a stack and a heap?
(i cut out my pointer questions, because other people have answered these in other posts here)
Answer 1): the first gets allocated on the stack. the second gets allocated on the heap.
Answer 2) there are a lot of differences (performance, size, etc) but the biggest difference is the stack is automatically cleaned up, but you must garbage collect off the heap otherwise you will result in memory leaks!
08/18/2005 (5:00 pm)
Here's a quiz for you all.. I will post the answers in a few hours.1) what's the difference between...
char[] test = new char[4];and
char* test = new char[4];
2) whats the main difference between a stack and a heap?
(i cut out my pointer questions, because other people have answered these in other posts here)
Answer 1): the first gets allocated on the stack. the second gets allocated on the heap.
Answer 2) there are a lot of differences (performance, size, etc) but the biggest difference is the stack is automatically cleaned up, but you must garbage collect off the heap otherwise you will result in memory leaks!
#8
*****************questions****************
now that you understand how pointers work, nows a good time to address the many questions one may have about them.
why cant i do this?
int a;
int b;
b=&a;
first off, b is defined as an int, not an int pointer. a pointer is the only datatype which can take on the value of an address. most of all, the main point of using a pointer is to use the dereference operator.
why cant i do this?
int a=5;
int *b=&a;
cout<
you can. if you did this you would print the address of a in hexidecimal format.
why cant i do this?
int a=5;
int *b;
b=a;
now why would you want to do that? youd probably get a page fault or something if you tried that.
why cant i do this?
int a=5;
int *b;
&a=&b;
now youre starting to get on my nerves. in general, you will NEVER NEVER NEVER set the address of something. set pointers to addresses, but you cannot set the address of something.
whats the difference between these 3?
first:
int a=5;
int *b=&a; //pointer b declared and initialized to &a
//legal
second:
int a=5;
int *b; //pointer b declared
b=&a; //pointer b set to &a
//legal
third:
int a=5;
int *b; //pointer b declared
*b=&a; //illegal
the first two are legal valid ways of initializing pointers that i discussed earlier. the third way is wrong. the line:
*b=&a;
'*b' is used to access what b points to and 'b' is used to set where b should point. this is something that was hard for me to grasp at first. think about what you're trying to do before you start throwing around asterisks and ampersands all willy nilly.
im confused, how do i know when to use &, *, or ->?
lets review:
1. & is the address operator. you use this to get the address of something to set a pointer.
2. * can be tricky because it's used in 2 circumstances
a. its used when declaring a new pointer
eg. int *b=&a;
b. its used to access the data a pointer points to
eg. *b=7;
3. -> is used to access the properties of a structure through a pointer.
why use pointers?
thats the best question youve asked yet. in short, pointers are useful for two things; passing datatypes to functions by reference, and organizing data structures into lists which can be sorted and searched quickly. if you want more details go research it.
sometimes i see & as a data type, whats that mean?
thats something different:
int a;
int &b=a; //this is not a pointer or address, this is an int reference
b is a reference to int a. a reference is like a shapebaseimage, it cannot exist without being linked to something else. it must be initialized upon declaration. once its linked to a variable, you cannot undo it, theyre linked for life. a reference is like an alias for another variable. changing one will change the other.
well i hope this little tut has been useful to someone. if anyone has any questions, corrections, clarifications etc. dont hesitate to chime in.
08/18/2005 (5:14 pm)
...cont'd*****************questions****************
now that you understand how pointers work, nows a good time to address the many questions one may have about them.
why cant i do this?
int a;
int b;
b=&a;
first off, b is defined as an int, not an int pointer. a pointer is the only datatype which can take on the value of an address. most of all, the main point of using a pointer is to use the dereference operator.
why cant i do this?
int a=5;
int *b=&a;
cout<
you can. if you did this you would print the address of a in hexidecimal format.
why cant i do this?
int a=5;
int *b;
b=a;
now why would you want to do that? youd probably get a page fault or something if you tried that.
why cant i do this?
int a=5;
int *b;
&a=&b;
now youre starting to get on my nerves. in general, you will NEVER NEVER NEVER set the address of something. set pointers to addresses, but you cannot set the address of something.
whats the difference between these 3?
first:
int a=5;
int *b=&a; //pointer b declared and initialized to &a
//legal
second:
int a=5;
int *b; //pointer b declared
b=&a; //pointer b set to &a
//legal
third:
int a=5;
int *b; //pointer b declared
*b=&a; //illegal
the first two are legal valid ways of initializing pointers that i discussed earlier. the third way is wrong. the line:
*b=&a;
'*b' is used to access what b points to and 'b' is used to set where b should point. this is something that was hard for me to grasp at first. think about what you're trying to do before you start throwing around asterisks and ampersands all willy nilly.
im confused, how do i know when to use &, *, or ->?
lets review:
1. & is the address operator. you use this to get the address of something to set a pointer.
2. * can be tricky because it's used in 2 circumstances
a. its used when declaring a new pointer
eg. int *b=&a;
b. its used to access the data a pointer points to
eg. *b=7;
3. -> is used to access the properties of a structure through a pointer.
why use pointers?
thats the best question youve asked yet. in short, pointers are useful for two things; passing datatypes to functions by reference, and organizing data structures into lists which can be sorted and searched quickly. if you want more details go research it.
sometimes i see & as a data type, whats that mean?
thats something different:
int a;
int &b=a; //this is not a pointer or address, this is an int reference
b is a reference to int a. a reference is like a shapebaseimage, it cannot exist without being linked to something else. it must be initialized upon declaration. once its linked to a variable, you cannot undo it, theyre linked for life. a reference is like an alias for another variable. changing one will change the other.
well i hope this little tut has been useful to someone. if anyone has any questions, corrections, clarifications etc. dont hesitate to chime in.
#9
int a[2]={1,2};
int *b;
b=&a
cout<<*b; //prints 1
cout< cout<<*(b+1); //prints 2
cout<
to answer your question, yes you could bind one row or column of a matrix to another so that when you change one, the other will automatically be changed, but i dont know how useful that would be. one thing to keep in mind though, pointers always only refer to one object at a time. the reason i say that is because you mentioned that the pointer "contains" a pointer matrix. im not sure how to code the situation youre thinking of though.
08/18/2005 (6:12 pm)
Thc theres an intimate relationship between pointers and arrays. in fact, an array variable is a pointer. int a[2]={1,2};
int *b;
b=&a
cout<<*b; //prints 1
cout< cout<<*(b+1); //prints 2
cout<
to answer your question, yes you could bind one row or column of a matrix to another so that when you change one, the other will automatically be changed, but i dont know how useful that would be. one thing to keep in mind though, pointers always only refer to one object at a time. the reason i say that is because you mentioned that the pointer "contains" a pointer matrix. im not sure how to code the situation youre thinking of though.
#10
08/18/2005 (8:28 pm)
That's great stuff, Sean. Thanks!
#11
As far as I understood, when using pointers as arrays, the variable name keeps the offset, but the address where is keeped?
Or there is an automatic selection of the data "I could want at the moment"?
Forget about my situation, was just to know if I undersood well. Just an example.
Thanks.
Bye, Thc.
08/21/2005 (3:24 am)
@Sean:As far as I understood, when using pointers as arrays, the variable name keeps the offset, but the address where is keeped?
Or there is an automatic selection of the data "I could want at the moment"?
Forget about my situation, was just to know if I undersood well. Just an example.
Thanks.
Bye, Thc.
#12
(which leads us to Jason's Triva Question Number 1)
Okay, ready for some brain-pickling fun?
FUNCTION POINTERS! (just because I like the sound of skulls detonating)
This declares a type called 'funcPtr'. It is the address of a function that takes no parameters and returns nothing, like foo, bar, and baz.
fooPtr is just like any other pointer, with one exception: You can make function calls through it:
BTW: When dealing with complex type declarations, it's a good idea to break it down using 'typedef'. If I wanted an array of function pointers, I could write it in two was:
You'll note there is no second way listed. That's because I couldn't figure out how to get the second method to compile, so just pretend you always have to use a typedef. ;) "void(*)(void) ptr2[]" doesn't work.
08/22/2005 (10:43 am)
@Thc-03, I'm afraid I don't understand your question. Arrays and pointers are ALMOST interchangable.(which leads us to Jason's Triva Question Number 1)
int a[4]; // allocates space for 4 integers int b* = new int[4] // allocates space for 4 integers, saves the address in 'b' for use and disposal int c[4] = new int[4]; // allocates c's 4 ints, allocates another 4 ints, and copies whatever happend to be at those addresses into c's ints. As the new'd memory address isn't saved, it leaks. That's bad.
Okay, ready for some brain-pickling fun?
FUNCTION POINTERS! (just because I like the sound of skulls detonating)
void foo( void ); void bar( void ); void baz( void ); typedef void(*funcPtr)(void);
This declares a type called 'funcPtr'. It is the address of a function that takes no parameters and returns nothing, like foo, bar, and baz.
funcPtr fooPtr = foo;
fooPtr is just like any other pointer, with one exception: You can make function calls through it:
fooPtr(); // calls foo fooPtr = bar; fooPtr(); // calls bar fooPtr = baz; fooPtr(); // calls baz
BTW: When dealing with complex type declarations, it's a good idea to break it down using 'typedef'. If I wanted an array of function pointers, I could write it in two was:
FuncPtr ptrs1[] = { &foo, &bar, &baz };You'll note there is no second way listed. That's because I couldn't figure out how to get the second method to compile, so just pretend you always have to use a typedef. ;) "void(*)(void) ptr2[]" doesn't work.
#14
08/22/2005 (12:19 pm)
Thanks, Mark...function pointers have always baffled me...I still can't quite resolve in my mind how they are used in real-world programming.
#15
Well golly! Lots of ways. First of all, they're used behind-the-scenes to implement virtual functions. That doesn't quite count though.
How about the most obtuse version of "hello world" ever? Each function prints a letter? Kinda fails the "real world" test again. ;)
Okay. Real World: Callbacks. Lots of event models out there for various things. Guis, all manner of i/o (file, network, whatever). Most applications that support 3rd-party plug-ins require callbacks to hook into their custom enumerations (call THIS on all of THOSE), events (requested a printout, closed a document, whatever), and so on.
I've had lots of experience with Acrobat's API, for example. Every time I want to so much as sneese, I need to register a callback to wipe my nose.
When you're using a library that doesn't have appropriate class you can inherit from (Acrobat fer zample), you have to register for callbacks in order to respond to various events. Not an issue with torque, but its required in Straight C, and as many library vendors want as many customers as possible. Commercial APIs that require C++ features can't sell to all the old-skoolers. They often provide a decent header or two to use for convenience to the C++ jockeys like myself, but that's just a layer on top of the 'C' stuff.
All Adobe's libraries (that I've been exposed to) are straight C. Acrobat has piles of callbacks all over the place.
The standard C library's 'qsort' function takes a pointer to a comparison function.
They can also be used to clean up Really Nasty switch statements. Turn each case into a function, and stick them all in an array. This is potentially faster too, avoiding all the underlying if-elseif-elseif--- in exchange for an array lookup and a function call... Not always appropriate though, depending on what you're switching on, it may not be appropriate for an array index... You could use something like an std::map, but you'd have to have a pretty huge 'switch' for that to pay off (because now you've got O(logN) ifs instead of '0', and map's [] operator is another function call).
In 'C', function pointers can be used to simulate virtual functions. Put a couple function pointers in a struct, and you've got faux member functions. Point them in different places at different times, and you've got your 'virtual'. You've still got to manually pass 'this', you don't get constructor/destructors, etc, etc.
Function pointers get used, they're just obscure enough that they're a tool of last resort. (insert Bush-bash here)
08/22/2005 (1:43 pm)
@mike:Well golly! Lots of ways. First of all, they're used behind-the-scenes to implement virtual functions. That doesn't quite count though.
How about the most obtuse version of "hello world" ever? Each function prints a letter? Kinda fails the "real world" test again. ;)
Okay. Real World: Callbacks. Lots of event models out there for various things. Guis, all manner of i/o (file, network, whatever). Most applications that support 3rd-party plug-ins require callbacks to hook into their custom enumerations (call THIS on all of THOSE), events (requested a printout, closed a document, whatever), and so on.
I've had lots of experience with Acrobat's API, for example. Every time I want to so much as sneese, I need to register a callback to wipe my nose.
When you're using a library that doesn't have appropriate class you can inherit from (Acrobat fer zample), you have to register for callbacks in order to respond to various events. Not an issue with torque, but its required in Straight C, and as many library vendors want as many customers as possible. Commercial APIs that require C++ features can't sell to all the old-skoolers. They often provide a decent header or two to use for convenience to the C++ jockeys like myself, but that's just a layer on top of the 'C' stuff.
All Adobe's libraries (that I've been exposed to) are straight C. Acrobat has piles of callbacks all over the place.
The standard C library's 'qsort' function takes a pointer to a comparison function.
They can also be used to clean up Really Nasty switch statements. Turn each case into a function, and stick them all in an array. This is potentially faster too, avoiding all the underlying if-elseif-elseif--- in exchange for an array lookup and a function call... Not always appropriate though, depending on what you're switching on, it may not be appropriate for an array index... You could use something like an std::map
In 'C', function pointers can be used to simulate virtual functions. Put a couple function pointers in a struct, and you've got faux member functions. Point them in different places at different times, and you've got your 'virtual'. You've still got to manually pass 'this', you don't get constructor/destructors, etc, etc.
Function pointers get used, they're just obscure enough that they're a tool of last resort. (insert Bush-bash here)
#16
Wow, that's some good stuff. I think I'll have to read through that a few times before it sinks in, but I think I understand a little better. Thanks...
08/22/2005 (2:10 pm)
@Mark...Wow, that's some good stuff. I think I'll have to read through that a few times before it sinks in, but I think I understand a little better. Thanks...
#17
What IS a pionter?
A memory address is like the address of your residence, the land where you live.
If your land, or house, represents a 'memory space' of 1 Byte (8 bits), and there are 1024 houses in your neighborhood, your neighborhood represents 1 KByte (1024 bytes) of memory space. It doesn't really matter if your address is in one subdivision (256M DDR RAM), or another subdivision (32k processor cache (stack)), or a transient's bunk bed at the YMCA (CPU register).
A pointer, when properly initialized, points to a memory address.
The size of this pointer variable usually is the same as the size of the addressing scheme of your system. For Win32 development, that's a 32 bit addressing space. This represents billions of house addresses (byte addresses).
In C, if you have a byte pointer variable, pc (char is 1 byte), represented by an integer on a 32 bit system, it would look like this:
These pointers, p, pc, and ps, are variables that, themselves, use 4 bytes of memory space (on a 32 bit system). Each pointer can be used to store an address of that memory space (4 bytes = 32 bits, or 8 bits per byte). p is itself a house that takes up 4 adddresses on a street. A char represents 1 byte of memory space. Therefore pc points to a memory blocks of 1 byte size starting at the address contained in the 4 byte pc variable space. A short represents 2 bytes of memory space, so ps points to memory blocks of 2 bytes in size starting at the memory address stored in the 4 bytes that represent the variable ps.
The same code on a system with a 16 bit addressing space would create a memory space of 2 bytes to hold the variable p, or ps, or pc.
Let's say we ask the system to give us the address of 16 bytes of space. We want to point to a memory array of 4 integers. Each integer is 4 bytes. We ask for 4 * sizeof(int) which evaluates to 16.
This asks the system to allocate 4 bytes times sizeof(int), which is 4 on a 32 bit system, or 16 bytes total and returns the address of the memory space where the 16 bytes live.
If you want to see who's home at the address of the first integer that p points to you'd write:
If you want to see who's home at the 3rd integer address from p, you could write:
Above I said that p was itself a house that takes up 4 bytes. You can get the address of p like so:
You could then change the address that p points to by using pp:
In order to give those bytes back to the system for someone else to use when we're done with them we can use:
The following line frees the memory allocated to pi.
Hope you're all thoroughly confused now.
08/22/2005 (2:39 pm)
Once you see what a pointer is, using it becomes fairly straightforward.What IS a pionter?
A memory address is like the address of your residence, the land where you live.
If your land, or house, represents a 'memory space' of 1 Byte (8 bits), and there are 1024 houses in your neighborhood, your neighborhood represents 1 KByte (1024 bytes) of memory space. It doesn't really matter if your address is in one subdivision (256M DDR RAM), or another subdivision (32k processor cache (stack)), or a transient's bunk bed at the YMCA (CPU register).
A pointer, when properly initialized, points to a memory address.
The size of this pointer variable usually is the same as the size of the addressing scheme of your system. For Win32 development, that's a 32 bit addressing space. This represents billions of house addresses (byte addresses).
In C, if you have a byte pointer variable, pc (char is 1 byte), represented by an integer on a 32 bit system, it would look like this:
char * pc; // character pointer pc
short * ps; // short pointer ps int * p; //integer pointer p
These pointers, p, pc, and ps, are variables that, themselves, use 4 bytes of memory space (on a 32 bit system). Each pointer can be used to store an address of that memory space (4 bytes = 32 bits, or 8 bits per byte). p is itself a house that takes up 4 adddresses on a street. A char represents 1 byte of memory space. Therefore pc points to a memory blocks of 1 byte size starting at the address contained in the 4 byte pc variable space. A short represents 2 bytes of memory space, so ps points to memory blocks of 2 bytes in size starting at the memory address stored in the 4 bytes that represent the variable ps.
The same code on a system with a 16 bit addressing space would create a memory space of 2 bytes to hold the variable p, or ps, or pc.
Let's say we ask the system to give us the address of 16 bytes of space. We want to point to a memory array of 4 integers. Each integer is 4 bytes. We ask for 4 * sizeof(int) which evaluates to 16.
p = malloc( 4 * sizeof(int));
This asks the system to allocate 4 bytes times sizeof(int), which is 4 on a 32 bit system, or 16 bytes total and returns the address of the memory space where the 16 bytes live.
If you want to see who's home at the address of the first integer that p points to you'd write:
int a; a = p[0]; // first integer (index 0) in an array of integers. or int b; b = *p; // value (*) of the integer that p points to
If you want to see who's home at the 3rd integer address from p, you could write:
a = p[2]; // zero based index, 0, 1, 2 being third integer. or b = *(p+1); // value (*) of what's at the next integer address after p (p + 1)
Above I said that p was itself a house that takes up 4 bytes. You can get the address of p like so:
int **pp = & p; // pp = address of p. Sometimes pp is called a handle.
You could then change the address that p points to by using pp:
int * pi = malloc( 4 * sizeof(int));
In order to give those bytes back to the system for someone else to use when we're done with them we can use:
free (p); *pp = & pi;
The following line frees the memory allocated to pi.
free( *pp); // tell the system we're done with this memory space.
Hope you're all thoroughly confused now.
#18
Later I remembered that memory addresses are threated (at least in assembly language) as pairs of addresses and offsets. (afc1:0003 in example).
About the array thing, I was unclear in memory.
The code I would used is:
About function pointers, this make me think once you have something capable of parsing scripts, you could (if I understood well) use the parser as follows:
08/24/2005 (3:35 pm)
I meant, if is possible to do *(pointername + x) to offset the pointer address, maybe the pointer itself contains just the offset.Later I remembered that memory addresses are threated (at least in assembly language) as pairs of addresses and offsets. (afc1:0003 in example).
About the array thing, I was unclear in memory.
The code I would used is:
int a = 0;
int *rows;
int **columns;
// properly initialize pointers here to avoid memory messes
for(a = 0; a < 10; a++)
{
*(rows + b) = [random number];
*(columns + a) = rows + a;
}
// and then...
*(columns + 3) = [any other pointer row here];About function pointers, this make me think once you have something capable of parsing scripts, you could (if I understood well) use the parser as follows:
int addition(int operand1 = 0, int operand2 = 0)
{
return operand1 + operand2;
}
double fake(double)
{
return 0;
}
typedef double(*funcptr) (double, ...);
// somewhere in the code...
funcptr actualfunction = fake; (for now)
// Let's say we have a script parser function, the argv[1] is the name of the command wrote, and from it until argv[x] = null there are arguments passed with the command.
// Then, a switch statement checks for the command used and assigns functions to the pointer and passes parameters to them.
case "addition":
actualfunction = (int)argv[1];
actualfunction((int) argv[2], (int) argv[3]);
break;
// cut...May this be ok?
Torque Owner Westy
For people who dont know what pointers are, they are variable objects that reference that start of memoery that they are occupying.
So..
MyClassObject object1; //This is a standard object, when you use it, you are referencing the whole block of memory it uses.
MyClassObject* object2; //Ok this is different, here you are referencing the address of where this object begins.
//You access public members differently
object1.member ...
object2->member ...
//this means the address of
object2 = &object1;
// (*) will give you what is at the address
object1 = (*object2);
//** is simply a pointer to a pointer.
MyClassObject* object;
MyClassObject** pobject = &object;
Lets hope other people can expand on that.