The C Programming Language

Pointers

Preface

In this article, I'll explain what pointers and addresses are, how arrays are actually pointers, and a little bit of pointer arithmetic.

Pointers and Addresses

If you were to pass an argument to a function, it would be a copy of the variable rather than the original (unless it's an array, more on that further down). Now, let's assume we have an array, and we want to swap two members using a function. consider the following erroenus code:

void swap(int x, int y){
 int temp = x;
 int x = y;
 int y = temp;
}

Such code would not work, because x and y are copies and not the originals. This is where pointers solve our problem.

Pointers and Addresses - Definition

A pointer is a variable that contains an address. An address is a value that represents the physical address of a variable in the memory. Where the variable is in the memory will be discussed in a later article.

Pointers and Addresses - Syntax

Defining a Pointer

To define a pointer, the syntax can is very simple, all you have to do is add an asterisk between the type and the name:

int* anIntegersAddress;
double *aDoublesAddress;
int * anotherIntegerAddress;

My personal preference is the first style, but the second is more frequently used. Sidenote: Apart from function pointers, this is the usual way to define a pointer.

Initializing a Pointer and Assignment

Now we that we have defined a few pointers, maybe we would like to initialize them or assign them a new value later in the code. we'll simply need to use an ampersand to get a variable's address, to do that, just preface the variable with it:

int x = 5;
int y = 7;
int* anIntegersAddress = &x;
int * anotherIntegerAddress;
anotherIntegersAddress = &y;

We can also - obviously - assign a pointer to a pointer, only if it's of same type of pointer:

int x = 5;
int y = 7;
int* anIntegersAddress = &x;
int * anotherIntegerAddress;
anotherIntegersAddress = anIntegersAddress;

Dereferencing a Pointer

The final piece of information needed to complete our swap function is being able to access a variable from its address, known as dereferencing a pointer. To do that, preface the pointer with an asterisk:

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

Prefacing any pointer or address with an asterisk would yield the variable the pointer points to. For the sake of completeness, for the latter the following syntax is legal, albeit, impractical:

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

Now to finally write a correct swap function:

#include <stdio.h>

void swap(int* x, int* y){
 int temp = *x;
 *x = *y;
 *y = temp;
}

int main(){
 int myArray[5] = { 1, 2, 3, 4, 5};
 printf("The second member of myArray is %d\n", myArray[1]);
 swap(&myArray[1], &myArray[3]);
 printf("The second member of myArray is now %d\n", myArray[1]);
}

Arrays in Reality

Arrays are actually pointers, that point to the first member of the array and not to the array itself!

int myArray[5] = { 1, 2, 3, 4, 5 };
int* anIntegerAddress = myArray;

Arrays and Pointer Arithmetic

While I'm not going to go over pointer arithmetic in its entirety, I'll go over a few concepts. As seen in the swap call above, we are passing the address of the second and fourth members using the square bracket operator and the ampersand operator. Well that is not the only way to pass them. Since we have the first pointer, we can use pointer arithmetic to get the pointers to the second and fourth members:

swap(myArray + 1, myArray + 3);

While this seems neater (at least to me), this obfuscates what the arguments are, if not for the relevant context clues such as the function's name, or the array's name, then it's not possible to tell whether this is arithmetic on integers or on pointers. It's important to have clear variable names if one were to use pointer arithmetic.
The addition here actually adds the size of one integer to the pointer, therefore, we get the pointer to the second integer as a result. For the second operation it add 3 times the size of one integer to the pointer, and as a result, we get the pointer to the fourth integer (Remember that array indexing starts from 0).
Anyways, here's the new version of the code, identical bar the swap call:

#include <stdio.h>

void swap(int* x, int* y){
 int temp = *x;
 *x = *y;
 *y = temp;
}

int main(){
 int myArray[5] = { 1, 2, 3, 4, 5};
 printf("The second member of myArray is %d\n", myArray[1]);
 swap(myArray+1, myArray+3);
 printf("The second member of myArray is now %d\n", myArray[1]);
}

Summary

And that's almost all there is to pointers as a variable. We have not discussed segmentation faults, that are errors that can arise when misusing pointers. We're also yet to talk about dynamic allocation, and the relevance of pointers to it, and there's also function pointers that are a very important feature of C, at least in my opinion. In the next article, we'll talk about dynamic allocation, then once we're done, we'll talk about errors and debugging. Until then!
All code files used in the article are provided below.

pointers1.c
pointers2.c

Contents