In C++ I Cannot Grasp Pointers and Classes - c++

I'm fresh out of college and have been working in C++ for some time now. I understand all the basics of C++ and use them, but I'm having a hard time grasping more advanced topics like pointers and classes. I've read some books and tutorials and I understand the examples in them, but then when I look at some advanced real life examples I cannot figure them out. This is killing me because I feel like its keeping me from bring my C++ programming to the next level. Did anybody else have this problem? If so, how did you break through it?
Does anyone know of any books or tutorials that really describe pointers and class concepts well?
or maybe some example code with good descriptive comments using advanced pointers and class techniques?
any help would be greatly appreciated.

Understanding Pointers in C/C++
Before one can understand how pointers work, it is necessary to understand how variables are stored and accessed in programs. Every variable has 2 parts to it - (1) the memory address where the data is stored and (2) the value of the data stored.
The memory address is often referred to as the lvalue of a variable, and the value of the data stored is referred to as the rvalue (l and r meaning left and right).
Consider the statement:
int x = 10;
Internally, the program associates a memory address with the variable x. In this case, let's assume that the program assigns x to reside at the address 1001 (not a realistic address, but chosen for simplicity). Therefore, the lvalue (memory address) of x is 1001, and the rvalue (data value) of x is 10.
The rvalue is accessed by simply using the variable “x”. In order to access the lvalue, the “address of” operator (‘&’) is needed. The expression ‘&x’ is read as "the address of x".
Expression Value
----------------------------------
x 10
&x 1001
The value stored in x can be changed at any time (e.g. x = 20), but the address of x (&x) can never be changed.
A pointer is simply a variable that can be used to modify another variable. It does this by having a memory address for its rvalue. That is, it points to another location in memory.
Creating a pointer to “x” is done as follows:
int* xptr = &x;
The “int*” tells the compiler that we are creating a pointer to an integer value. The “= &x” part tells the compiler that we are assigning the address of x to the rvalue of xptr. Thus, we are telling the compiler that xptr “points to” x.
Assuming that xptr is assigned to a memory address of 1002, then the program’s memory might look like this:
Variable lvalue rvalue
--------------------------------------------
x 1001 10
xptr 1002 1001
The next piece of the puzzle is the "indirection operator" (‘*’), which is used as follows:
int y = *xptr;
The indirection operator tells the program to interpret the rvalue of xptr as a memory address rather than a data value. That is, the program looks for the data value (10) stored at the address provided by xptr (1001).
Putting it all together:
Expression Value
--------------------------------------------
x 10
&x 1001
xptr 1001
&xptr 1002
*xptr 10
Now that the concepts have been explained, here is some code to demonstrate the power of pointers:
int x = 10;
int *xptr = &x;
printf("x = %d\n", x);
printf("&x = %d\n", &x);
printf("xptr = %d\n", xptr);
printf("*xptr = %d\n", *xptr);
*xptr = 20;
printf("x = %d\n", x);
printf("*xptr = %d\n", *xptr);
For output you would see (Note: the memory address will be different each time):
x = 10
&x = 3537176
xptr = 3537176
*xptr = 10
x = 20
*xptr = 20
Notice how assigning a value to ‘*xptr’ changed the value of ‘x’. This is because ‘*xptr’ and ‘x’ refer to the same location in memory, as evidenced by ‘&x’ and ‘xptr’ having the same value.

Pointers and classes aren't really advanced topics in C++. They are pretty fundamental.
For me, pointers solidified when I started drawing boxes with arrows. Draw a box for an int. And int* is now a separate box with an arrow pointing to the int box.
So:
int foo = 3; // integer
int* bar = &foo; // assigns the address of foo to my pointer bar
With my pointer's box (bar) I have the choice of either looking at the address inside the box. (Which is the memory address of foo). Or I can manipulate whatever I have an address to. That manipulation means I'm following that arrow to the integer (foo).
*bar = 5; // asterix means "dereference" (follow the arrow), foo is now 5
bar = 0; // I just changed the address that bar points to
Classes are another topic entirely. There's some books on object oriented design, but I don't know good ones for beginners of the top of my head. You might have luck with an intro Java book.

This link has a video describing how pointers work, with claymation. Informative, and easy to digest.
This page has some good information on the basic of classes.

I used to have a problem understand pointers in pascal way back :) Once i started doing assembler pointers was really the only way to access memory and it just hit me. It might sound like a far shot, but trying out assembler (which is always a good idea to try and understand what computers is really about) probably will teach you pointers. Classes - well i don't understand your problem - was your schooling pure structured programming? A class is just a logical way of looking at real life models - you're trying to solve a problem which could be summed up in a number of objects/classes.

Pointers and classes are completely different topics so I wouldn't really lump them in together like this. Of the two, I would say pointers are more fundamental.
A good exercise for learning about what pointers are is the following:
create a linked list
iterate through it from start to finish
reverse it so that the head is now the back and the back is now the head
Do it all on a whiteboard first. If you can do this easily, you should have no more problems understanding what pointers are.

Pointers already seem to be addressed (no pun intended) in other answers.
Classes are fundamental to OO. I had tremendous trouble wrenching my head into OO - like, ten years of failed attempts. The book that finally helped me was Craig Larman's "Applying UML and Patterns". I know it sounds as if it's about something different, but it really does a great job of easing you into the world of classes and objects.

We were just discussing some of the aspects of C++ and OO at lunch, someone (a great engineer actually) was saying that unless you have a really strong programming background before you learn C++, it will literally ruin you.
I highly recommend learning another language first, then shifting to C++ when you need it. It's not like there is anything great about pointers, they are simply a vestigial piece left over from when it was difficult for a compiler convert operations to assembly efficiently without them.
These days if a compiler can't optimize an array operation better then you can using pointers, your compiler is broken.
Please don't get me wrong, I'm not saying C++ is horrible or anything and don't want to start an advocacy discussion, I've used it and use it occasionally now, I'm just recommending you start with something else.
It's really NOT like learning to drive a manual car then easily being able to apply that to an automatic, it's more like learning to drive on one of those huge construction cranes then assuming that will apply when you start to drive a car--then you find yourself driving your car down the middle of the street at 5mph with your emergency lights on.
[edit] reviewing that last paragraph--I think that may have been my most accurate analogy ever!

