Skip to content

Instantly share code, notes, and snippets.

@pinealservo
Created February 27, 2014 21:38
Show Gist options
  • Save pinealservo/9260116 to your computer and use it in GitHub Desktop.
Save pinealservo/9260116 to your computer and use it in GitHub Desktop.
C Pointers in a nutshell
If you think you know how they work and how the syntax works but you still can't use them, then you probably don't *actually* understand how they work and how the syntax works.
In C, when you declare a variable with something like
int x;
you are asking the compiler to reserve some space in memory to store a value, and you are also defining a name. So there are three distinct things here; a *name*, a *value*, and a *storage location*.
When a name appears on the left-hand side of an assignment (i.e., a statement like `x = 3;`) it refers to the *storage location* that the compiler set aside when you declared the variable. So the assignment will change the *value* that is stored at the variable's *storage location* by setting it to the *value* of the expression on the right-hand side of the `=`.
Now, I haven't talked about pointers yet. But pointers are not *any different* from other variables. Let's look at a pointer declaration now:
int * y;
Now the compiler will set aside some storage space for us, and it will have the correct size for your platform to store an address. The name `y` will be associated with the variable; both with the storage space itself for when it's used on the left-hand side of an assignment, and the value of the variable (which is going to be an address, although we haven't assigned anything to it yet so it's likely not a *good* address yet).
Let me repeat for emphasis: Pointer variables are not a special kind of variable. They work exactly like any other kind of variable. They just happen to hold an address in their storage location rather than some other kind of value.
So, in order to put a useful value in our pointer `y`, we need a way to get an address. If you were writing a device driver in a kernel, you could look up some useful addresses in a manual and do something like this:
#define WIDGET_PORT 0x08cf7770
y = (int *)(WIDGET_PORT);
Now we have put the literal address where some hardware register is mapped into memory into `y`. So, to examine the state of the widget hardware, we have to *dereference* the address. Dereferencing is just an operation that works on variables that hold addresses; it essentially performs a fetch of the value stored at the address. This is the same kind of thing that happens automatically whenever you use a variable for its value rather than its storage location.
Somewhat unfortunately, the operator for dereferencing an address is `*`:
printf("Widget state: %d\n", *y);
This says "Take the value of the variable `y` (i.e. fetch the value currently stored at the *storage location* associated with the *name* `y`) and treat it as an address. Then fetch the value stored at that address. Pass that as the second argument to printf."
Most of the time, you will not use literal addresses as pointers. You will use them either to refer to freshly allocated memory (malloc, for example, returns an address value that you may store in a pointer variable) or to the storage location of other variables. Normally the location of a variable's storage location is only used on the left-hand side of an assignment statement, but C also provides an operator that will give it to us:
printf("The location of x is: %p\n", &x);
A normal use of the name `x` will refer to the *value* in the storage location that the name `x` refers to, but this "address-of" operator instead gives us the address of the storage location itself!
Since an address is just a normal value, we can store it in a variable of the appropriate type, such as the `y` we defined earlier:
y = &x;
Here, y appears on the left-hand side of an assignment. Therefore the assignment operation is going to get the *storage location* named by `y` and it's going to store a new value in it. And we just saw that the "address-of" operator is going to look at the *storage location* named by `x` and yield as its value the *address* of that *storage location*.
As a result, the *storage location* named by `y` will store as its *value* the address of the *storage location* named by `x`. So printing `y` will give an address; printing `x` will give an integer. But we can also use the "dereference" operator on `y` and print the resulting value, which will be the same as printing `x`:
printf("y: %p, x: %d, *y: %d, &x, %p\n", y, x, *y, &x);
This will show the same hex value for y and &x, and the same integer value for x and *y.
So, let's look at your description of your problem:
> For example I want to have two pointers, x and y. I want x to point to something and then I want y to record what that something is and then I want to change x.
It's not entirely clear what you intend, so I'll rephrase based on some assumptions:
> I have a pointer, x, that I will use to traverse some data. For each of the data I point at, I want to make a copy of that datum into another variable y that will retain that value when x changes.
So, let's define some variables based on that specification:
int *x;
int y;
int first = 5;
int second = 8;
Now we'll store the address of first in x:
x = &first;
printf("first: %d, &first: %p, x: %p, *x: %d\n", first, &first, x, *x);
And we'll copy the value at the address stored in x to y:
y = *x;
printf("y: %d, *x: %d\n", y, *x);
And now we'll change x to the address of second:
x = &second;
printf("y: %d, *x: %d\n", y, *x);
TLDR:
* Variables associate a *name* with a *storage location* that holds a *value*
* When a variable is used on the left-hand side of an assignment, its associated *storage location* gets a new value put in it.
* When a variable is used most other places, an implicit fetch of the *value* stored at its *storage location* happens.
* Pointers are just regular variables that happen to store addresses.
* The `*` operator fetches the value at an address.
* The `&` operator finds the address of a variable's *storage location*.
Hopefully this helps!
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment