Pointer basics – C

Pointers

Pointers are variables which store a value of memory address in which a value of certain datatype is kept. Simply put, they point(address) to a value – not directly containing a value but just a reference to the value. To get the actual value of the reference one has to dereference the pointer (see operators). Since the value of a pointer is memory address, this means that if multiple pointers point to same memory address, after dereferencing they contain same value (Meaning that, should that value be changed, all of the pointers will have the same value after dereferencing them).

As the name pointer suggests it points to somewhere, however it is also very important that there is a pointee – memory where pointer points to. Meaning that the memory must be allocated for your program (statically – arrayvariable or dynamicaly – malloc, calloc, etc..). By default the pointers are not pointing anywhere in particular and once you try to see the value in the memory, you will get segmentation fault – program crashes because you tried to access memory locations, which are not meant for you to access (see 2).

The amount of memory usage for a pointer variable depends solely on the computer architecture, whether it is 32-bit or 64-bit. Meaning that the pointer variable will take either 4 or 8 bytes of memory.

To give a quick overview about pointers consider the following:

The following code..

// Declare an integer and initialize with 25
int number = 25;
// Declare int pointer, initialize with address of number
int *ptr = &number;
// Declare int pointer, initialize with the value of ptr
int *ptr2 = ptr;

// Print the value and addresses of each variable
// Note that pointer variables contain address as a value
printf("%d, %p - %p - %p\n",
        number, &number, ptr, ptr2);
// Assign a new value to number
number = 99;
// Print the values
// Note that pointer variables are dereferenced
printf("%d - %d - %d\n",
        number, *ptr, *ptr2);

Produces similar output..

25, 0x7fffeb6c00e4 - 0x7fffeb6c00e4 - 0x7fffeb6c00e4
99 - 99 - 99

Which can be visualized as..

Legend
Variables with initial values
Variables with new values

 

  • Both ptr and ptr2 point to the memory address where variable number is stored.
  • After the number value is changed, the pointers still refer to the memory address of number.

Pointers are most commonly used:

  • Referencing a value
  • Arrays and strings
  • Passing variable as an original to a function
  • Memory manipulation
    • Dynamic memory allocation
    • Modifying register values
  • Data structures
    • trees
    • linked lists
  • Files and streams
  • Function pointers

Basic usage

Declaring

The declaration of a pointer variable is very straightforward, add an asterisk (*) before the variable name. E.g. to declare an integer pointer (variable which has a value of memory location, which stores an integer) you should type int *ptr;. It should be noted that only at declaration it is necessary to add an asterisk to define the pointer variable, after declaration asterisk (*) will dereference the pointer variable. And of course as with any  variable, it is good practice to initialize it (NULL pointer should usually be default value, see assign value paragraph).

According to our style guide for C, it is recommended to add asterisk before the variable name instead of after datatype. The reasoning for this is – when declaring multiple pointers within one statement it is easier to associate the pointer to the variable. Consider the following examples:

// Which of these variables are pointers to integers?
int* a, b, c;
// Recommended use when declaring multiple variables with one statement
// Spot the difference?
int *a, *b, *c;
// Most explicit
int *a;
int *b;
int *c;

It is possible to even declare a pointer to a pointer, which can be array of arrays e.g. char **strings;.

void pointer

NB! You can declare any pointer to any datatype, even void! Pointers which have type void are used when it is unknown what kind of data will the memory contain.

Assign value

As it is known, the values can be assigned by using the assignment operator (=). Because the variables are pointers, they can store memory addresses as values. This means that programmer can assign  other same type pointers or memory addresses of variables of same type, e.g.:

int number = 25;
int *ptr = &number; // address of number
int *ptr2 = ptr;    // value of ptr

NULL pointer

NULL is a special kind of pointer, this means that it points nowhere. It is considered to be default value which should be assigned, similarly as integers have default initialized value of 0. NULL pointer is usually 0 typecasted to void pointer: ((void*)0).

Example usage of declaring a variable which at first is initialized as NULL pointer (Assume that later on in the program it would be reassigned with a different value) :

int *numbers = NULL;
double *real = NULL;
Pointers

Operators

To operate with pointers there are 2 operators:

  1. * – dereference, read the value from the pointed memory location
  2. & – get the memory address of a variable

Note that * is used as deference only once, after declaration of a pointer variable.

An example of using both of the operators.

// Take variable as reference, assign new value
void change_value(int *src, int val) {
    // Dereference src (read the value in memory) and assign new value
    *src = val;
}

int main(void) {
    // declare variable x and initialize it with 5
    int x = 5;
    // Get the memory address of variable x, pass x as a reference (original value)
    change_value(&x, 25);
    // x now has a value of 25

    return 0;
}

Because we modified the values in the memory directly, after the call of change_value function was called, the changes persist.

Warnings

You should be careful when trying to dereference the following:

  • Pointers which point to unallocated space (see 2 – pointer must have pointee)
  • NULL pointers

If the programmer tries to dereference one of those pointers, the operating system will kill the process with an error Segmentation fault (core dumped). This means that the program is trying to read or write to memory locations which are not reserved for this program. In first case it could be any random memory address and in the second case trying to read from the first address of the memory (the memory region where the OS is loaded).

Arithmetic

As we already know, array is a sequential collection of data (see Arrays) and an  array can be indexed (from 0 to length – 1). In addition it is known that by using the variable name of an array means the reference to the first element of the array. This means that if a pointer variable will have the value of array (must have same types) then the pointer variable will also point to the first element of the array. In the following example “Hello” is printed twice:

#include <stdio.h>

int main(void) {

    char str[] = "Hello";
    char *ptr = str;
    puts(str);
    puts(ptr);

    return 0;
}

Variables str and ptr can be represented as follows (Note how the value of ptr is the same as first memory address of array str):

Character array in memory
ptr points to where str is pointing

Adding on top of that knowledge, we know that it is possible to also print the string out by accessing array elements by index and printing it out character by character. Using indexes the str variable could be printed as such:

// Print characters until 0-terminator is met
for (int i = 0; str[i] != '\0'; i++) {
    printf("%c", str[i]);
}

The same thing could be achieved by using pointer arithmetic  – using memory addresses to point to the right element and then dereferencing to get the value in that memory address. The following code snippet achieves the same thing by using pointer arithmetic:

// Print until character is not 0-terminator
for (int i = 0; *(str + i) != '\0'; i++) {
    // dereference the i-th element of the array (same as str[0 + i])
    printf("%c", *(str + i));
}

Same result could aslo be achieved by the following code (try to figure out how it works):

// ptr points to the first element of str
while (*ptr) {
    printf("%c", *(ptr++));
}

Resources

  1. Everything you need to know about pointers in C [ Link ]
  2. Pointer Fun C [ Link ]
  3. void pointers [ Link ]
  4. Pointers image [ Link ]
  5. Dereferencing a NULL pointer [ Link ]

5 thoughts on “Pointer basics – C

Comments are closed.