To understand pointers, I can't recommend the K&R book highly enough.

The book that cracked pointers for me was Illustrating Ansi C by Donald Alcock. Its full of hand-drawn-style box and arrow diagrams that illustrate pointers, pointer arithmetic, arrays, string functions etc...
Obviously its a 'C' book but for core fundamentals its hard to beat

From lassevek's response to a similar question on SO:
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:
Copy pointer value, just write the address on a new piece of paper
Linked lists, piece of paper at the house with the address of the next
house on it
Freeing the memory, demolish the house and erase the address
Memory leak, you lose the piece of paper and cannot find the house
Freeing the memory but keeping a (now invalid) reference, demolish the
house, erase one of the pieces of
paper but 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
Buffer overrun, you move more stuff into the house than you can
possibly fit, spilling into the
neighbours house

For Pointers:
I found this post had very thoughtful discussion about pointers. Maybe that would help. Are you familar with refrences such as in C#? That is something that actually refers to something else? Thats probably a good start for understanding pointers.
Also, look at Kent Fredric's post below on another way to introduce yourself to pointers.

Learn assembly language and then learn C. Then you will know what the underlying principles of machine are (and thefore pointers).
Pointers and classes are fundamental aspects of C++. If you don't understand them then it means that you don't really understand C++.
Personally I held back on C++ for several years until I felt I had a firm grasp of C and what was happening under the hood in assembly language. Although this was quite a long time ago now I think it really benefited my career to understand how the computer works at a low-level.
Learning to program can take many years, but you should stick with it because it is a very rewarding career.

For pointers and classes, here is my analogy. I'll use a deck of cards. The deck of cards has a face value and a type (9 of hearts, 4 of spades, etc.). So in our C++ like programming language of "Deck of Cards" we'll say the following:
HeartCard card = 4; // 4 of hearts!
Now, you know where the 4 of hearts is because by golly, you're holding the deck, face up in your hand, and it's at the top! So in relation to the rest of the cards, we'll just say the 4 of hearts is at BEGINNING. So, if I asked you what card is at BEGINNING, you would say, "The 4 of hearts of course!". Well, you just "pointed" me to where the card is. In our "Deck of Cards" programming language, you could just as well say the following:
HeartCard card = 4; // 4 of hearts!
print &card // the address is BEGINNING!
Now, turn your deck of cards over. The back side is now BEGINNING and you don't know what the card is. But, let's say you can make it whatever you want because you're full of magic. Let's do this in our "Deck of Cards" langauge!
HeartCard *pointerToCard = MakeMyCard( "10 of hearts" );
print pointerToCard // the value of this is BEGINNING!
print *pointerToCard // this will be 10 of hearts!
Well, MakeMyCard( "10 of hearts" ) was you doing your magic and knowing that you wanted to point to BEGINNING, making the card a 10 of hearts! You turn your card over and, voila! Now, the * may throw you off. If so, check this out:
HeartCard *pointerToCard = MakeMyCard( "10 of hearts" );
HeartCard card = 4; // 4 of hearts!
print *pointerToCard; // prints 10 of hearts
print pointerToCard; // prints BEGINNING
print card; // prints 4 of hearts
print &card; // prints END - the 4 of hearts used to be on top but we flipped over the deck!
As for classes, we've been using classes in the example by defining a type as HeartCard. We know what a HeartCard is... It's a card with a value and the type of heart! So, we've classified that as a HeartCard. Each language has a similar way of defining or "classifying" what you want, but they all share the same concept! Hope this helped...

In the case of classes I had three techniques that really helped me make the jump into real object oriented programming.
The first was I worked on a game project that made heavy use of classes and objects, with heavy use of generalization (kind-of or is-a relationship, ex. student is a kind of person) and composition (has-a relationship, ex. student has a student loan). Breaking apart this code took a lot of work, but really brought things into perspective.
The second thing that helped was in my System Analysis class, where I had to make http://www.agilemodeling.com/artifacts/classDiagram.htm">UML class diagrams. These I just really found helped me understand the structure of classes in a program.
Lastly, I help tutor students at my college in programming. All I can really say about this is you learn a lot by teaching and by seeing other people's approach to a problem. Many times a student will try things that I would never have thought of, but usually make a lot of sense and they just have problems implementing their idea.
My best word of advice is it takes a lot of practice, and the more you program the better you will understand it.

In a sense, you can consider "pointers" to be one of the two most fundamental types in software - the other being "values" (or "data") - that exist in a huge block of uniquely-addressable memory locations. Think about it. Objects and structs etc don't really exist in memory, only values and pointers do. In fact, a pointer is a value too....the value of a memory address, which in turn contains another value....and so on.
So, in C/C++, when you declare an "int" (intA), you are defining a 32bit chunk of memory that contains a value - a number. If you then declare an "int pointer" (intB), you are defining a 32bit chunk of memory that contains the address of an int. I can assign the latter to point to the former by stating "intB = &intA", and now the 32bits of memory defined as intB, contains an address corresponding to intA's location in memory.
When you "dereference" the intB pointer, you are looking at the address stored within intB's memory, finding that location, and then looking at the value stored there (a number).
Commonly, I have encountered confusion when people lose track of exactly what it is they're dealing with as they use the "&", "*" and "->" operators - is it an address, a value or what? You just need to keep focused on the fact that memory addresses are simply locations, and that values are the binary information stored there.

There's no substitute for practicing.
It's easy to read through a book or listen to a lecture and feel like you're following what's going on.
What I would recommend is taking some of the code examples (I assume you have them on disk somewhere), compile them and run them, then try to change them to do something different.
Add another subclass to a hierarchy
Add a method to an existing class
Change an algorithm that iterates
forward through a collection to go
backward instead.
I don't think there's any "silver bullet" book that's going to do it.
For me, what drove home what pointers meant was working in assembly, and seeing that a pointer was actually just an address, and that having a pointer didn't mean that what it pointed to was a meaningful object.

