//
//  pointer.c
//

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

static void addOneCalledByValue(uint16_t t);
static void addOneCalledByReference(uint16_t *t);

static void nullifyArray(uint16_t *array, uint16_t size);
static void printArray(const uint16_t *array, uint16_t size);

static uint16_t * sumVariables(uint16_t a, uint16_t b);

typedef struct {
    int16_t lat;
    int16_t lon;
    int16_t alt;
} GPS_Pos;

uint16_t global_var;
static uint16_t module_var;

const uint16_t const_global_var;
static const uint16_t const_module_var;

int main(int argc, const char * argv[]) {
    
    //Pointer
    printf("pointers...\n\n");
    
    uint16_t t = 1302;
    
        printf("t      => %u\n", t);
        printf("&t     => %p\n", &t);
    
    uint16_t* t_ptr = &t;
    
        printf("t_ptr  => %p\n", t_ptr);
    
    uint16_t t2 = *t_ptr;
    
        printf("t2     => %u\n", t2);
    
    t = 3;
    
        printf("t      => %u\n", t);
        printf("*t_ptr => %u\n", *t_ptr);
        printf("t2     => %u\n", t2);
        printf("t_ptr  => %p\n", t_ptr);
    
    
    
    
    //const Pointer vs. Pointer const
    printf("\n\nconst pointer...\n\n");
    
    uint16_t a = 2;
    uint16_t b = 4;
    
    const uint16_t * int_ptr_foo = &a;
    //*int_ptr_foo = 3;
    int_ptr_foo = &b;
    
    uint16_t * const int_ptr_bar = &a;
    *int_ptr_bar = 3;
    //int_ptr_bar = &b;
    
    
    
    
    //Pointer as parameter
    printf("\n\npointer as parameter...\n\n");
    
    addOneCalledByValue(t);
    
        printf("t      => %u\n", t);
        printf("&t     => %p\n", &t);
    
    addOneCalledByReference(&t);
    
        printf("t      => %u\n", t);
        printf("&t     => %p\n", &t);
    
    
    
    
    //Arrays
    printf("\n\narrays...\n\n");
    
    uint16_t array[] = {1302, 2110, 123, 456, 789};
    
        printf("array            => %p\n", array);
    
        printf("array[0]         => %u\n", array[0]);
        printf("array[3]         => %u\n", array[3]);
    
        printf("&(array[2])      => %p\n", &array[2]);
    
    uint16_t* array_ptr = array;
    
        printf("array_ptr        => %p\n", array_ptr);
    
        printf("*array_ptr       => %u)\n", (*array_ptr));
    
        printf("array_ptr + 2    => %p\n", array_ptr + 2);
        printf("*(array_ptr + 2) => %u\n", *(array_ptr + 2));
    
    nullifyArray(array, 5);
    
    printArray(array, 5);
    
    
    
    
    //NULL/invalid pointer
    printf("\n\nNULL/invalid pointer...\n\n");
    
    uint16_t *null_ptr = (uint16_t *)NULL; //0x0000000012345678
    
        printf("null_ptr         => %p\n", null_ptr);
    
    addOneCalledByReference(null_ptr);
    
    
    
    
    //Structs
    printf("\n\nstructs...\n\n");
    
    GPS_Pos pos = {123,456,789};
    
        printf("pos.lat          => %i\n", pos.lat);
        printf("pos.lon          => %i\n", pos.lon);
        printf("pos.alt          => %i\n", pos.alt);
    
    GPS_Pos* pos_ptr = &pos;
    
        printf("pos_ptr          => %p\n", pos_ptr);
    
        printf("(*pos_ptr).lat   => %i\n", (*pos_ptr).lat); // . hat hoehere Prioritaet als * !!!
        printf("(*pos_ptr).lon   => %i\n", (*pos_ptr).lon); // . hat hoehere Prioritaet als * !!!
        printf("(*pos_ptr).alt   => %i\n", (*pos_ptr).alt); // . hat hoehere Prioritaet als * !!!
    
        printf("pos_ptr->lat     => %i\n", pos_ptr->lat);
        printf("pos_ptr->lon     => %i\n", pos_ptr->lon);
        printf("pos_ptr->alt     => %i\n", pos_ptr->alt);
    
        printf("pos_ptr          => %p\n", pos_ptr);
        printf("&(pos_ptr->lat)  => %p\n", &(pos_ptr->lat));
        printf("&(pos_ptr->lon)  => %p\n", &(pos_ptr->lon));
        printf("&(pos_ptr->alt)  => %p\n", &(pos_ptr->alt));
    
    int16_t *lat = &(pos_ptr->lat);
    
    *lat = 3;
    
        printf("pos.lat          => %i\n", pos.lat);
    
    
    
    
    //function pointer...
    printf("\n\nfunction pointer...\n\n");
    
    uint16_t blub = 5;
    
    void (*addOne)(uint16_t *) = addOneCalledByReference;
    
        printf("blub             => %u\n", blub);
    
    addOne(&blub);
    
        printf("blub             => %u\n", blub);
    
    return 0;
}

static void addOneCalledByValue(uint16_t t){
    t = t + 1;
}

static void addOneCalledByReference(uint16_t *t){
    if(t != NULL){
        *t = *t + 1;
    }
}

static void nullifyArray(uint16_t *array, uint16_t size){
    for(uint16_t i = 0; i < size; i++){
        array[i] = 0;
    }
}

static void printArray(const uint16_t *array, uint16_t size){
    for(uint16_t i = 0; i < size; i++){
        printf("array[%u]         => %u\n", i, array[i]);
    }
}

static uint16_t * sumVariables(uint16_t a, uint16_t b) {
    uint16_t sum = a + b;
    
        printf("sum               => %u\n", sum);
    
    uint16_t *sum_ptr = &sum;
    
        printf("sum_ptr           => %p\n", sum_ptr);
    
    return sum_ptr; // &sum;
}
