
The 5-minute Guide to C Pointers - denniskubes
http://denniskubes.com/2012/08/16/the-5-minute-guide-to-c-pointers/
======
Jun8
30 second guide to C pointers, from _Alice in Wonderland_ :

`It's long,' said the Knight, `but very, very beautiful. Everybody that hears
me sing it -- either it brings the tears into their eyes, or else -- '

`Or else what?' said Alice, for the Knight had made a sudden pause.

`Or else it doesn't, you know. The name of the song is called "Haddocks'
Eyes."'

`Oh, that's the name of the song, is it?' Alice said, trying to feel
interested.

`No, you don't understand,' the Knight said, looking a little vexed. `That's
what the name is called. The name really is "The Aged Aged Man."'

`Then I ought to have said "That's what the song is called"?' Alice corrected
herself.

`No, you oughtn't: that's quite another thing! The song is called "Ways and
Means": but that's only what it's called, you know!'

`Well, what is the song, then?' said Alice, who was by this time completely
bewildered.

`I was coming to that,' the Knight said. `The song really is "A-sitting On A
Gate": and the tune's my own invention.'

The song that the Knight is referring to is this one:
<http://en.wikipedia.org/wiki/Haddocks%27_Eyes>

~~~
Danieru
Over the past four months I wrote a library in C. In said library exists the
following chain:

typedef hidden pointer -> object -> dictionary -> attribute object -> linked
list -> object

Then the whole thing can start again from the last object. At both the linked
list and dictionary points the pointers have been cast to void. During
development there was linked list in place of the dictionary. Since this was
before I wrote output debuging involved manually walking the two linked lists.

Else where a function takes a void * array of structs yet needs to access the
contents and thus requires a pointer to an accessor function.

I love C but it can get _confusing_. My plan is to spend the next few weeks in
recovery learning RoR.

~~~
densh
You might want to look at Go. It always felt like a revised version of C with
great standard library and sane defaults.

------
rosser
Every time someone tries offering a simplified explanation of pointers, I've
countered with the old Buddhist saying that, "The pointing finger is not the
moon," followed by a brief foray into syntax and operators, e.g.,

    
    
      moon* finger = &luna;
    

As often as not, enlightenment occurs.

~~~
sageikosa
void* finger = &luna;

Don't force the finger to only point to the moon.

------
sown
Pointers are sometimes not arrays. :)

    
    
        extern int *x;
        extern int y[]
    

x is a pointer to an int and y is a pointer to an array of ints of unspecified
size. It's equivalent to saying float x and then extern int x somewhere else.
They're type mismatched.

If you said 'x is a char pointer', you mean lookup symbol table for address of
x, then do a memory address dereference and then get the contents of the
memory at dereferenced address.

If you said 'x is a char array', you mean use the symbol table to get the
address, then calculate offset and get contents from that address.

When you define it one way and then do it another, you end up doing both of
those above. get contents of x, then get value of offset, add it to the
contents of x, then get contents of the resulting address+offset.

The issue is the declaration which can happen many times and the definition
which occurs just once.

Now, you can have an array and a pointer be equivalent if it is used in an
expression because the compiler converts array references to pointers.

~~~
mikeash
Arrays and pointers are _completely different entities_ in C. The only reason
people think there's any sort of equivalence is because:

1\. The "array indexing operator" [] actually works only on pointers.

2\. Arrays are automatically converted to a pointer to the first array element
whenever necessary.

3\. Arrays are _really uncommon_ in C, and many things we think of as arrays
are not arrays as C considers them. Declare a function parameter with []?
That's a pointer, not an array. Malloc a bunch of memory? Not an array.

------
_kst_
> Imagine an array variable like a pointer that cannot be changed that holds
> the memory address of the first element of the array it points to.

Nope. Arrays are not pointers; pointers are not arrays. This is perhaps the
most common misconception about C, and a "Guide to C Pointers" should not
propagate it.