The best book I've read on these topics is Thinking in C++ by Bruce Eckel. You can download it for free here.

For classes:
The breakthru moment for me was when I learned about interfaces. The idea of abstracting away the details of how you wrote solved a problem, and giving just a list of methods that interact with the class was very insightful.
In fact, my professor explicitly told us that he would grade our programs by plugging our classes into his test harness. Grading would be done based on the requirements he gave to us and whether the program crashed.
Long story short, classes let you wrap up functionality and call it in a cleaner manner (most of the time, there are always exceptions)

One of the things that really helped me understand these concepts is to learn UML - the Unified Modeling Language. Seeing concepts of object-oriented design in a graphical format really helped me learn what they mean. Sometimes trying to understand these concepts purely by looking at what source code implements them can be difficult to comprehend.
Seeing object-oriented paradigms like inheritance in graphical form is a very powerful way to grasp the concept.
Martin Fowler's UML Distilled is a good, brief introduction.

Pretend a pointer is an array address.
x = 500; // memory address for hello;
MEMORY[x] = "hello";
print MEMORY[x];
its a graphic oversimplification, but for the most part as long as you never want to know what that number is or set it by hand you should be fine.
Back when I understood C I had a few macros I had which more or less permitted you to use pointers just like they were an array index in memory. But I've long since lost that code and long since forgotten.
I recall it started with
#define MEMORY 0;
#define MEMORYADDRESS( a ) *a;
and that on its own is hardly useful. Hopefully somebody else can expand on that logic.

Classes are relatively easy to grasp; OOP can take you many years. Personally, I didn't fully grasp true OOP until last year-ish. It is too bad that Smalltalk isn't as widespread in colleges as it should be. It really drives home the point that OOP is about objects trading messages, instead of classes being self-contained global variables with functions.
If you truly are new to classes, then the concept can take a while to grasp. When I first encountered them in 10th grade, I didn't get it until I had someone who knew what they were doing step through the code and explain what was going on. That is what I suggest you try.

To better understand pointers, I think, it may be useful to look at how the assembly language works with pointers. The concept of pointers is really one of the fundamental parts of the assembly language and x86 processor instruction architecture. Maybe it'll kind of let you fell like pointers are a natural part of a program.
As to classes, aside from the OO paradigm I think it may be interesting to look at classes from a low-level binary perspective. They aren't that complex in this respect on the basic level.
You may read Inside the C++ Object Model if you want to get a better understanding of what is underneath C++ object model.

The point at which I really got pointers was coding TurboPascal on a FatMac (around 1984 or so) - which was the native Mac language at the time.
The Mac had an odd memory model whereby when allocated the address the memory was stored in a pointer on the heap, but the location of that itself was not guaranteed and instead the memory handling routines returned a pointer to the pointer - referred to as a handle. Consequently to access any part of the allocated memory it was necessary to dereference the handle twice. It took a while, but constant practice eventually drove the lesson home.
Pascal's pointer handling is easier to grasp than C++, where the syntax doesn't help the beginner. If you are really and truly stuck understanding pointers in C then your best option might be to obtain a copy a a Pascal compiler and try writing some basic pointer code in it (Pascal is near enough to C you'll get the basics in a few hours). Linked lists and the like would be a good choice. Once you're comfortable with those return to C++ and with the concepts mastered you'll find that the cliff won't look so steep.

Did you read Bjarne Stroustrup's The C++ Programming Language? He created C++.
The C++ FAQ Lite is also good.

You may find this article by Joel instructive. As an aside, if you've been "working in C++ for some time" and have graduated in CS, you may have gone to a JavaSchool (I'd argue that you haven't been working in C++ at all; you've been working in C but using the C++ compiler).
Also, just to second the answers of hojou and nsanders, pointers are very fundamental to C++. If you don't understand pointers, then you don't understand the basics of C++ (acknowledging this fact is the beginning of understanding C++, by the way). Similarly, if you don't understand classes, then you don't understand the basics of C++ (or OO for that matter).
For pointers, I think drawing with boxes is a fine idea, but working in assembly is also a good idea. Any instructions that use relative addressing will get you to an understanding of what pointers are rather quickly, I think.
As for classes (and object-oriented programming more generally), I would recommend Stroustrups "The C++ Programming Language" latest edition. Not only is it the canonical C++ reference material, but it also has quite a bit of material on a lot of other things, from basic object-oriented class hierarchies and inheritance all the way up to design principles in large systems. It's a very good read (if not a little thick and terse in spots).

Pointers are not some sort of magical stuff, you're using them all the time!
When you say:
int a;
and the compiler generates storage for 'a', you're practically saying that you're declaringan int and you want to name its memory location 'a'.
When you say:
int *a;
you're declaring a variable that can hold a memory location of an int.
It's that simple. Also, don't be scared about pointer arithmetics, just always
have in mind a "memory map" when you're dealing with pointers and think in terms
of walking through memory addresses.
Classes in C++ are just one way of defining abstract data types. I'd suggest reading a good OOP book to understand the concept, then, if you're interested, learn how C++ compilers generate code to simulate OOP. But this knowledge will come in time, if you stick with C++ long enough :)

Your problem seems to be the C core in C++, not C++ itself. Get yourself the Kernighan & Ritchie (The C Programming Language). Inhale it. It's very good stuff, one of the best programming language books ever written.

Related

I am trying to sort an array with pointers

