views:

7176

answers:

29

From the number of questions posted here, it's clear that people have some pretty fundemental issues when getting their heads around pointers and pointer arithmetic.

I'm curious to know why. They've never really caused me major problems (although I first learned about them back in the Neolithic). In order to write better answers to these questions, I'd like to know what people find difficult.

So, if you're struggling with pointers, or you recently were but suddenly "got it", what were the aspects of pointers that caused you problems?

(I've tried to word this so that it's not argumentative or subjective. I'm genuinely interested in what people have problems with here)

+16  A: 

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.]

Steve Townsend
Pointers were considered difficult long before Java came into existence and dominated the CS curriculum.
Jason
@Jason - that is true but does not negate the argument.
Steve Townsend
Spolsky isn't saying that JavaSchools are the reason people find pointers difficult. He's saying they result in pointer-illiterate people with Computer Science degrees.
benzado
@benzado - fair point - my brief post would be improved if it read 'a great article supporting the notion that pointers are hard'. What the article does imply is that "having a CS degree from a 'good school'" is not as good a predictor of success as a developer as it used to be, while "understands pointers" (and recursion) still is.
Steve Townsend
@Steve Townsend: I think you're missing the point of Mr. Spolsky's argument.
Jason
@Jason - possibly - what do you think that is? I will tell you if I missed it or disagree, and why.
Steve Townsend
@Steve Townsend: Mr. Spolsky is arguing that Java schools are raising a generation of programmers that don't know pointers and recursion, not that pointers are hard because of the prevalence of Java schools. As you stated "there is a great article about why this is hard" and linked to said article, it seems you have the latter interpretation. Forgive me if I'm wrong.
Jason
@Jason - agreed, see my comment above in response to @benzado. Any better? perhaps this makes my response offtopic, but I really like that article and its tangential relevance led me to post.
Steve Townsend
Steve, my comment was actually for Jason. I forgot to use tweet syntax. I don't think any of us are missing the point of anything.
benzado
@benzado - I do think my original text is not quite what I meant and am editing in the revised version.
Steve Townsend
+35  A: 

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.

Robert Harvey
Nice with the neutral POV, there.
dmckee
@dmckee: Well, am I wrong? How many Java programmers could deal with a segfault?
Robert Harvey
@Robert Harvey: `How many Java programmers could deal with a segfault?` And there goes the neutral POV! ;-) (not saying I disagree with your comment)
Praetorian
Learning about computers from the bottom-up (started literally by looking up instructions for an HC11 and typing them in hex into an S-record) makes it fairly straightforward as to what my processor does when it sees a pointer. I've never done x86 assembly, but those concepts still hold (though they're vastly more complex nowadays)
Nick T
Are segfaults something to do with stick shift? *-- A Java Programmer*
Tom Anderson
@Robert Harvey: How many C++ programmers can write comprehensible, maintainable, leak-proof code? Hint - they're usually the same people. I don't think your beef is with Java, or with the lack of knowledge about the underlying machine, but with the long tail of programming talent :)
Merlyn Morgan-Graham
@Robert: it was meant as a genuine complement. This is a tough subject to discuss without hurting peoples feelings. And I'm afraid my comment precipitated the very conflict I thought you'd managed to avoid. *Mea cupla.*
dmckee
@Merlyn: Exactly right. Unfortunately there are days when I feel like I'm at the end of that long tail ;).
Robert Harvey
I disagree; you do not need to understand the underlying architecture to get pointers (they are an abstraction, anyway).
Jason
@Jason: In C, a pointer is essentially a *memory address.* Working with them safely is impossible without understanding the machine architecture. See http://en.wikipedia.org/wiki/Pointer_(computing) and http://boredzo.org/pointers/#definition
Robert Harvey
@Merlyn - good point. You could rephrase Robert's response to ask how many Java programmers really understand how their **virtual** machine works.
Steve Townsend
@Jason: You're right that you don't need to understand the architecture to get pointers, but they're trivial to understand if you understand the architecture, and a huge pain if you don't. I learned C after I spent several years writing 8502 and 6809 assembly, and I never understood why people dreaded pointers when I learned them. I thought they were just like index registers...
Ori Pessach
C pointers are an abstraction. If you stick within the "defined" bits of the standard your code will be safe without you knowing anything about the underlying architecture. It's just that in practice many kinds of things are not efficient (or even not possible) using portable standard C and so details about architecture (and compiler!) become important. But the fact is pointers are an abstraction meant to hide the underlying platform's concept of an address. Is an address 8, 16, 32, or 64 bits? Segmented? Tagged? Doesn't matter. Portable C will handle all the above.
James Iry
I don't think your analogy is as correct as it could be. It should be "… just as most *mechanics* don't know anything about an engine." (Since people who drive a car are the consumers, not the people who work on cars.) And by the way, I think that analogy would be false then. Most mechanics probably know more about cars than programmers know about computers.
Josh Leitzel
lol. After all the development in programming languages, a bunch of really smart people are still fighting over C vs Java. That's hilarious.
zengr
Exactly. I regularly see young fanatic developers that despite low-level C and pointers, but if a problem pops up at a customer, are unable to understand the memory dumps and solve the problem in the debugger, because they don't understand anymore what's actually going on.
Patrick
@Robert Harvey: No. I think those definitions you gave are bad. C pointers are an abstraction of the memory. A pointer is probably better defined as something that lets you indirectly refer to certain values. When I learned pointers I didn't need to know anything about the underlying architecture of the NeXT boxes in our computer lab because the concepts applied equally to the x86 box I had at home.
Jason
@Ori Pessach: I respectfully disagree. The underlying architecture just gets in the way. If you understand pointers correctly, what you learn applies equally to 8502s and x86s. What you learned from working in assembly was _indirection_, and that is the key concept to understanding C pointers; it had nothing to do with the particular architecture.
Jason
@Jason: Indirection only tells you part of the story. It doesn't help you understand the relationship between arrays and pointers, pointer arithmetic, how to write code that generates code, function pointers, the difference between pointers to the stack to pointers to the heap, or really much of anything that ends up biting you when you don't understand it. There's no substitute for a good, solid understanding of what happens at least one level of abstraction lower than the one you work with.
Ori Pessach
@Ori Pessach: None of the things that you listed is any different with knowledge of the underlying architecture. (Except maybe generating code, depending on what kind of code you're talking about.) I prefer to think of them in terms of the C abstractions.
Steve M
@Steve M: When you don't understand what's going on beneath the abstraction it might be hard to understand (for example) why, when you define two arrays and modify one of them, the other might change. The reason is that C's abstraction of memory is leaky. I've seen, time and again, people who don't have a good working knowledge of the underlying concepts stumbling over these exact problems. Abstraction is great when it works, but it gets in the way when it doesn't. I see a huge difference between the level of competence of people who understand the architecture and people who don't.
Ori Pessach
+2  A: 

I think it requires a solid foundation, probably from the machine level, with introduction to some machine code, assembly, and how to represent items and data structure in RAM. It takes a little time, some homework or problem solving practice, and some thinking.

But if a person knows high level languages at first (which is nothing wrong -- a carpenter uses an ax. a person who needs to split atom uses something else. we need people who are carpenters, and we have people who study atoms) and this person who knows high level language is given a 2 minute introduction to pointers, and then it is hard to expect him to understand pointer arithmetics, pointers to pointers, array of pointers to variable size strings, and array of array of characters, etc. A low-level solid foundation can help a lot.

動靜能量
Groking pointers does not require an understanding of machine code or assembly.
Jason
+5  A: 

The main difficulty with pointers, at least to me, is that I didn't start with C. I started with Java. The whole notion of pointers were really foreign until a couple of classes in college where I was expected to know C. So then I taught myself the very basics of C and how to use pointers in their very basic sense. Even then, every time I find myself reading C code, I have to look up pointer syntax.

So in my very limited experience(1 year real world + 4 in college), pointers confuse me because I've never had to really use it in anything other than a classroom setting. And I can sympathize with the students now starting out CS with JAVA instead of C or C++. As you said, you learned pointers in the 'Neolithic' age and have probably been using it ever since that. To us newer people, the notion of allocating memory and doing pointer arithmetic is really foreign because all these languages have abstracted that away.

P.S. After reading the Spolsky essay, his description of 'JavaSchools' was nothing like what I went through in college at Cornell ('05-'09). I took the structures and functional programming (sml), operating systems (C), algorithms (pen and paper), and a whole slew of other classes that weren't taught in java. However all the intro classes and electives were all done in java because there's value in not reinventing the wheel when you are trying to do something higher leveled than implementing a hashtable with pointers.

shoebox639
Honestly, given that you have difficulties with pointers still, I'm not sure that your experience at Cornell substantively contradicts Joel's article. Obviously enough of your brain is wired in a Java-mindset to make his point.
jkerian
Wat? References in Java (or C#, or Python, or propably dozens of other languages) are just pointers without the arithmetic. Understanding pointers means understanding why `void foo(Clazz obj) { obj = new Clazz(); }` is a no-op while `void bar(Clazz obj) { obj.quux = new Quux(); }` mutates the argument...
delnan
I know what references are in Java, but I'm just saying that if you asked me to do reflection in Java or write anything meaningful in C I can't just chug it out. It requires a lot of research, like learning it for the first time, every time.
shoebox639
+34  A: 

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:

  1. Heap vs Stack storage. It is simply stunning how many people do not understand this, even in a general sense.
  2. Stack frames. Just the general concept of a dedicated section of the stack for local variables, along with the reason it's a 'stack'... details such as stashing the return location, exception handler details, and previous registers can safely be left till someone tries to build a compiler.
  3. "Memory is memory is memory" Casting just changes which versions of operators or how much room the compiler gives for a particular chunk of memory. You know you're dealing with this problem when people talk about "what (primative) variable X really is".

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.

jkerian
This sounds exactly like my professor for my computing 1 and 2 (data structures) course. The very first day, we filled out memory templates for some programs and followed the flow of the programs. Fictional addresses for the heap helped, and constantly being quizzed/tested on those templates really helps with an understanding of pointers. We even followed some in the data structures course for case studies.
Kizaru
sigjuice
Honestly, you don't really need to know it anymore. They used to teach latin and greek in school. They don't anymore. Sure SOME people might need/want to know it, but overall it's not necessary.
Jack Marchetti
jkerian
@John Marchetti: You don't need to know Latin and Greek to use English. (With that said, I'm disappointed in people who call themselves linguists who don't have at least a technical understanding of both) C is not in the same category for the obvious reason that there are hundreds of billions of lines of C code in production. 90% of real-world programming is maintenance.
jkerian
@John Marchetti: Even more so... given that the question was "What is the root issue with people's problem with pointers", I don't think the people asking the pointer-related questions would be terribly impressed with "You don't really need to know" as an answer. Obviously they disagree. :)
jkerian
sigjuice
jkerian
"Generally giving explicit fictional addresses to the various locations helped." -> +1
FredOverflow
+14  A: 

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).

John Bode
Yes. 'int foo = 5; int *pfoo = See how useful that is? OK, moving along...' I didn't really use pointers until I wrote my own double-linked list library.
John Lopez
+1. I use to tutor CS100 students and so many of their problems were solved just by going over pointers in an understandable way.
benzado
+12  A: 

I didn't get pointers until I read the description in K&R. Until that point, pointers didn't make sense. I read a whole bunch of stuff where people said "Don't learn pointers, they are confusing and will hurt your head and give you aneurysms" so I shied away from it for a long time, and created this unnecessary air of difficult-concept.

Otherwise, mostly what I thought was, why on earth would you want a variable that you have to go through hoops to get the value of, and if you wanted to assign stuff to it, you had to do strange things to get values to go into them. The whole point of a variable is something to store a value, I thought, so why someone wanted to make it complicated was beyond me. "So with a pointer you have to use the * operator to get at its value??? What kind of goofy variable is that?", I thought. Pointless, no pun intended.

The reason it was complicated was because I didn't understand that a pointer was an address to something. If you explain that it is an address, that it is something that contains an address to something else, and that you can manipulate that address to do useful things, I think it might clear up the confusion.

A class that required using pointers to access/modify ports on a PC, using pointer arithmetic to address different memory locations, and looking at more complicated C-code that modified their arguments disabused me of the idea that pointers were, well, pointless.

sheepsimulator
If you have limited resources to work with (RAM, ROM, CPU), such as in embedded applications, pointers rapidly make much more sense.
Nick T
+3  A: 

Looking back, there were four things that really helped me to finally understand pointers. Prior to this, I could use them, but I did not fully understand them. That is, I knew if I followed the forms, I would get the results I desired, but I did not fully understand the 'why' of the forms. I realize that this is not exactly what you have asked, but I think it is a useful corollary.

  1. Writing a routine that took a pointer to an integer and modified the integer. This gave me the necessary forms upon which to build any mental models of how pointers work.

  2. One-dimensional dynamic memory allocation. Figuring out 1-D memory allocation made me understand the concept of the pointer.

  3. Two-dimensional dynamic memory allocation. Figuring out 2-D memory allocation reinforced that concept, but also taught me that the pointer itself requires storage and must be taken into account.

  4. Differences between stack variables, global variables and heap memory. Figuring out these differences taught me the types of memory to which the pointers point/refer.

Each of these items required imagining what was going on at a lower level--building a mental model that satisfied every case I could think of throwing at it. It took time and effort, but it was well worth it. I am convinced that to understand pointers, you have to build that mental model on how they work and how they are implemented.

Now back to your original question. Based on the previous list, there were several items that I had difficulty in grasping originally.

  1. How and why would one use a pointer.
  2. How are they different and yet similar to arrays.
  3. Understanding where the pointer information is stored.
  4. Understanding what and where it is the pointer is pointing at.
Sparky
+2  A: 

The problem I have always had (primarily self-taught) is the "when" to use a pointer. I can wrap my head around the syntax for constructing a pointer but I need to know under which circumstances a pointer should be used.

Am I the only one with this mindset? ;-)