For more information about why this is wrong, read section 6 of the
[comp.lang.c FAQ](<http://www.c-faq.com>).

~~~
ninetax
Well for a quick sum up:

An array is like a constant pointer, it's always pointing at the first element
of the the array. To try to point it at something else is an error.

    
    
        array[2] 
    

is short for

    
    
        *(array + 2*sizeof(<type of array>)) 
    

which takes the address of the first element and adds the appropriate number
of bytes to it in order to access the requested element, then it dereferences
the "pointer" and you get the value of the element.

If this isn't 100% correct, please let me know.

~~~
eswangren
Just as with pointer arithmetic (because that's what this actually is) you
don't multiply by the size of its elements. This:

    
    
      array[2]
    

is the same as this:

    
    
      *(array + 2)
    

The compiler knows what the type of data the pointer refers to and can produce
the byte offset itself. Also:

    
    
      "...it's always pointing at the first element of the the array"
    

Eh... an array can degrade into a pointer when needed, but what does the
following produce?

    
    
      char arr[10];
      ??? x = &arr;
    

Is "x" a pointer to pointer to char? From your assessment it would seem so,
but in reality the type of "x" is

    
    
      char (*)[10]
    

i.e., pointer to array of char 10. An array is an array, and arrays can
degrade into pointer types.

~~~
RegEx
Additionally, (as you know, but merely pointing out for the curious), `sizeof
arr` returns the size of arr in bytes, not the size of a pointer to the first
element of arr.

------
sausagefeet
When printfing pointers you need to cast them to (void\ _). %p only prints
void\_ and there is no guarantee two pointer types have the same size. And I
can't figure out how to write an astrix.

I also think it is a mistake to bring up memory addresses so early. The first
paragraph is incredibly confuses.

A pointer is simple. It's a variable that points at something. You can change
where it points and you can change the value that it is pointing to. (&) is
the pointer-to operator and gives you a pointer to something.

I think that is roughly all that needs to be said. The all of locations,
memory, addresses is just confusion.

~~~
sausagefeet
Pedantic notes:

\- "The cast isn’t explicitly needed in C but it does make things more
readable" - I think many people would disagree with this, including me.
Casting is ugly, error prone, and conceals errors. Don't do it, there is no
need. If you think it is helping you because you can see what type things are
then your functions are too large and incoherent, fix that problem instead.

\- "Here we print out the values of our uninitialized and NULL pointers.
Notice that our uninitialized pointer has a memory location" - This behaviour
is completely undefined and it is doing injustice to those who would benefit
from this blog post. All code people run on an example site should be well-
defined. "Worst case the program crashes badly" - No, worst case is you have
no idea what could happen! Old versions of gcc ran nethack when it detected
undefined behaviour at compile time. In practice, crashing is actually the
best case since you can see the error. In worst case it silently corrupts data
in your program and you can't find it until it's so far from the error site
that it's near impossible to track down.

\- "using the NULL keyword" - NULL is not a keyword, it's a macro defined in
stddef.h (maybe stdlib.h? I forget).

\- "doing so will cause a segmentation fault" - No, it's undefined behaviour.
On DOS systems the memory addresses 0 was valid and writable.

\- "That being said an array variable does point to the memory address of the
first element of the array." - No, it IS the first element. It decays to a
pointer to its first element under various operations, though.

\- "char * fullname = "full name";" - const char * . Modifying string literals
is undefined and the fact that the compiler does not require fullname to be a
const char * is merely a historic oversight.

I understand the desire to learn-by-writing, but I don't feel this tutorial
offers much to the discussion and confuses some of the same things the many
other pointer tutorials confuse. I don't think someone new to pointers will
actually come out with a superior understanding of pointers after reading
this. Much of the content is not technically wrong the wording and method of
introduction isn't any less confusing.

------
manaskarekar
Here's another one with more information on pointers in C.

<http://www.thegeekstuff.com/2012/01/advanced-c-pointers/>

~~~
ddfreyne
Another tutorial about pointers that I found quite nicely written is
<http://boredzo.org/pointers/>.

------
phao
Yet another broken C pointers guide out there to confuse people.

~~~
denniskubes
What is broken about it? I am happy to make corrections.

~~~
jorgem
Some thoughts:

>> A pointer is a variable that holds, literally points to, a memory address

What is a memory address?

How does a pointer literally point to a memory address?

~~~
jcoder
It's the guide to pointers, not the guide to memory addresses—I think readers
are expected to google unfamiliar terms.

~~~
jorgem
I think if I understand memory addresses and assembly language, then I
understand pointers. If the guide doesn't explain why pointers are useful and
efficient on real hardware, then it's missing the point. Which was my point.

------
pjmlp
Nice tutorial!

Maybe it shows my age, but I am yet to understand why so many developers
nowadays have such a hard time grasping pointers, regardless of the language
being used to teach them.

~~~
zaptheimpaler
I had the same opinion at one point. Like you said, the concept of pointers is
very simple, but it can get confusing in application, as you start dealing
with more levels of indirection. Try coding something/understanding code that
requires triple star pointers, then you'll see why they're confusing.

~~~
pjmlp
Easy, just grab a pencil and paper, draw the data structures and you're done.

Again, maybe it just shows my age, as I started coding with BASIC and Z80
assembly.

------
bnegreve
> The * operator is used to both declare a pointer variable and to dereference
> a pointer depending on where it appears.

You seem to be suggesting that this is an inconsistency, it isn't:

    
    
      int *ptr;

means that

    
    
      (*ptr)
    

is of type ptr.

    
    
      *ptr = 3;
    

Means the same and affect 3 to (*ptr)

~~~
qlkzy
Don't you mean

    
    
      (*ptr)
    

is of type _int_?

~~~
bnegreve
yes, of course.

------
ExpiredLink
I expected a repost of a repost of this:
<http://www.youtube.com/watch?v=f-pJlnpkLp0>

------
khakimov
thanks, also recommend to read "What do people find difficult about C
pointers?" [http://stackoverflow.com/questions/4025768/what-do-people-
fi...](http://stackoverflow.com/questions/4025768/what-do-people-find-
difficult-about-c-pointers)

~~~
keporahg
I never really had much of a problem with the syntax, but the point at which
the behavior of pointers really clicked for me (after a night of many
segfaults of course) was when I realized that when you pass a pointer to a
function, you're sending a copy of that pointer, just like with any other
primitive type. E.g:

    
    
        void foo(int *p)
        {
            /* assignment won't be persistent after foo() returns; need to send **p */
            p = (int *)malloc(1024 * sizeof(int));
        }
    

Not sure why my brain had decided to make an exception for pointers for the
rule that all variables are passed as copies when I first learned C, but after
that I never had any problems.

~~~
RegEx
I experienced the same frustration. The exercise that gave me the "ah-ha!"
moment I needed was prepending to a linked list via the head instead of the
tail: You need to pass the address of `head` into the function so that the new
head is reflected in the calling environment when you say `head = np`.

~~~
unwind
... or have the list operation return the new list head, which can make it way
cleaner. See glib's list APIs, for instance.

~~~
RegEx
Well I was simply meeting exercise requirements, which aren't necessarily the
most practical.

------
chris_wot
Nothing on pointer pointers :( so sad.

~~~
denniskubes
I added a pointers to pointers section. :)

~~~
chris_wot
You rock.

------
Kiro
So... What do you use them for?

~~~
mike-cardwell
There are many uses. It greatly helps to understand the difference between the
heap and the stack, and to understand the difference between static and
dynamic allocation.

Functions in C are "pass by value" rather than "pass by reference". To
simulate "pass by reference", the "value" you would pass is the memory address
of the data in question, ie the pointer.

Also, if you put data on the heap, you must keep a reference to its memory
address, otherwise you wont be able to access it again. You use a pointer for
this. The following bit of code allocates some space on the heap, sticks an
integer (5) on it and then returns a reference to that memory address, which
is stored in a pointer variable named x.

    
    
      int * x = new int(5);
    

To understand why you would do the above instead of "int x = 5", you really
need to understand what the stack and heap are, and why/when to use them.

Also, you can create read-only versions of variables this way. Eg:

    
    
      int x = 5;
      const int * y = &x;
    

At this point, y points to the address containing x, but can only be used to
read. printing out "x" and "* y" will both give you the same result. If you
want to update it, you can do "x=6", but "* y=6" will cause a compile time
error, because of the const.

There are probably loads of other uses too. I only started learning C/C++ last
month, in my spare time. Hmm, I seem to have learnt a few things.

~~~
nosefrog
Correct me if I'm wrong, but I'm pretty sure C doesn't use the 'new' keyword,
it uses 'malloc'.

~~~
mike-cardwell
You are correct, as you know. That was a C++ example, as you know.

------
derleth
The nontechnical guide to C pointers:

 _They're post office box numbers._

In this analogy, the post office is all your RAM. The big place where my
analogy breaks down a bit is that, in this little world, the post office will
store things bigger than one box in multiple adjacent boxes, so to get
anything into or out of the post office you have to specify which box you want
them to start with and how many boxes they'll have to use.

The star (dereference) operator takes as its argument a post office box number
and instructs the machine to go to that post office box and start taking
things out of enough boxes beginning with that box to satisfy the type of the
pointer. The only things that only take one box are char values; the number of
boxes everything else takes up depends greatly on the specific kind of
hardware.

It's possible to put a slip of paper containing a number into a post office
box; in 32-bit x86, a number long enough to encode a post office box number
takes up four boxes. In 64-bit x86, it takes up eight boxes.

Using two stars means 'Go to this box, take out enough stuff from the next few
boxes to make a pointer, go to the box specified by that pointer, and take
enough stuff out from that box (and possibly the next few) to satisfy the type
of that pointer.' Using three stars involves another go-to-box step, using
four stars another, and using five stars is usually a sign of gross mental
derangement.

(Oh, and if you're running under an OS much more featureful than MS-DOS, the
post office box is a total lie told to your application by the OS. Getting
into _that_ gets a bit complicated.)

