Sage-Code Laboratory
index<--

C Pointers

C programming language is famous for its ability to access memory directly by address. For this C has a special data types named pointers. We already mentioned pointers before, in the article about functions. Next you will learn a bit more about this concept.

Pointer Variables

You define a pointer variables using prefix "*" in front of variable name. A pointer can be initialized with value NULL. This is a constant that is actually = 0. It represents the zero memory location of a computer that is hardware protected and you can not read value or write value on this location.

Example:

#include <stdio.h>
int main () {
    int *p = NULL;
    printf("The value of p is : %x\n", p);
    return 0;
}

Variable Address

Address of a variable is extracted with symbol "&" and it can be assigned to a pointer. This is the most common way to initialize a pointer. Once you know the location of a variable you can read or write its content using the pointer instead of variable name.

array

Pointer Concept

#include <stdio.h>
int main () {
    int  d = 17;
    int  m = 11'
    int  y = 2020;
    int *p = &y; // a pointer to integer
    printf("Value of p: %0X\n", p ); //a hexadecimal address
    printf("Value of *p: %d\n", *p ); //expected value 2020
    return 0;
}

Output:

Value of p: AF04
Value of *p: 2020

Pointer Arithmetic

Sounds exotic but is not hard at all. There are two ways to use a pointer after it is defined. First way to use it as value (with prefix *). Second is to use it as address (without the prefix). Since a pointer is a number it can be printed and you can perform arithmetic operations with it.

Example:

#include <stdio.h>
int main () {
    int v = 5; // an integer variable
    int *p = &v; // a pointer to integer variable
    //initial value
    printf("p = %0X\n", p );
    p = p + 1; //increment
    printf("p = %0X\n", p );
    p = p - 1; //decrement
    printf("p = %0X\n", p );
    return 0;
}

Output:

p = 384042E4
p = 384042E8
p = 384042E4

Take a look at last digit of p. It is 4 then it is 8 then is back 4. That means we have changed the address where pointer p is pointing. We have incremented pointer with one, but we have got 4 numbers up. That is pointer arithmetic is "smart". It will give you next address for "int" type. Since my machine is on 32 bit, int occupy 4 bytes. So the increment it will sow me position for the next memory location after my integer.

Increment & Decrement

There are two specific operators to C:

You can use these two operators to perform increments and decrements of pointers. They will be type dependent for pointers. It will increment/decrements an address with the size of data type. If an address point to 4 bytes, the increment will be size of data type divided by 4.

Array Traversal

Arrays are defined in C as read only pointers to first element of array. So we can assign this pointer to another control pointer that is not read only. By using pointer arithmetic we can change control pointer to visit all elements of the array.

Example:

#include <stdio.h>
int main () {
    //define a vector of 10 elements
    int v[] = {10, 20, 30, 40, 50, 60, 70, 80, 90, 100};
    int i; //control variable
    int *p; //temporary pointer
    p = v; // same as &v
    printf("Address of v: %X\n", v ); // v is a read only pointer
    printf("Address of v: %X\n",&v ); // pointing to first element
    printf("Content of v: %d\n",*v ); // expect: 10 this is first element
    /* array traversal using pointer arithmetic */
    for ( i = 0; i < 10; i++, p++) {
        printf("v[%d] = %d\n", i, *p);
    }
    return 0;
}

Notes:

Comparing Pointers

Since the pointers are unsigned integer numbers, you can compare two pointers using relation operators. For array traversal you can detect if one element is precedent, current or next using < , = , > like in example below. 

#include <stdio.h>
int main () {
    //define a vector of 10 elements
    int v[] = {10, 20, 30, 40, 50, 60, 70, 80, 90, 100};
    //temporary pointer
    int *p;
    /* array traversal using pointer arithmetic */
    for ( p = &v[0]; p <= &v[9]; p++) {
        printf("%d,", *p);
    }
    return 0;
}

Array of Pointers

This is a strange thing. You can have a collection of pointers. These pointers can point to first element into another collection. The most common array of pointers is *char[]. It represents actually and array of strings, like in the following example:

#include <stdio.h>
int main () {
    char *capitals[] = {
        "Washington",
        "London",
        "Bucharest",
        "Moscow",
        "New Delhi"
    };
    int i = 0;
    for ( i = 0; i < 5; i++) {
        printf("capitals[%d] = %s\n", i, capitals[i] );
    }
    return 0;
}

Now you know almost everything about pointers. So we can continue with some juicy stuff: 

Pointer as result

You can use a pointer as a result of a function. Without pointers you can not return more than one single result, but using a pointer you can return a structure or array. There is a catch, the pointer or the structure must be allocated on the heap. A local array that is not dynamic allocated is on the stack and can not be returned as a result.

Rules:

Example:

#include <stdio.h>
#include <stdlib.h>
int *vector(int n)
{
    /* allocate memory on the heap */
    int *a = calloc(n, sizeof(int));
    if ( a != NULL ) {
        for( size_t i=0; i<n; i++ ) {
            a[i] = i + 1;
        }
    }
    return a;
}
int main () {
    int *v, i, x = 10;
    /* generate a vector with x number of elements */
    v = vector(x);
    /* array traversal using pointer arithmetic */
    for (i = 0; i < x; i++) {
        printf("%d,", *v);
        v++;
    }
    return 0;
}

Pointer to Struct

Pointers can be used to refer to a struct by its address. This is particularly useful for passing structs to a function by reference or to refer to another instance of the struct type as a field.

The pointer value can be refereed just like any other pointer, using star operator: "*". There is also a specific operator "->" which is referring to the value of a member of the struct.

Example:

#include <stdio.h>
/* declare a struct named point */
struct point {
    int x;
    int y;
};
int main() {
    struct point test = { 3, 7 }; //instance of point
    struct point *p = &test; //reference to struct instance
    // Using "*" to de-reference struct members
    printf("p.x = %d\n", (*p).x );
    printf("p.y = %d\n", (*p).y );
    (*p).x = 2; // alter first member of the struct
    (*p).y = 4; // alter second member of the struct
    // Using "->" to de-reference struct members
    printf("p.x = %d\n", p->x);
    printf("p.y = %d\n", p->y);
} 

Read next: Functions