Larry
@Larry - I get that. My response kinda deals with that.
sheepsimulator
+54  A: 

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 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)

Jeff Knecht
Your comment on the first one, >>*ip = 4; //sets the value of ip to '4'<< is wrong. It should be >>//sets the value of the thing pointed at by ip to '4'
aaaa bbbb
That's what I like in assembly. You have a DWORD and can treat is as int, int*, pointer to any structure or function, and everything without casts.
ruslik
@ruslik: That's very unsafe, apart from anything else. If your DWORD is an int, you can't suddenly call it an int*- cause now your program crashes.
DeadMG
@DeadMG well.. anarchy means responsability :)
ruslik
@ruslik: Except you could just get a program (the compiler) to make sure that you have it right.
DeadMG
Stacking too many types on top of each other is a bad idea, in any language. You may find writing "foo(" strange in C, but writing something like "std::map<std::pair<int,int>,std::pair<std::vector<int>,std::tuple<int,double,std::list<int>>>>" in C++ is also very complex. This does not mean that pointers in C or STL containers in C++ are complex. It just means that you have to use better type-definitions to make it understandable for the reader of your code.
Patrick
I sincerely can't believe an misunderstanding of the _syntax_ is the most heavily voted answer. That's the easiest part about pointers.
Jason
Even reading this answer, I was tempted to get a sheet of paper and draw the picture. In C, I was always drawing pictures.
Michael Easter
Wait'll Jeff gets to function pointers....
Tommy McGuire
+3  A: 

