http://stackoverflow.com/questions/5727/understanding-pointers wrote: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.
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.
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.
Code: Select all
var
h: THouse;
begin
h := THouse.Create;
...
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 seam 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.
Code: Select all
var
h1, h2: THouse;
begin
h1 := THouse.Create;
h2 := h1; // copies the address, not the house
...
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.
Code: Select all
var
h: THouse;
begin
h := THouse.Create;
...
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.
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).
Code: Select all
var
h: THouse;
begin
h := THouse.Create;
...
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.
Memory leak
You lose the piece of paper and cannot find the house. The house is still standing somewhere though, and when you later on want to construct a new house, you cannot reuse that spot.
Code: Select all
var
h: THouse;
begin
h := THouse.Create;
h := THouse.Create; // uh-oh, what happened to our first house?
...
h.Free;
h := nil;
Here we overwrote the contents of the h variable with the address of a new house, but the old one is still standing... somewhere. After this code, there is no way to reach that house, and it will be left standing. In other words, the allocated memory will stay allocated until the application closes, at which point the operating system will tear it down.
A more common way to get this method is just to forget to free something, instead of overwriting it as above. In Delphi terms, this will occur with the following method:
Code: Select all
procedure OpenTheFrontDoorOfANewHouse;
var
h: THouse;
begin
h := THouse.Create;
h.OpenFrontDoor;
// uh-oh, no .Free here, where does the address go?
end;
After this method has executed, there's no place in our variables that the address to the house exists, but the house is still out there.
Freeing the memory but keeping a (now invalid) reference
Demolish the house, erase one of the pieces of paper but you also have another piece of paper with the old address on it, when you go to the address, you won't find a house, but you might find something that resembles the ruins of one.
Perhaps you will even find a house, but it is not the house you were originally given the address to, and thus any attempts to use it as though it belongs to you might fail horribly.
Sometimes you might even find that a neighbouring address has a rather big house set up on it that occupies three address (Main Street 1-3), and your address goes to the middle of the house. Any attempts to treat that part of the large 3-address house as a single small house might also fail horribly.
Code: Select all
var
h1, h2: THouse;
begin
h1 := THouse.Create;
h2 := h1; // copies the address, not the house
...
h1.Free;
h1 := nil;
h2.OpenFrontDoor; // uh-oh, what happened to our house?
Here the house was torn down, through the reference in h1, and while h1 was cleared as well, h2 still has the old, out-of-date, address. Access to the house that is no longer standing might or might not work.
Buffer overrun
You move more stuff into the house than you can possibly fit, spilling into the neighbours house or yard. When the owner of that neighbouring house later on comes home, he'll find all sorts of things he'll consider his own.
(hard to give a concrete example to, presumably, the THouse type has been written correctly, will get back to this one).
Linked Lists
When you follow an address on a piece of paper, you get to a house, and at that house there is another piece of paper with a new address on it, for the next house in the chain, and so on.
Code: Select all
var
h1, h2: THouse;
begin
h1 := THouse.Create('Home');
h2 := THouse.Create('Cabin');
h1.NextHouse := h2;
Here we create a link from our home house to our cabin. We can follow the chain until a house has no NextHouse reference, which means it's the last one. To visit all our houses, we could use the following code:
Code: Select all
var
h1, h2: THouse;
h: THouse;
begin
h1 := THouse.Create('Home');
h2 := THouse.Create('Cabin');
h1.NextHouse := h2;
...
h := h1;
while h <> nil do
begin
h.LockAllDoors;
h.CloseAllWindows;
h := h.NextHouse;
end;