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

/**
 * Primer demonstrira zašto je nekada važno proslediti dupli pokazivač.
 * Očekuje se da poziv druge funkcije (new_malloc_seg_fault) proizvede 
 * "segmentation fault" zbog pristupa nedozvoljenom regionu memorije.
*/

/**
 * @brief Funkcija koja ne bi trebalo da proizvede problem sa pristupom memoriji.
 * @details Funkcija prima dupli pokazivač, odnosno adresu koja pokazuje na
 * lokaciju pokazivača. Funkcija "malloc" vratiće kao rezultat pokazivač, odnosno
 * adresu zauzete memorije. Na lokaciju na koju ukazuje ptr_to_ptr smešta se ta
 * adresa. Recimo da se radi sa 32-bitnom little endian arhitekturom, na kojoj 
 * je vrednost pokazivača zapravo 4-bajtna adresa neke memorijske lokacije.
 * Analogija bi bila ista i za 64-bitnu arhitekturu sa 8-bajtnim adresama,
 * ali je manja veličina izabrana zarad lakše ilustracije.
 * 
 * Ovo je naša promenljiva ptr, koja čuva tu 4-bajtnu adresu, i nalazi se sama
 * na lokaciji čija je adresa npr. 0x12345678. Svako prikazano polje je jedan
 * bajt 4-bajtne adrese, koja je u početku postavljena na 0 (NULL pokazivač).
 * 
 *                          (0x12345678) ptr|  0x00  |
 *                                          |  0x00  |
 *                                          |  0x00  |
 *                                          |  0x00  |
 * 
 * Funkcija prima ptr_to_ptr, odnosno pokazivač na pokazivač, čija će vrednost
 * biti jednaka adresi našeg ptr pokazivača:
 
 * ptr_to_ptr|  0x78  |     (0x12345678) ptr|  0x00  |
 *           |  0x56  |                     |  0x00  |
 *           |  0x34  |                     |  0x00  |
 *           |  0x12  |                     |  0x00  |
 * 
 * Dakle, ptr_to_ptr je pokazivač na promenljivu ptr. Kada se pozove funkcija 
 * "malloc", ona će vratiti pokazivač, odnsno adresu zauzete memorije. 
 * Neka je adresa te memorije 0xABCDEF00. Kada se zapiše *ptr_to_ptr,
 * pristupa se sadržaju na koji pokazuje ptr_to_ptr, i tom sadržaju se 
 * dodeljuje vrednost 0xABCDEF00. Sadržaj na koji pokazuje ptr_to_ptr je
 * sadržaj promenljive ptr, pa sad stvari izgledaju ovako:
 * 
 * ptr_to_ptr|  0x78  |     (0x12345678) ptr|  0x00  |
 *           |  0x56  |                     |  0xEF  |
 *           |  0x34  |                     |  0xCD  |
 *           |  0x12  |                     |  0xAB  |
 * 
 * Ovime se postiže da pokazivač ptr zapravo sadrži adresu zauzete memorije,
 * odnosno da taj pokazivač ukazuje na memoriju zauzetu pomoću "malloc".
*/
void new_malloc_no_seg_fault(void** ptr_to_ptr, size_t size) {
    *ptr_to_ptr = malloc(size);
    return;
}

/**
 * @brief Funkcija koja proizvodi "segmentation fault".
 * @details Funkcija prima samo pokazivač, odnosno vrednost adrese.
 * Pokazivači se prosleđuju po vrednosti, kao i bilo koja druga vrednost
 * u C-u. Ovo znači da će se datoj funkciji proslediti samo kopija pokazivača
 * odnosno adrese koju on čuva, i ta adresa naći će se na stek frejmu konkretnog
 * poziva funkcije, kao i bilo koji drugi parametar funkcije. Funkcija "malloc" 
 * vratiće kao rezultat pokazivač, odnosno adresu zauzete memorije. Ta adresa
 * će se samo upisati na stek frejm, odnosno u kopiju prosleđenog pokazivača, pa
 * neće biti vidljiva van funkcije nakon njenog završetka.Recimo da se radi sa 
 * 32-bitnom little endian arhitekturom, na kojoj je vrednost pokazivača zapravo 
 * 4-bajtna adresa neke memorijske lokacije. Analogija bi bila ista i za 64-bitnu 
 * arhitekturu sa 8-bajtnim adresama, ali je manja veličina izabrana zarad lakše 
 * ilustracije.
 * 
 * Ovo je naša promenljiva ptr, koja čuva tu 4-bajtnu adresu, i nalazi se sama
 * na lokaciji čija je adresa npr. 0x12345678. Svako prikazano polje je jedan
 * bajt 4-bajtne adrese, koja je u početku postavljena na 0 (NULL pokazivač).
 * 
 *                          (0x12345678) ptr|  0x00  |
 *                                          |  0x00  |
 *                                          |  0x00  |
 *                                          |  0x00  |
 * 
 * Kada se taj pokazivač prosledi funkciji, na stek frejmu će se napraviti
 * njegova kopija:
 * 
 *                          (0x12345678) ptr|  0x00  |
 *                                          |  0x00  |
 *                                          |  0x00  |
 *                                          |  0x00  |
 *                                             ...
 *                                  ptr_copy|  0x00  |
 *                                          |  0x00  |
 *                                          |  0x00  |
 *                                          |  0x00  |
 *                                             ...
 * 
 * Kada se pozove funkcija "malloc", ona će vratiti pokazivač, odnsno adresu 
 * zauzete memorije. Neka je adresa te memorije 0xABCDEF00. Ta adresa biće 
 * dodeljena kao vrednost kopiji pokazivača, ptr_copy, dok će originalni
 * pokazivač, ptr, ostati nepromenjen:
 * 
 *                          (0x12345678) ptr|  0x00  |
 *                                          |  0x00  |
 *                                          |  0x00  |
 *                                          |  0x00  |
 *                                             ...
 *                                  ptr_copy|  0x00  |
 *                                          |  0xEF  |
 *                                          |  0xCD  |
 *                                          |  0xAB  |
 *                                             ...
 * 
 * Nakon završetka funkcije, kopija pokazivača se briše, a pokazivač ptr
 * ostaje i dalje nepromenjen. Kada se pokuša pristup adresi na koju on 
 * pokazuje, dobija se segmentation fault, jer se adresa zauzete memorije
 * nikada nije ni dodelila ovom pokazivaču.
*/
void new_malloc_seg_fault(void* ptr_copy, size_t size) {
    ptr_copy = malloc(size);
    return;
}

int main() {

    int* ptr;

    ptr = NULL;
    new_malloc_no_seg_fault((void**)&ptr, sizeof(int));
    *ptr = 5;
    printf("Passed the correct new malloc. Ptr points to %d.\n", *ptr);


    ptr = NULL;
    new_malloc_seg_fault((void*)ptr, sizeof(int));
    /**
     * Pokazivač ptr je neizmenjen. Menjana je samo njegova kopija.
     * Zbog toga se u liniji ispod pristupa nealociranoj memoriji
     * i dobija se "segmentation fault".
    */
    *ptr = 10;
    printf("Passed the incorrect new malloc. Ptr points to %d.\n", *ptr);

}