HiveBrain v1.2.0
Get Started
← Back to all entries
patterncppCritical

What are the barriers to understanding pointers and what can be done to overcome them?

Submitted by: @import:stackoverflow-api··
0
Viewed 0 times
arebarriersovercomeanddonethethempointerscanwhat

Problem

Why are pointers such a leading factor of confusion for many new, and even old, college-level students in C or C++? Are there any tools or thought processes that helped you understand how pointers work at the variable, function, and beyond level?

What are some good practice things that can be done to bring somebody to the level of, "Ah-hah, I got it," without getting them bogged down in the overall concept? Basically, drill-like scenarios.

Solution

Pointers is a concept that for many can be confusing at first, in particular when it comes to copying pointer values around and still referencing the same memory block.

I've found that the best analogy is to consider the pointer as a piece of paper with a house address on it, and the memory block it references as the actual house. All sorts of operations can thus be easily explained.

I've added some Delphi code down below, and some comments where appropriate. I chose Delphi since my other main programming language, C#, does not exhibit things like memory leaks in the same way.

If you only wish to learn the high-level concept of pointers, then you should ignore the parts labelled "Memory layout" in the explanation below. They are intended to give examples of what memory could look like after operations, but they are more low-level in nature. However, in order to accurately explain how buffer overruns really work, it was important that I added these diagrams.

Disclaimer: For all intents and purposes, this explanation and the example memory
layouts are vastly simplified. There's more overhead and a lot more details you would
need to know if you need to deal with memory on a low-level basis. However, for the
intents of explaining memory and pointers, it is accurate enough.

Let's assume the THouse class used below looks like this:

type
    THouse = class
    private
        FName : array[0..9] of Char;
    public
        constructor Create(name: PChar);
    end;


When you initialize the house object, the name given to the constructor is copied into the private field FName. There is a reason it is defined as a fixed-size array.

In memory, there will be some overhead associated with the house allocation, I'll illustrate this below like this:

---[ttttNNNNNNNNNN]---
^ ^
| |
| +- the FName array
|
+- overhead

The "tttt" area is overhead, there will typically be more of this for various types of runtimes and languages, like 8 or 12 bytes. It is imperative that whatever values are stored in this area never gets changed by anything other than the memory allocator or the core system routines, or you risk crashing the program.

Allocate memory

Get an entrepreneur to build your house, and give you the address to the house. In contrast to the real world, memory allocation cannot be told where to allocate, but will find a suitable spot with enough room, and report back the address to the allocated memory.

In other words, the entrepreneur will choose the spot.

THouse.Create('My house');


Memory layout:

---[ttttNNNNNNNNNN]---
1234My house

Keep a variable with the address

Write the address to your new house down on a piece of paper. This paper will serve as your reference to your house. Without this piece of paper, you're lost, and cannot find the house, unless you're already in it.

var
    h: THouse;
begin
    h := THouse.Create('My house');
    ...


Memory layout:

h
v
---[ttttNNNNNNNNNN]---
1234My house

Copy pointer value

Just write the address on a new piece of paper. You now have two pieces of paper that will get you to the same house, not two separate houses. Any attempts to follow the address from one paper and rearrange the furniture at that house will make it seem that the other house has been modified in the same manner, unless you can explicitly detect that it's actually just one house.

Note This is usually the concept that I have the most problem explaining to people, two pointers does not mean two objects or memory blocks.

var
    h1, h2: THouse;
begin
    h1 := THouse.Create('My house');
    h2 := h1; // copies the address, not the house
    ...


h1
v
---[ttttNNNNNNNNNN]---
1234My house
^
h2

Freeing the memory

Demolish the house. You can then later on reuse the paper for a new address if you so wish, or clear it to forget the address to the house that no longer exists.

var
    h: THouse;
begin
    h := THouse.Create('My house');
    ...
    h.Free;
    h := nil;


Here I first construct the house, and get hold of its address. Then I do something to the house (use it, the ... code, left as an exercise for the reader), and then I free it. Lastly I clear the address from my variable.

Memory layout:

h

Dangling pointers

You tell your entrepreneur to destroy the house, but you forget to erase the address from your piece of paper. When later on you look at the piece of paper, you've forgotten that the house is no longer there, and goes to visit it, with failed results (see also the part about an invalid reference below).

var
    h: THouse;
begin
    h := THouse.Create('My house');
    ...
    h.Free;
    ... // forgot to clear h here
    h.OpenFrontDoor; // will most likely fail


Using h after the call to .Free might work, but that is just pure luck. Most likely it will fail, at a customers place, in the middle of a critical operation.

h

Code Snippets

type
    THouse = class
    private
        FName : array[0..9] of Char;
    public
        constructor Create(name: PChar);
    end;
THouse.Create('My house');
var
    h: THouse;
begin
    h := THouse.Create('My house');
    ...
var
    h1, h2: THouse;
begin
    h1 := THouse.Create('My house');
    h2 := h1; // copies the address, not the house
    ...
var
    h: THouse;
begin
    h := THouse.Create('My house');
    ...
    h.Free;
    h := nil;

Context

Stack Overflow Q#5727, score: 757

Revisions (0)

No revisions yet.