Pointers are difficult because of the indirection.

Jason
"It is said that there is no problem in computer science which cannot be solved by one more level of indirection" (no idea who said it first, though)
Paul
It's like magic, where the misdirection is what confuses people (but is totally awesome)
Nick T
Yeah, I think you hit it on the head here.
willell
A: 

Well, pointers are difficult because they are pointers ;)

MovieYoda
JAJAJA nice try...better luck next time
Necronet
It's not a qustion about recursion :)
ruslik
A: 

Pointers (along with some other aspects of low-level work), require the user to take away the magic.

Most high level programmers like the magic.

Paul Nathan
+5  A: 

I should start out by saying that C and C++ were the first programming languages I learned. I started with C, then did C++ in school a lot, and then went back to C to fluent in it.

The first thing that confused me about pointers when learning C was the simple:

char ch;
char str[100];
scanf("%c %s", &ch, str);

This confusion was mostly rooted in having been introduced to using reference to a variable for OUT arguments before pointers were properly introduced to me. I remember that I skipped writing the first few examples in C for Dummies because they were too simple only to never get the first program I did write to work (most likely because of this).

What was confusing about this was what &ch actually meant as well as why str didn't need it.

After I became familiar with that I next remember being confused about dynamic allocation. I realized at some point that having pointers to data wasn't extremely useful without dynamic allocation of some type, so I wrote something like:

char * x = NULL;
if (y) {
     char z[100];
     x = z;
}

to try to dynamically allocate some space. It didn't work. I wasn't sure that it would work, but I didn't know how else it might work.

I later learned about malloc and new, but they really seemed like magical memory generators to me. I knew nothing about how they might work.

Some time later I was being taught recursion again (I'd learned it on my own before, but was in class now) and I asked how it worked under the hood -- where were the separate variables stored. My professor said "on the stack" and lots of things became clear to me. I had heard the term before and had implemented software stacks before. I had heard others refer to "the stack" long before, but had forgotten about it.

Around this time I also realized that using multidimensional arrays in C can get very confusing. I knew how they worked, but they were just so easy to get tangled up in that I decided to try to work around using them whenever I could. I think that the issue here was mostly syntactic (especially passing to or returning them from functions).

Since I was writing C++ for school for the next year or two I got a lot of experience using pointers for data structures. Here I had a new set of troubles -- mixing up pointers. I would have multiple levels of pointers (things like node ***ptr;) and always tripping over myself. I'd dereference a pointer the wrong number of times and eventually resort to figuring out how many * I needed by trial and error.

At some point I learned how a program's heap worked (sort of, but good enough that it no longer kept me up at night). I remember reading that if you look a few bytes before the pointer that malloc on a certain system returns you can see how much data was actually allocated. I realized that the code in malloc could ask for more memory from the OS and this memory was not part of my executable files. Having a decent working idea of how malloc works is a really useful.

Soon after this I took an assembly class, which didn't teach me as much about pointers as most programmers probably think. It did get me to think more about what assembly my code might be translated into, though. I had always tried to write efficient code, but now I had a better idea how to.

I also took couple of classes where I had to write some lisp. When writing lisp I wasn't as concerned with efficiency as I was in C. I had very little idea what this code might be translated into if compiled, but I did know that it seemed like using lots of local named symbols (variables) made things a lot easier. At some point I wrote some AVL tree rotation code in a little bit of lisp that I had a very hard time writing in C++ because of pointer issues. I realized that my aversion to what I thought were excess local variables had hindered my ability to write that and several other programs in C++.

I also took a compilers class. While in this class I flipped ahead to the advances material and learned about static single assignment (SSA) and dead variables, which isn't that important except that it taught me that any decent compiler will do a decent job of dealing with variables which are no longer used. I already knew that more variables (including pointers) with correct types and good names would help me keep things straight in my head, but now I also knew that avoiding them for efficiency reasons was even more stupid than my less micro-optimization minded professors told me.

So for me, knowing a good bit about the memory layout of a program helped a lot. Thinking about what my code means, both symbolically and on the hardware, helps me out. Using local pointers that have the correct type helps a lot. I often write code that looks like:

int foo(struct frog * f, int x, int y) {
    struct leg * g = f->left_leg;
    struct toe * t = g->big_toe;
    process(t);

so that if I screw up a pointer type it is very clear by the compiler error what the problem is. If I did:

int foo(struct frog * f, int x, int y) {
    process(f->left_leg->big_toe);

and got any pointer type wrong in there the compiler error would be a whole lot more difficult to figure out. I would be tempted to resort to trial and error changes in my frustration, and probably make things worse.

nategoose
+1. Thorough and insightful. I had forgotten about scanf, but now that you bring it up, I remember having the same confusion.
Joe White
+11  A: 

When dealing with pointers, people that get confused are widely in one of two camps. I've been (am?) in both.

The array[] crowd

This 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:

  1. array notation (indexing) with the array name
  2. array notation (indexing) with the pointer name
  3. pointer notation (the *) with the pointer name
  4. pointer notation (the *) with the array name

 

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.

The reference to a pointer and pointer to a pointer crowd

This 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...

David Titarenco
I think you may have given a C++ answer to a C question here... at least the second part.
detly
Pointers to pointers apply to C, as well :p
David Titarenco
+2  A: 

Once upon a time... We had 8 bit microprocessors and everyone wrote in assembly. Most processors included some type of indirect addressing used for jump tables and kernels. When higher level languages came along we add a thin layer of abstraction and called them pointers. Over the years we have gotten more and more away from the hardware. This is not necessarily a bad thing. They are called higher level languages for a reason. The more I can concentrate on what I want to do instead of the details of how it is done the better.

Jim C
+5  A: 

I had my "pointer moment" working on some telephony programs in C. I had to write a AXE10 exchange emulator using a protocol analyser that only understood classic C. Everything hinged on knowing pointers. I tried writing my code without them (hey, I was "pre-pointer" cut me some slack) and failed utterly.

The key to understanding them, for me, was the & (address) operator. Once I understood that &i meant the "address of i" then understanding that *i meant "the contents of the address pointed to by i" came a bit later. Whenever I wrote or read my code I always repeated what "&" meant and what "*" meant and eventually I came to use them intuitively.

To my shame, I was forced into VB and then Java so my pointer knowledge is not as sharp as it once was, but I am glad I am "post-pointer". Don't ask me to use a library that requires me to understand **p, though.

Gary Rowe
+3  A: 

Pointers are a way of dealing with the difference between a handle to an object and an object itself. (ok, not necessarily objects, but you know what I mean, as well as where my mind is)

At some point, you probably have to deal with the difference between the two. In modern, high-level language this becomes the distinction between copy-by-value and copy-by-reference. Either way, it is a concept that is often difficult for programmers to grasp.

However, as has been pointed out, the syntax for handling this problem in C is ugly, inconsistent, and confusing. Eventually, if you really attempt to understand it, a pointer will make sense. But when you start dealing with pointers to pointers, and so on ad nauseum, it gets really confusing for me as well as for other people.

Another important thing to remember about pointers is that they're dangerous. C is a master programmer's language. It assumes you know what the heck you're doing and thereby gives you the power to really mess things up. While some types of programs still need to be written in C, most programs do not, and if you have a language that provides a better abstraction for the difference between an object and its handle, then I suggest you use it.

Indeed, in many modern C++ applications, it is often the case that any required pointer arithmetic is encapsulated and abstracted. We don't want developers doing pointer arithmetic all over the place. We want a centralized, well tested API that does pointer arithmetic at the lowest level. Making changes to this code must be done with great care and extensive testing.

Samo
+2  A: 

Here is a non-answer: Use cdecl (or c++decl) to figure it out:

eisbaw@leno:~$ cdecl explain 'int (*(*foo)(const void *))[3]'
declare foo as pointer to function (pointer to const void) returning pointer to array 3 of int
eisbaw
+2  A: 

I had programmed in c++ for like 2 years and then converted to Java(5 years) and never looked back. However, when I recently had to use some native stuff, I found out (with amazement) that I hadn't forgotten anything about pointers and I even find them easy to use. This is a sharp contrast to what I experienced 7 years ago when I first tried to grasp the concept. So, I guess understanding and liking is a matter of programming maturity ? :)

OR

Pointers are like riding a bike, once you figure out how to work with them, there's no forgetting it.

All in all, hard to grasp or not, the whole pointer idea is VERY educational and I believe it should be understood by every programmer regardless if he programs on a language with pointers or not.

baba
+4  A: 

Here's a pointer/array example that gave me pause. Assume you have two arrays:

uint8_t source[16] = { /* some initialization values here */ };
uint8_t destination[16];

And your goal is to copy the uint8_t contents from source destination using memcpy(). Guess which of the following accomplish that goal:

memcpy(destination, source, sizeof(source));
memcpy(&destination, source, sizeof(source));
memcpy(&destination[0], source, sizeof(source));
memcpy(destination, &source, sizeof(source));
memcpy(&destination, &source, sizeof(source));
memcpy(&destination[0], &source, sizeof(source));
memcpy(destination, &source[0], sizeof(source));
memcpy(&destination, &source[0], sizeof(source));
memcpy(&destination[0], &source[0], sizeof(source));

The answer (Spoiler Alert!) is ALL of them. "destination", "&destination", and "&destination[0]" are all the same value. "&destination" is a different type than the other two, but it is still the same value. The same goes for the permutations of "source".

As an aside, I personally prefer the first version.

Andrew Cottrell
I prefer the first version as well (less punctuation).
sigjuice
+10  A: 

Most things are harder to understand if you're not grounded in the knowledge that's "underneath". When I taught CS it got a lot easier when I started my students on programming a very simple "machine", a simulated decimal computer with decimal opcodes whose memory consisted of decimal registers and decimal addresses. They would put in very short programs to, for example, add a series of numbers to get a total. Then they would single step it to watch what was happening. They could hold down the "enter" key and watch it run "fast".

I'm sure almost everyone on SO wonders why it is useful to get so basic. We forget what it was like not knowing how to program. Playing with such a toy computer puts in place concepts without which you can't program, such as the ideas that computation is a step-by-step process, using a small number of basic primitives to build up programs, and the concept of memory variables as places where numbers are stored, in which the address or name of the variable is distinct from the number it contains. There is a distinction between the time at which you enter the program, and the time at which it "runs". I liken learning to program as crossing a series of "speed bumps", such as very simple programs, then loops and subroutines, then arrays, then sequential I/O, then pointers and data structure. All of these are much easier to learn by reference to what a computer is really doing underneath.

Finally, when getting to C, pointers are confusing though K&R did a very good job of explaining them. The way I learned them in C was to know how to read them - right to left. Like when I see int *p in my head I say "p points to an int". C was invented as one step up from assembly language and that's what I like about it - it is close to that "ground". Pointers, like anything else, are harder to understand if you don't have that grounding.

Mike Dunlavey
A good way to learn this is to program 8-bit microcontrollers. They are easy to understand. Take the Atmel AVR controllers; they are even supported by gcc.
Xenu
@Xenu: I agree. For me it was Intel 8008 and 8051 :-)
Mike Dunlavey
+2  A: 

They add an extra dimension to the code without a significant change to the syntax. Think about this:

int a;
a = 5

There's only one thing to change: a. You can write a = 6 and the results are obvious to most people. But now consider:

int *a;
a = &some_int;

There are two things about a that are relevant at different times: the actual value of a, the pointer, and the value "behind" the pointer. You can change a:

a = &some_other_int;

...and some_int is still around somewhere with the same value. But you can also change the thing it points to:

*a = 6;

There's a conceptual gap between a = 6, which has only local side effects, and *a = 6, which could affect a bunch of other things in other places. My point here is not that the concept of indirection is inherently tricky, but that because you can do both the immediate, local thing with a or the indirect thing with *a... that might be what confuses people.

detly
A: 

I personally did not understand the pointer even after my post graduation and after my first job. The only thing I was knowing is that you need it for linked list, binary trees and for passing arrays into functions. This was the situation even at my first job. Only when I started to give interviews, I understand that the pointer concept is deep and has tremendous use and potential. Then I started reading K & R and writing own test program. My whole goal was job-driven.
At this time I found that pointers are really not bad nor difficult if they are been taught in a good way. Unfortunately when I learn C in graduation, out teacher was not aware of pointer, and even the assignments were using less of pointers. In the graduate level the use of pointer is really only upto creating binary trees and linked list. This thinking that you don't need proper understanding of pointers to work with them, kill the idea of learning them.

Manoj R
A: 

Pointers.. hah.. all about pointer in my head is that it give a memory address where the actual values of whatever its reference.. so no magic about it.. if you learn some assembly you wouldn't have that much trouble learning how pointers works.. come on guys... even in Java everything is a reference..

cass_
A: 

When yours truly last had to debug someone else's C code, it contained a right-threaded binary tree containing double indirect pointers to structs (aaaaaarrrrgggghhhh!).

symcbean
A: 

What I still don't understand about pointers is what they are use for? If all pointers so is reference the memory location of a variable, how does that help you. My thoughs are if you're trying to manipulate a variable or copy a variable why not just set them equal. For instance int x = 3; y = x...

David
+1  A: 

It seems many students have a problem with the concept of indirection, especially when they meet the concept of indirection for the first time. I remember from back when I was a student that out of the +100 students of my course, only a handful of people really understood pointers.

The concept of indirection is not something that we often use in real life, and therefore it's a hard concept to grasp initially.

axilmar