Hacker News new | ask | show | jobs
by tomrod 2555 days ago
I don't think I understand pointers. Maybe we can help each other. My mental model of pointers is a map: lat/long identify the object of interest (the local coffee shop), but not what is interesting about it (their menu and hours).
7 comments

When learning abstract programming concepts, I think it is important to have some practice operationalizing that knowledge. Precise definitions are important, but by themselves aren't enough because it doesn't guarantee you'll understand the implications of that definition.

Analogies seem like they help, but often lead to error when you reach a point where the analogy is stretched to far.

To see if you understand pointers, try exercise #3 here: https://www.joelonsoftware.com/2005/12/29/test-yourself/ . Just step through the code in your head, and then use your mouse to highlight the text in the box below it. Hopefully that helps you to get started in the right direction.

Hmm, your mental model possibly could use a tweak. Yes, a pointer is like a map. It tells you how to get to the thing but it isn't the thing. It is a reference point, a pointer to the thing. The thing that it points to might be a library, a museum or a place to pick up more maps. Irrespective, the thing to remember is it something to takes you there it is not the place.

You may also pass around the map to your friend in effect showing them how to get to the place, without possibly even having seen the place yourself.

And if you are a bad person, you could share maps that lead to dead end dumps

Hmmm. Interesting. I'm going to have to roll that around in my brain for a day-or-so to see if I can make that compute for me. (Which means I may be back here in a day to check back in!)

Maybe it's because I started in assembly language, but to me, data exists at an address in memory. Or starting at an address in memory. That data might be on integer, a float, a character, the beginning of a string, the head of an object/data-struct, OR an address of data somewhere else (which may be any of the above again). Pointers, to me, are simply an address of an address of a data thingie.

Why would you want to use these? One reason is that pushing large data-objects back-and-forth across function calls is expensive (pointers are usually just 32-bit or 64-bit numbers). Another is that one can have a pool of resources (think polygons in a large 3d scene), that are marked "used" or "unused". This gets a large performance boost from not having to do the whole malloc/free thing on lots and lots of small objects. Another (this is related to the first), the function can receive a data-structure, and modify it (side effects!) without having to copy it and pass the modified copy back.

I'm intrigued by your mental model. Having not thought it through - it seems as if lat/long is appropriate, but maybe even the idea that it is a coffee shop that you will find there is undetermined. (That is: the fact that it is a coffee shop is one of the things that is interesting about it, like the menu and hours. Again, I need to think this through).

Thanks!

So, I'd like to point out that some of your assumptions about performance may no longer be true. Optimizing compilers are REALLY good now-a-days, but one thing you can do to really trip them up is introduce a bunch of pointers.

It takes very little time to allocate space on the stack and not too much time to copy data from one register to the stack or another register. Very often, if you don't use pointers, the compiler will take your data and throw it into a register and reference that register directly in the method you just called (free).

Now, if you are going to allocate on the heap anyways, then sure, it makes sense to start looking into things like object pools. But that wouldn't be a baseline I'd start with.

Objects with a few ints or longs in them can be passed around free or nearly free with modern compilers.

Here is an example of that concept in action

https://godbolt.org/z/G6r0X6

You really don't get much faster than that.

Note that your model is also an abstraction. Modern architectures move data around between a variety of memory locations (and store it in multiple locations) which are all addressed via the pointer ‘transparently’. It’s not really a memory address anymore and hasn’t been for some time.

That’s not to say your model is bad, it’s the same one I have in my head. But it’s no more ‘real’ than coordinates or library cards or P.O. Box number.

Isn't it still the model that is exposed to the programmer, even though internally all kinds of things are going on to make it all go faster? For example, nowadays many/most processors have separate caches for instructions and data, meaning that they strictly speaking don't conform to the Von Neumann architecture. But the programmer doesn't see the different caches, ideally doesn't even see the cache at all.

It's like the execution model, where processors do a lot of out-of-order execution, but do a lot of work so they can present a model to the programmer as if everything happens in-order.

That depends on the architecture, the os, the compiler & the runtime.

Part of the confusion in teaching pointers (I think) is that we act like they are a lower level abstraction than they are (because they used to be). On modern commodity hardware with mainstream languages pointers have very little to do with memory addresses. Accessing memory via them will not happen in constant time, they may or may not perform better when used, even if the language doesn’t copy them on use the OS or processor might etc.

I just find when I try to teach people the memory address model of pointers there are so many exceptions that the model isn’t helpful. Like the OP I struggle with an alternative.

Agreed. But it depends on the computer. On the old vectorized machines like the Cray Y-MP, it was always just a mental model. On even modern embedded systems w/o virtual memory, it's pretty close to being really real.

(I find that the P.O. Box number thing to be a useful general abstraction for me, but it doesn't seem to convey the concept well to people who are confused. Hence the intent behind the intent of my question: "Does anyone know how to effectively teach pointers?")

I'm semi-convinced the reason many people have a problem understanding pointers is because C makes them needlessly confusing. Or at least in my experience people struggle more with C pointers than they do with learning assembly.
FWIW I struggled with pointers in Pascal before struggling with pointers in C.

I do think one area that causes issues with C is any sort of string manipulation requires a reasonable understanding of pointers, and most introductory programming classes tend to focus on things like string manipulation.

To use that analogy: The coordinates tell you where the restaurant is (pointer), but you still have to go to the actual restaurant to get some food (data).
A better analogy would be the coffee shop (as a physical building) versus the street address of the building. If you want to do anything in the coffee shop you have to go there, the pointer (address) tells you where to go.

And just like real world street addresses, you can't make blind assumptions about pointers.

The value may make logical sense, or it may be completely meaningless and you require direction from someone to find it.

You can't just write down a random address and expect a building to exist at it.

You can hold onto the street address for a coffee shop, put it in a notebook, then one day go to the address to find that the coffee shop was torn down and the street address is invalid.

Do you know what an array is?

If so, then you can think of memory like as a giant array of bytes and a pointer as the index in that array.

Hurray, you now understand pointers :)

Don't muddy it up beyond that.

There are different notions of what an array is.

In some languages, an array is dynamic. You don't have to declare the size. You can just put stuff at any index you desire, and the array will grow as needed. For example, just set foo[1000000000] to 42. That might take a gigabyte or more of RAM, or just address space, or neither.

The indexes might not be required to be numbers. Some languages allow strings or even arbitrary objects as indexes. You could index by a JPEG or a device handle or a float.

The values might not be required to have a consistent type. Some languages would let you throw random different-sized things into an array.

* In some languages, an array is dynamic.

Doesn't really matter for the general concept.

* The indexes might not be required to be numbers.

In most of those languages, that data type is called a map, dictionary, or even associative array. I've seen few languages actually use the phrase "associative array" primarily because it is confusing.

But, to be clear, I'm talking about the common "array" definition. That is, a value indexed by a number.

* The values might not be required to have a consistent type.

Yet, I was clear in saying "a byte array". A pointer points to the byte address and doesn't care about what type is ultimately represented. That is why void pointers are a thing. It is a language level action to reinterpret the pointer into a concrete object type.

But again, that confuses the issue of what pointers are with concerns like memory layout and object sizes. To be clear, you don't need to those concepts to understand what a pointer is.

* Some languages would let you throw random different-sized things into an array.

I specifically said "array of bytes". It does not matter what a language lets you do. A pointer is the head of a byte address and the interpretation of that byte and subsequent bytes are a language level concern. All unneeded information for a discussion on "what is a pointer".

Add to that: you store the index in another cell in the array.