I am trying to sort an array with a pointer. This is what I have so far. This is pretty much the example ripped form the textbook, though the example in the text does not include
std::copy(net, net+SIZE, net2);
void pointer(void) {
int j,i;
std::copy(net, net+SIZE, net2);
//int *p[SIZE];
float temp;
int sortedflag=0;
//for (i=0;i<SIZE;i++) net2[i]=net+i;
for(i=0;i<SIZE;i++)cout<<*net2[i]<<"";
while (!sortedflag){
sortedflag=1;
for(j=0;j<SIZE-1;j++){
if(*net2[j]>*net2[j+i]){
temp=net2[j];
net2[j]=net2[j+1];
net2[j+1]=temp;
sortedflag=0;
}
}
}
full code
http://pastebin.com/rYYp3vrR
the error I keep getting is
cannot convert float to *float
I understand why this is but I am completely lost as to a solution. I have been searching the web for the past week for solutions.
Also Bonus points if you can explain practical uses for pointers. This is almost certainly inexperience but it just seems like pointers make the program needlessly complex and less secure.
float temp should read float *temp - you need to temporarily store a pointer, not a float.
You are right, there is little point in using pointers in this example. Suppose you were trying to sort objects that were extremely large; shuffling the objects would then take a lot more time than shuffling pointers to them.
There are lots of uses of pointers (ideally of the smart kind -shared_ptr, unique_ptr etc). It is often said, only partly in jest, that there is no problem in computer science that can't be solved with another level of indirection, and pointers are one way of achieving that indirection.
To elaborate on Alan's comments of shuffling, take for example a sorting algorithm like Merge Sort.
Generally, merge sorting uses a copy of the array that you're sorting to help in the merge process. But with pointers, e.g. a linked list implementation, you can merge sort all of your data without having to bring it into the memory that your program (process) uses.
Or, take for example moving a file on your computer. Your file system (more than likely) only changes the pointer to that file on your HDD, it won't physically move it.
(I know this is not a direct programming example, but hopefully it gives more clarity to the idea of pointers as a whole since it is a huge aspect of understanding programming.)
I don't have the requisite points to comment, so I hope you'll forgive this post listed as an answer.

How to backtrack a pointer?

Let say I have 2 pointers pointing to the same memory location. If I know what the address it is, how can I find out what pointers are pointing to that location?
int x=5;
int* p1=&x;
int* p2=&x;
How do I get the address of p1 and p2? Is it possible to even do this in C/C++? If not then is it possible to search through all pointers and see which ones have the value of &x?
No, its not possible to "backtrack" a pointer in C or C++ (a good rule of thumb is if a feature has big hidden performance costs, then its not present in C or C++)
As for the second approach (going through memory looking for pointers), that is precisely what some tools like the Boehm garbage collector do. However, not only is this process inneficient and not portable but it also can lead to "false positives" since you can't tell if a byte pattern in memory is a real pointer or something else like a regular integer or part of a string.
Anyway, you should ask yourself what is the real problem you need to solve instead of trying to hack a garbage collector on your own. Depending on what you want to do there are many ways to approach it in C++ (RAII, smart pointers, etc)

Reasons to not pass simple types by reference?

So far as I understand you should not pass simple types by reference in c++ because it does not improve perfomance, it's even bad for performance(?). At least thats what I managed to gather from the net.
But I can't find out the reason why it's bad for performance, is it because it's quicker for c++ to just create a new simple type than it it is too look up variable or what is it?
If you create a reference, it's:
pointer to memory location -> memory location
If you use a value, it's:
memory location
Since a value has to be copied either way (the reference or the value), passing by reference does not improve performance; one extra lookup has to be made. So it theoretically "worsens" performance, but not by any amount you'll ever notice.
It's a good question and the fact that you're asking it shows that you're paying attention to your code. However, the good news is that in this particular case, there's an easy way out.
This excellent article by Dave Abrahms answers all your questions and then some: Want Speed? Pass by Value.
Honestly, it does not do the link justice to summarize it, it's a real must-read. However, to make a long story short, your compiler is smart enough to do it correctly and if you try doing it manually, you may prevent your compiler from doing certain optimizations.
Internally references are treated at pointers, which need to be dereferenced each time you access them. That obviously requires additional operations.
For example, in 32 bit mode, int size is 4 bytes and int * pointer size is 4 bytes.
Passing 4 bytes int directly is quicker, than passing 4 byte pointer and then loading int by that pointer.

C++ Pointer Snippet

Greetings everyone. This is my first question here at stackoverflow so please bear with me.
My programming class this semester is Java; last semester was C++. My Java teacher feels (justifiably, I think) that it is very important for we students to understand the mechanics of memory management.
Since Java has automatic garbage collection, he has seen fit to give us an assignment in which we must write a very basic program in C++ that creates a two-dimensional array using pointers. Specifically, we are to first create an array of pointers; each pointer in the first array should reference its own array of integers. Then we must deallocate the memory associated with the two arrays.
This assignment is supposed to consist of two functions: one to allocate the 2-D array, and a second to deallocate. I just want to make sure that the following code is logically sound before I proceed.
I'm sure this all seems very simple, but the hitch is that my C++ teacher spent all of two days on pointers. While I somewhat understand the mechanics, I am pretty clueless on implementation. That being said, the following is a very rough start. Is this logically sound? Am I completely off the mark? My most profound thanks in advance for any help.
EDIT: I have created a new question with updated code. You can view it by clicking Here.
When you use
int* i = new int;
you pair it with
delete i;
and when you use
int* i = new int [12];
you pair it with
delete [] i;
If there are brackets in the new, there should be brackets in the delete. Otherwise, your program looks reasonable to me, except that you haven't implemented those two functions that your prof wants you to.
Looks correct to me, with one exception - when you delete arrays you need the following syntax:
delete [] arrayName;
That's a well-asked question.
I don't think I'd call it a "2-D array": it's an array of arrays, not a 2-D array.
I think I'd call my index i or iColumn or iRow instead of nCount (your nRows and nColumns are logically const and used as fencepost/high-water-mark values, whereas your nCount is a loop index).
For bonus points, think about how to test your solution. You can run it to see if it faults ... but the converse, i.e. not faulting, isn't proof that it's correct. What O/S are you running it on? If you're using Linux then a worthwhile test is to run your code using valgrind (because when you run it valgrind can automatically detect a lot of the ways in which it's possible to misuse memory).
You need to use delete [] instead of just delete.
It looks sound(logically).
By the way - it's ok to run a program and have it fail. :-)

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

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 9 years ago.
Improve this question
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.
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 <--+
v +- before free
---[ttttNNNNNNNNNN]--- |
1234My house <--+
h (now points nowhere) <--+
+- after free
---------------------- | (note, memory might still
xx34My house <--+ contain some data)
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 <--+
v +- before free
---[ttttNNNNNNNNNN]--- |
1234My house <--+
h <--+
v +- after free
---------------------- |
xx34My house <--+
As you can see, h still points to the remnants of the data in memory, but
since it might not be complete, using it as before might fail.
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.
var
h: THouse;
begin
h := THouse.Create('My house');
h := THouse.Create('My house'); // 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.
Memory layout after first allocation:
h
v
---[ttttNNNNNNNNNN]---
1234My house
Memory layout after second allocation:
h
v
---[ttttNNNNNNNNNN]---[ttttNNNNNNNNNN]
1234My house 5678My house
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:
procedure OpenTheFrontDoorOfANewHouse;
var
h: THouse;
begin
h := THouse.Create('My house');
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.
Memory layout:
h <--+
v +- before losing pointer
---[ttttNNNNNNNNNN]--- |
1234My house <--+
h (now points nowhere) <--+
+- after losing pointer
---[ttttNNNNNNNNNN]--- |
1234My house <--+
As you can see, the old data is left intact in memory, and will not
be reused by the memory allocator. The allocator keeps track of which
areas of memory has been used, and will not reuse them unless you
free it.
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.
var
h1, h2: THouse;
begin
h1 := THouse.Create('My house');
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.
This is a variation of the dangling pointer above. See its memory layout.
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.
This is the reason I chose a fixed-size array. To set the stage, assume that
the second house we allocate will, for some reason, be placed before the
first one in memory. In other words, the second house will have a lower
address than the first one. Also, they're allocated right next to each other.
Thus, this code:
var
h1, h2: THouse;
begin
h1 := THouse.Create('My house');
h2 := THouse.Create('My other house somewhere');
^-----------------------^
longer than 10 characters
0123456789 <-- 10 characters
Memory layout after first allocation:
h1
v
-----------------------[ttttNNNNNNNNNN]
5678My house
Memory layout after second allocation:
h2 h1
v v
---[ttttNNNNNNNNNN]----[ttttNNNNNNNNNN]
1234My other house somewhereouse
^---+--^
|
+- overwritten
The part that will most often cause crash is when you overwrite important parts
of the data you stored that really should not be randomly changed. For instance
it might not be a problem that parts of the name of the h1-house was changed,
in terms of crashing the program, but overwriting the overhead of the
object will most likely crash when you try to use the broken object,
as will overwriting links that is stored to
other objects in the object.
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.
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:
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;
Memory layout (added NextHouse as a link in the object, noted with
the four LLLL's in the below diagram):
h1 h2
v v
---[ttttNNNNNNNNNNLLLL]----[ttttNNNNNNNNNNLLLL]
1234Home + 5678Cabin +
| ^ |
+--------+ * (no link)
In basic terms, what is a memory address?
A memory address is in basic terms just a number. If you think of memory
as a big array of bytes, the very first byte has the address 0, the next one
the address 1 and so on upwards. This is simplified, but good enough.
So this memory layout:
h1 h2
v v
---[ttttNNNNNNNNNN]---[ttttNNNNNNNNNN]
1234My house 5678My house
Might have these two address (the leftmost - is address 0):
h1 = 4
h2 = 23
Which means that our linked list above might actuall look like this:
h1 (=4) h2 (=28)
v v
---[ttttNNNNNNNNNNLLLL]----[ttttNNNNNNNNNNLLLL]
1234Home 0028 5678Cabin 0000
| ^ |
+--------+ * (no link)
It is typical to store an address that "points nowhere" as a zero-address.
In basic terms, what is a pointer?
A pointer is just a variable holding a memory address. You can typically ask the programming
language to give you its number, but most programming languages and runtimes tries to
hide the fact that there is a number beneath, just because the number itself does not
really hold any meaning to you. It is best to think of a pointer as a black box, ie.
you don't really know or care about how it is actually implemented, just as long as it
works.
In my first Comp Sci class, we did the following exercise. Granted, this was a lecture hall with roughly 200 students in it...
Professor writes on the board: int john;
John stands up
Professor writes: int *sally = &john;
Sally stands up, points at john
Professor: int *bill = sally;
Bill stands up, points at John
Professor: int sam;
Sam stands up
Professor: bill = &sam;
Bill now points to Sam.
I think you get the idea. I think we spent about an hour doing this, until we went over the basics of pointer assignment.
An analogy I've found helpful for explaining pointers is hyperlinks. Most people can understand that a link on a web page 'points' to another page on the internet, and if you can copy & paste that hyperlink then they will both point to the same original web page. If you go and edit that original page, then follow either of those links (pointers) you'll get that new updated page.
The reason pointers seem to confuse so many people is that they mostly come with little or no background in computer architecture. Since many don't seem to have an idea of how computers (the machine) is actually implemented - working in C/C++ seems alien.
A drill is to ask them to implement a simple bytecode based virtual machine (in any language they chose, python works great for this) with an instruction set focussed on pointer operations (load, store, direct/indirect addressing). Then ask them to write simple programs for that instruction set.
Anything requiring slightly more than simple addition is going to involve pointers and they are sure to get it.
Why are pointers such a leading factor of confusion for many new, and even old, college level students in the C/C++ language?
The concept of a placeholder for a value - variables - maps onto something we're taught in school - algebra. There isn't an existing parallel you can draw without understanding how memory is physically laid out within a computer, and no one thinks about this kind of thing until they're dealing with low level things - at the C/C++/byte communications level.
Are there any tools or thought processes that helped you understand how pointers work at the variable, function, and beyond level?
Addresses boxes. I remember when I was learning to program BASIC into microcomputers, there were these pretty books with games in them, and sometimes you had to poke values into particular addresses. They had a picture of a bunch of boxes, incrementally labelled with 0, 1, 2... and it was explained that only one small thing (a byte) could fit in these boxes, and there were a lot of them - some computers had as many as 65535! They were next to each other, and they all had an address.
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.
For a drill? Make a struct:
struct {
char a;
char b;
char c;
char d;
} mystruct;
mystruct.a = 'r';
mystruct.b = 's';
mystruct.c = 't';
mystruct.d = 'u';
char* my_pointer;
my_pointer = &mystruct.b;
cout << 'Start: my_pointer = ' << *my_pointer << endl;
my_pointer++;
cout << 'After: my_pointer = ' << *my_pointer << endl;
my_pointer = &mystruct.a;
cout << 'Then: my_pointer = ' << *my_pointer << endl;
my_pointer = my_pointer + 3;
cout << 'End: my_pointer = ' << *my_pointer << endl;
Same example as above, except in C:
// Same example as above, except in C:
struct {
char a;
char b;
char c;
char d;
} mystruct;
mystruct.a = 'r';
mystruct.b = 's';
mystruct.c = 't';
mystruct.d = 'u';
char* my_pointer;
my_pointer = &mystruct.b;
printf("Start: my_pointer = %c\n", *my_pointer);
my_pointer++;
printf("After: my_pointer = %c\n", *my_pointer);
my_pointer = &mystruct.a;
printf("Then: my_pointer = %c\n", *my_pointer);
my_pointer = my_pointer + 3;
printf("End: my_pointer = %c\n", *my_pointer);
Output:
Start: my_pointer = s
After: my_pointer = t
Then: my_pointer = r
End: my_pointer = u
Perhaps that explains some of the basics through example?
The reason I had a hard time understanding pointers, at first, is that many explanations include a lot of rubbish about passing by reference. All this does is confuse the issue. When you use a pointer parameter, you're still passing by value; but the value happens to be an address rather than, say, an int.
Someone else has already linked to this tutorial, but I can highlight the moment when I began to understand pointers:
A Tutorial on Pointers and Arrays in C: Chapter 3 - Pointers and Strings
int puts(const char *s);
For the moment, ignore the const. The parameter passed to puts() is a pointer, that is the value of a pointer (since all parameters in C are passed by value), and the value of a pointer is the address to which it points, or, simply, an address. Thus when we write puts(strA); as we have seen, we are passing the address of strA[0].
The moment I read these words, the clouds parted and a beam of sunlight enveloped me with pointer understanding.
Even if you're a VB .NET or C# developer (as I am) and never use unsafe code, it's still worth understanding how pointers work, or you won't understand how object references work. Then you'll have the common-but-mistaken notion that passing an object reference to a method copies the object.
I found Ted Jensen's "Tutorial on Pointers and Arrays in C" an excellent resource for learning about pointers. It is divided into 10 lessons, beginning with an explanation of what pointers are (and what they're for) and finishing with function pointers. http://web.archive.org/web/20181011221220/http://home.netcom.com:80/~tjensen/ptr/cpoint.htm
Moving on from there, Beej's Guide to Network Programming teaches the Unix sockets API, from which you can begin to do really fun things. http://beej.us/guide/bgnet/
The complexities of pointers go beyond what we can easily teach. Having students point to each other and using pieces of paper with house addresses are both great learning tools. They do a great job of introducing the basic concepts. Indeed, learning the basic concepts is vital to successfully using pointers. However, in production code, it's common to get into much more complex scenarios than these simple demonstrations can encapsulate.
I've been involved with systems where we had structures pointing to other structures pointing to other structures. Some of those structures also contained embedded structures (rather than pointers to additional structures). This is where pointers get really confusing. If you've got multiple levels of indirection, and you start ending up with code like this:
widget->wazzle.fizzle = fazzle.foozle->wazzle;
it can get confusing really quickly (imagine a lot more lines, and potentially more levels). Throw in arrays of pointers, and node to node pointers (trees, linked lists) and it gets worse still. I've seen some really good developers get lost once they started working on such systems, even developers who understood the basics really well.
Complex structures of pointers don't necessarily indicate poor coding, either (though they can). Composition is a vital piece of good object-oriented programming, and in languages with raw pointers, it will inevitably lead to multi-layered indirection. Further, systems often need to use third-party libraries with structures which don't match each other in style or technique. In situations like that, complexity is naturally going to arise (though certainly, we should fight it as much as possible).
I think the best thing colleges can do to help students learn pointers is to to use good demonstrations, combined with projects that require pointer use. One difficult project will do more for pointer understanding than a thousand demonstrations. Demonstrations can get you a shallow understanding, but to deeply grasp pointers, you have to really use them.
I don't think pointers as a concept are particularly tricky - most students' mental models map to something like this and some quick box sketches can help.
The difficulty, at least that which I've experienced in the past and seen others deal with, is that the management of pointers in C/C++ can be unncessarily convoluted.
I thought I'd add an analogy to this list that I found very helpful when explaining pointers (back in the day) as a Computer Science Tutor; first, let's:
Set the stage:
Consider a parking lot with 3 spaces, these spaces are numbered:
-------------------
| | | |
| 1 | 2 | 3 |
| | | |
In a way, this is like memory locations, they are sequential and contiguous.. sort of like an array. Right now there are no cars in them so it's like an empty array (parking_lot[3] = {0}).
Add the data
A parking lot never stays empty for long... if it did it would be pointless and no one would build any. So let's say as the day moves on the lot fills up with 3 cars, a blue car, a red car, and a green car:
1 2 3
-------------------
| o=o | o=o | o=o |
| |B| | |R| | |G| |
| o-o | o-o | o-o |
These cars are all the same type (car) so one way to think of this is that our cars are some sort of data (say an int) but they have different values (blue, red, green; that could be an color enum)
Enter the pointer
Now if I take you into this parking lot, and ask you to find me a blue car, you extend one finger and use it to point to a blue car in spot 1. This is like taking a pointer and assigning it to a memory address (int *finger = parking_lot)
Your finger (the pointer) is not the answer to my question. Looking at your finger tells me nothing, but if I look where you're finger is pointing to (dereferencing the pointer), I can find the car (the data) I was looking for.
Reassigning the pointer
Now I can ask you to find a red car instead and you can redirect your finger to a new car. Now your pointer (the same one as before) is showing me new data (the parking spot where the red car can be found) of the same type (the car).
The pointer hasn't physically changed, it's still your finger, just the data it was showing me changed. (the "parking spot" address)
Double pointers (or a pointer to a pointer)
This works with more than one pointer as well. I can ask where is the pointer, which is pointing to the red car and you can use your other hand and point with a finger to the first finger. (this is like int **finger_two = &finger)
Now if I want to know where the blue car is I can follow the first finger's direction to the second finger, to the car (the data).
The dangling pointer
Now let's say you're feeling very much like a statue, and you want to hold your hand pointing at the red car indefinitely. What if that red car drives away?
1 2 3
-------------------
| o=o | | o=o |
| |B| | | |G| |
| o-o | | o-o |
Your pointer is still pointing to where the red car was but is no longer. Let's say a new car pulls in there... a Orange car. Now if I ask you again, "where is the red car", you're still pointing there, but now you're wrong. That's not an red car, that's orange.
Pointer arithmetic
Ok, so you're still pointing at the second parking spot (now occupied by the Orange car)
1 2 3
-------------------
| o=o | o=o | o=o |
| |B| | |O| | |G| |
| o-o | o-o | o-o |
Well I have a new question now... I want to know the color of the car in the next parking spot. You can see you're pointing at spot 2, so you just add 1 and you're pointing at the next spot. (finger+1), now since I wanted to know what the data was there, you have to check that spot (not just the finger) so you can deference the pointer (*(finger+1)) to see there is a green car present there (the data at that location)
An example of a tutorial with a good set of diagrams helps greatly with the understanding of pointers.
Joel Spolsky makes some good points about understanding pointers in his Guerrilla Guide to Interviewing article:
For some reason most people seem to be born without the part of the brain that understands pointers. This is an aptitude thing, not a skill thing – it requires a complex form of doubly-indirected thinking that some people just can't do.
The problem with pointers is not the concept. It's the execution and language involved. Additional confusion results when teachers assume that it's the CONCEPT of pointers that's difficult, and not the jargon, or the convoluted mess C and C++ makes of the concept. So vast amounts of effort are poored into explaining the concept (like in the accepted answer for this question) and it's pretty much just wasted on someone like me, because I already understand all of that. It's just explaining the wrong part of the problem.
To give you an idea of where I'm coming from, I'm someone who understands pointers perfectly well, and I can use them competently in assembler language. Because in assembler language they are not referred to as pointers. They are referred to as addresses. When it comes to programming and using pointers in C, I make a lot of mistakes and get really confused. I still have not sorted this out. Let me give you an example.
When an api says:
int doIt(char *buffer )
//*buffer is a pointer to the buffer
what does it want?
it could want:
a number representing an address to a buffer
(To give it that, do I say doIt(mybuffer), or doIt(*myBuffer)?)
a number representing the address to an address to a buffer
(is that doIt(&mybuffer) or doIt(mybuffer) or doIt(*mybuffer)?)
a number representing the address to the address to the address to the buffer
(maybe that's doIt(&mybuffer). or is it doIt(&&mybuffer) ? or even doIt(&&&mybuffer))
and so on, and the language involved doesn't make it as clear because it involves the words "pointer" and "reference" that don't hold as much meaning and clarity to me as "x holds the address to y" and "this function requires an address to y". The answer additionally depends on just what the heck "mybuffer" is to begin with, and what doIt intends to do with it. The language doesn't support the levels of nesting that are encountered in practice. Like when I have to hand a "pointer" in to a function that creates a new buffer, and it modifies the pointer to point at the new location of the buffer. Does it really want the pointer, or a pointer to the pointer, so it knows where to go to modify the contents of the pointer. Most of the time I just have to guess what is meant by "pointer" and most of the time I'm wrong, regardless of how much experience I get at guessing.
"Pointer" is just too overloaded. Is a pointer an address to a value? or is it a variable that holds an address to a value. When a function wants a pointer, does it want the address that the pointer variable holds, or does it want the address to the pointer variable?
I'm confused.
I think the main barrier to understanding pointers is bad teachers.
Almost everyone are taught lies about pointers: That they are nothing more than memory addresses, or that they allow you to point to arbitrary locations.
And of course that they are difficult to understand, dangerous and semi-magical.
None of which is true. Pointers are actually fairly simple concepts, as long as you stick to what the C++ language has to say about them and don't imbue them with attributes that "usually" turn out to work in practice, but nevertheless aren't guaranteed by the language, and so aren't part of the actual concept of a pointer.
I tried to write up an explanation of this a few months ago in this blog post -- hopefully it'll help someone.
(Note, before anyone gets pedantic on me, yes, the C++ standard does say that pointers represent memory addresses. But it does not say that "pointers are memory addresses, and nothing but memory addresses and may be used or thought of interchangeably with memory addresses". The distinction is important)
I think that what makes pointers tricky to learn is that until pointers you're comfortable with the idea that "at this memory location is a set of bits that represent an int, a double, a character, whatever".
When you first see a pointer, you don't really get what's at that memory location. "What do you mean, it holds an address?"
I don't agree with the notion that "you either get them or you don't".
They become easier to understand when you start finding real uses for them (like not passing large structures into functions).
I could work with pointers when I only knew C++. I kind of knew what to do in some cases and what not to do from trial/error. But the thing that gave me complete understanding is assembly language. If you do some serious instruction level debugging with an assembly language program you've written, you should be able to understand a lot of things.
The reason it's so hard to understand is not because it's a difficult concept but because the syntax is inconsistent.
int *mypointer;
You are first learned that the leftmost part of a variable creation defines the type of the variable. Pointer declaration does not work like this in C and C++. Instead they say that the variable is pointing on the type to the left. In this case: *mypointer is pointing on an int.
I didn't fully grasp pointers until i tried using them in C# (with unsafe), they work in exact same way but with logical and consistent syntax. The pointer is a type itself. Here mypointer is a pointer to an int.
int* mypointer;
Don't even get me started on function pointers...
I like the house address analogy, but I've always thought of the address being to the mailbox itself. This way you can visualize the concept of dereferencing the pointer (opening the mailbox).
For instance following a linked list:
1) start with your paper with the address
2) Go to the address on the paper
3) Open the mailbox to find a new piece of paper with the next address on it
In a linear linked list, the last mailbox has nothing in it (end of the list). In a circular linked list, the last mailbox has the address of the first mailbox in it.
Note that step 3 is where the dereference occurs and where you'll crash or go wrong when the address is invalid. Assuming you could walk up to the mailbox of an invalid address, imagine that there's a black hole or something in there that turns the world inside out :)
I think that the main reason that people have trouble with it is because it's generally not taught in an interesting and engaging manner. I'd like to see a lecturer get 10 volunteers from the crowd and give them a 1 meter ruler each, get them to stand around in a certain configuration and use the rulers to point at each other. Then show pointer arithmetic by moving people around (and where they point their rulers). It'd be a simple but effective (and above all memorable) way of showing the concepts without getting too bogged down in the mechanics.
Once you get to C and C++ it seems to get harder for some people. I'm not sure if this is because they are finally putting theory that they don't properly grasp into practice or because pointer manipulation is inherently harder in those languages. I can't remember my own transition that well, but I knew pointers in Pascal and then moved to C and got totally lost.
I don't think that pointers themselves are confusing. Most people can understand the concept. Now how many pointers can you think about or how many levels of indirection are you comfortable with. It doesn't take too many to put people over the edge. The fact that they can be changed accidently by bugs in your program can also make them very difficult to debug when things go wrong in your code.
I think it might actually be a syntax issue. The C/C++ syntax for pointers seems inconsistent and more complex than it needs to be.
Ironically, the thing that actually helped me to understand pointers was encountering the concept of an iterator in the c++ Standard Template Library. It's ironic because I can only assume that iterators were conceived as a generalization of the pointer.
Sometimes you just can't see the forest until you learn to ignore the trees.
The confusion comes from the multiple abstraction layers mixed together in the "pointer" concept. Programmers don't get confused by ordinary references in Java/Python, but pointers are different in that they expose characteristics of the underlying memory-architecture.
It is a good principle to cleanly separate layers of abstraction, and pointers do not do that.
The way I liked to explain it was in terms of arrays and indexes - people might not be familiar with pointers, but they generally know what an index is.
So I say imagine that the RAM is an array (and you have only 10-bytes of RAM):
unsigned char RAM[10] = { 10, 14, 4, 3, 2, 1, 20, 19, 50, 9 };
Then a pointer to a variable is really just the index of (the first byte of) that variable in the RAM.
So if you have a pointer/index unsigned char index = 2, then the value is obviously the third element, or the number 4. A pointer to a pointer is where you take that number and use it as an index itself, like RAM[RAM[index]].
I would draw an array on a list of paper, and just use it to show things like many pointers pointing to the same memory, pointer arithmetic, pointer to pointer, and so on.
Post office box number.
It's a piece of information that allows you to access something else.
(And if you do arithmetic on post office box numbers, you may have a problem, because the letter goes in the wrong box. And if somebody moves to another state -- with no forwarding address -- then you have a dangling pointer. On the other hand -- if the post office forwards the mail, then you have a pointer to a pointer.)
Not a bad way to grasp it, via iterators.. but keep looking you'll see Alexandrescu start complaining about them.
Many ex-C++ devs (that never understood that iterators are a modern pointer before dumping the language) jump to C# and still believe they have decent iterators.
Hmm, the problem is that all that iterators are is in complete odds at what the runtime platforms (Java/CLR) are trying to achieve: new, simple, everyone-is-a-dev usage. Which can be good, but they said it once in the purple book and they said it even before and before C:
Indirection.
A very powerful concept but never so if you do it all the way.. Iterators are useful as they help with abstraction of algorithms, another example. And compile-time is the place for an algorithm, very simple. You know code + data, or in that other language C#:
IEnumerable + LINQ + Massive Framework = 300MB runtime penalty indirection of lousy, dragging apps via heaps of instances of reference types..
"Le Pointer is cheap."
Some answers above have asserted that "pointers aren't really hard", but haven't gone on to address directly where "pointer are hard!" comes from. Some years back I tutored first year CS students (for only one year, since I clearly sucked at it) and it was clear to me that the idea of pointer is not hard. What's hard is understanding why and when you would want a pointer.
I don't think you can divorce that question - why and when to use a pointer - from explaining broader software engineering issues. Why every variable should not be a global variable, and why one should factor out similar code into functions (that, get this, use pointers to specialize their behaviour to their call site).
I don't see what is so confusing about pointers. They point to a location in memory, that is it stores the memory address. In C/C++ you can specify the type the pointer points to. For example:
int* my_int_pointer;
Says that my_int_pointer contains the address to a location that contains an int.
The problem with pointers is that they point to a location in memory, so it is easy to trail off into some location you should not be in. As proof look at the numerous security holes in C/C++ applications from buffer overflow (incrementing the pointer past the allocated boundary).
Just to confuse things a bit more, sometimes you have to work with handles instead of pointers. Handles are pointers to pointers, so that the back end can move things in memory to defragment the heap. If the pointer changes in mid-routine, the results are unpredictable, so you first have to lock the handle to make sure nothing goes anywhere.
http://arjay.bc.ca/Modula-2/Text/Ch15/Ch15.8.html#15.8.5 talks about it a bit more coherently than me. :-)
Every C/C++ beginner has the same problem and that problem occurs not because "pointers are hard to learn" but "who and how it is explained". Some learners gather it verbally some visually and the best way of explaining it is to use "train" example (suits for verbal and visual example).
Where "locomotive" is a pointer which can not hold anything and "wagon" is what "locomotive" tries pull (or point to). After, you can classify the "wagon" itself, can it hold animals,plants or people (or a mix of them).