This complexity and the seeming (bold seeming) interchangeability with references ,which is often another caveat of pointers and an error of newcomers, makes understanding pointers hard.
Pointers are arguably the most difficult feature of C to understand. But, they are one of the features which make C an excellent language. In this article, we will go from the very basics of pointers to their usage with arrays, functions, and structure.
# What are the two common problems with pointers? Dangling pointers (dangerous) and Lost heap-dynamic variable.
Once you know how memory works, what's the stack, what's the heap, why there are different segments of memory, pointers will come easy enough, because as I said, the pointer itself is not really a complex concept, and neither is pointer arithmetic (which is just basic addition and subtraction).
When I first started working with them, the biggest problem I had was the syntax.
int* ip;
int * ip;
int *ip;
are all the same.
but:
int* ip1, ip2; //second one isn't a pointer!
int *ip1, *ip2;
Why? because the "pointer" part of the declaration belongs to the variable, and not the type.
And then dereferencing the thing uses a very similar notation:
*ip = 4; //sets the value of the thing pointed to by ip to '4'
x = ip; //hey, that's not '4'!
x = *ip; //ahh... there's that '4'
Except when you actually need to get a pointer... then you use an ampersand!
int *ip = &x;
Hooray for consistency!
Then, apparently just to be jerks and prove how clever they are, a lot of library developers use pointers-to-pointers-to-pointers, and if they expect an array of those things, well why not just pass a pointer to that too.
void foo(****ipppArr);
to call this, I need the address of the array of pointers to pointers to pointers of ints:
foo(&(***ipppArr));
In six months, when I have to maintain this code, I will spend more time trying to figure out what all this means than rewriting from the ground up. (yeah, probably got that syntax wrong -- it's been a while since I've done anything in C. I kinda miss it, but then I'm a bit of a massochist)
I suspect people are going a bit too deep in their answers. An understanding of scheduling, actual CPU operations, or assembly-level memory management isn't really required.
When I was teaching, I found the following holes in students' understanding to be the most common source of problems:
Most of my students were able to understand a simplified drawing of a chunk of memory, generally the local variables section of the stack at the current scope. Generally giving explicit fictional addresses to the various locations helped.
I guess in summary, I'm saying that if you want to understand pointers, you have to understand variables, and what they actually are in modern architectures.
Proper understanding of pointers requires knowledge about the underlying machine's architecture.
Many programmers today don't know how their machine works, just as most people who know how to drive a car don't know anything about the engine.
When dealing with pointers, people that get confused are widely in one of two camps. I've been (am?) in both.
array[]
crowdThis is the crowd that straight up doesn't know how to translate from pointer notation to array notation (or doesn't even know that they are even related). Here are four ways to access elements of an array:
int vals[5] = {10, 20, 30, 40, 50};
int *ptr;
ptr = vals;
array element pointer
notation number vals notation
vals[0] 0 10 *(ptr + 0)
ptr[0] *(vals + 0)
vals[1] 1 20 *(ptr + 1)
ptr[1] *(vals + 1)
vals[2] 2 30 *(ptr + 2)
ptr[2] *(vals + 2)
vals[3] 3 40 *(ptr + 3)
ptr[3] *(vals + 3)
vals[4] 4 50 *(ptr + 4)
ptr[4] *(vals + 4)
The idea here is that accessing arrays via pointers seems pretty simple and straightforward, but a ton of very complicated and clever things can be done this way. Some of which can leave experienced C/C++ programmers befuddled, let alone inexperienced newbies.
reference to a pointer
and pointer to a pointer
crowdThis is a great article that explains the difference and which I'll be citing and stealing some code from :)
As a small example, it can be very difficult to see exactly what the author wanted to do if you came across something like this:
//function prototype
void func(int*& rpInt); // I mean, seriously, int*& ??
int main()
{
int nvar=2;
int* pvar=&nvar;
func(pvar);
....
return 0;
}
Or, to a lesser extent, something like this:
//function prototype
void func(int** ppInt);
int main()
{
int nvar=2;
int* pvar=&nvar;
func(&pvar);
....
return 0;
}
So at the end of the day, what do we really solve with all this gibberish? Nothing.
Now we have seen the syntax of ptr-to-ptr and ref-to-ptr. Are there any advantages of one over the other? I am afraid, no. The usage of one of both, for some programmers are just personal preferences. Some who use ref-to-ptr say the syntax is "cleaner" while some who use ptr-to-ptr, say ptr-to-ptr syntax makes it clearer to those reading what you are doing.
This complexity and the seeming (bold seeming) interchangeability with references ,which is often another caveat of pointers and an error of newcomers, makes understanding pointers hard. It's also important to understand, for completion's sake, that pointers to references are illegal in C and C++ for confusing reasons that take you into lvalue
-rvalue
semantics.
As a previous answer remarked, many times you'll just have these hotshot programmers that think they are being clever by using ******awesome_var->lol_im_so_clever()
and most of us are probably guilty of writing such atrocities at times, but it's just not good code, and it's certainly not maintainable.
Well this answer turned out to be longer than I had hoped...
I blame the quality of reference materials and the people doing the teaching, personally; most concepts in C (but especially pointers) are just plain taught badly. I keep threatening to write my own C book (titled The Last Thing The World Needs Is Another Book On The C Programming Language), but I don't have the time or the patience to do so. So I hang out here and throw random quotes from the Standard at people.
There's also the fact that when C was initially designed, it was assumed you understood machine architecture to a pretty detailed level just because there was no way to avoid it in your day-to-day work (memory was so tight and processors were so slow you had to understand how what you wrote affected performance).
There is a great article supporting the notion that pointers are hard on Joel Spolsky's site - The Perils of JavaSchools.
[Disclaimer - I am not a Java-hater per se.]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With