Tuesday, November 20, 2012

C Pointers Explained, Really




From: Bill! (easterb@ucscb)
Subject: Okay

Well, if you know assembly, you have a head start
on many of the cis freshpersons here.  You at least know
For some reason, books and instructors talking about
pointers want to overlook this.

When I have some code:

int n;
int *p;

There is a place in my memory that looks like this:

Address:   :
  0x5100|     |   n is an integer, one machine word big
  0x5104|     |   p is a pointer, also one word big
  0x5108|     |   other unused memory

Let's give these variables some values.
I set n to be the number 151.

        n = 151;

I set the pointer p to point to the integer n.

        p = &n;

address of the variable n".

Address:     :     Value at that address:
  0x5100  | 151|  n
  0x5104  |5100|  p
  0x5108  |   ?|



make this coincide with what we were pointing at.

Now I want to print out the memory address of n.


conform to the Assembly notation I am used to).
Notice the _value_ of p is an address.



Here we are taking the address of a pointer variable, 
using the & operator.

char name[] = "Bill";
char *p;
int *q;


 0x5101 |'i'|  char: 1 byte
 0x5102 |'l'|  char: 1 byte
 0x5103 |'l'|  char: 1 byte
 0x5104 |\0 |  char: 1 byte
 0x5105 |   |  p is a pointer: 1 word
 0x5109 |   |  q is a pointer: 1 word

        p = name;

character 'B' as a result.

Now what happens if I do this:


Hex 5101.  Pretty simple.

Now let's try something irresponsible:

        q = name;

bit-ordering algorithm on your machine's architecture.  On ucscb,

mentioned earlier:  C assumes that what they are pointing at


paragraph.  It gets incremented by the size of the object it

Nice going.  Try to convert _that_ to an integer representation.

int n;

        n = 151;

int x;


 0x5100 |151|  n is an integer
 0x5104 |151|  x is another integer

the int at location 5100.

passing the variable "by reference".

int n;

        n = 151;

int *x;
        *x = 451;

passed is the address, not the number.

 0x5100 | 151|  n is an integer
 0x5104 |5100|  x is a pointer to int

value at location 5100.  This is the location of n.

 0x5100 | 451|  n is an integer
 0x5104 |5100|  x is a pointer to int

of the object at that location.

Well, those are the basics.

 0x5100 |   0|  no variable name

First let's see what p and x were declared as:
int *x;    /* pointer to int */
int **p;   /* pointer to pointer.  
              The subordinate pointer is a pointer to int.*/

Now that value is another address!  Okay, let's dereference that

that int at 5104."

p has been incremented.  But we looked where it was pointing
worry about it."



Bushinji said...

Great post!
I finally got it, thanks a bunch! :)

Marin Todinov said...

Dear Programming Guru,



Thank you again,

Marin Todinov said...
This comment has been removed by the author.
quantumdude said...


Gogus said...



i.love.it said...

i think you are wrong when u said:
"the first 3 bytes of the char *p"

p is a character type and only has 1 byte?

would q actually overlap its own bytes coming after p?

Bill Karwin said...

Hi i.love.it,

p is not a character, p is a pointer.



danmux said...


Chase S said...

Really, no one teaches it like this?


Good work!

Bill Karwin said...



Gathogo said...

Very very well explained!!

Anthony Cesaro said...




Bill Karwin said...

@Anthony Cesaro:



Chattrawit S. said...


Rishikesh Fanse said...

nice one dude

akmal niazi khan said...


Love from

Priyansh Ramnani said...

Thanks a lot sir! :)
I had a great difficulty understanding pointers
This made my concept crystal clear!!

Prateek Pandey said...

Wow great one.


Bill Karwin said...


Prateek Pandey said...

Yes, Bill it is.

Consider mentioning it in your article

Michael Fulton said...


Sujitkumar said...


Mukul said...

Thanks a lot .

Jun Zhou said...

Hi, thanks so much for your excellent tutorial. I am new to c programming and trying to understand pointers with the following simple test, but stucked

int x=5,y=6, *p;
p = &y;

printf("1. address of y is %d\n",p);
printf("2. address of y is %d\n",&y);
printf("3. address of x is %d\n",&x);

with codeblock compiler (16.01) running on a 64bit pc I got the returns as

1. address of y is 2686740
2. address of y is 2686740
3. address of x is 2684744

curiously I would like to see what "p+1" would be

printf("4. p+1 = %d\n",p+1);

and the result is

4. p+1 = 2686744

as this is the address for "x" I then go bit further to see what is the value of *p now and
is it equals to x

printf("5. *p = %d\n", *p);
printf("6. x = %d\n", x);

and the returns are

5. *p = 6
6. x = 5

this makes me realized that the address p+1 is nothing to do with *p so I tried

int *p1;
*p1 = *(int *)(p+1);

printf("the value of *p1 = %d\n",*p1);

the compiling is OK but the run gives me this

Process returned -1073741819 (0xC0000005)

I am lost, so please help.


Michael Fulton said...

Hi Jun,

Maybe I can explain what p + 1 actually does in this case. When you add 1 to p, you add the size (in bytes) of 1 element that p is pointing to. For example, since p is pointing to an Integer, and integer is 4 bytes, the memory address of p will be advanced by 4 bytes when you add 1. If it was "long" data type, like `long *p;` then adding one would advance it 8 bytes (or whatever it is on your machine).

Hope this helps.

Jun Zhou said...

Hi Michael,

Thank you very much.

I have no problem in understanding "p+1" has the value of "2686744" which seems to me is the
address of "x". what make me lost is the last bit of the test with *p1, what I am expecting
is that *p1 is a pointer pointing to x.


Michael Fulton said...

(p + 1) -> pointer equivalent to x...
Casting it to pointer (why?) With (int *)...
Then dereferencing with *, so now you have the value of x (which is 6)... Then assigning that 6 to the *p1 which should be a memory address.

If you want *p1 to be memory address of x, why not "int *p1 = p + 1"? Or if you want value of x, int X2 = *(p + 1) so X2 == 6.

Bill Karwin said...

Jun Zhou, In your last test, you seem to be trying to set the value of the memory that p1 points to.

In your first lines of code, you initialize the pointer p to the address of y (p = &y). This is okay because y has a real location where an integer value is stored.

But in your last test, p1 is declared a pointer, but you give it no address of an int variable. Therefore p1 is uninitialized, and it is not guaranteed that it points to a valid location where any int can be stored. It's like it's pointing to a location off the edge of the world.

Then you set the value at *p1, it's undefined what happens. Is the value set? Can it be set? There's no telling. And your test seems to show that it's invalid.

Pointers don't implicitly get a space to store the value they point to. That has to be allocated by a concrete variable.

I would also comment that it's risky using pointer arithmetic to increment a pointer to point to a separate discrete variable. I don't think it's guaranteed that compilers will always store variables contiguously or in the same direction of increasing memory addresses. I wouldn't rely on that, except if I'm advancing a pointer through elements of an array.