// main.c
// example for difference between call-by-value and call-by-reference
// see also http://th-nuremberg.de/roettger/index.php/C-Programmierung/Call-By-Value

#include <stdio.h> // header file contains function prototypes

double G = 9.81; // global variables are strictly forbidden
const double g = 9.81; // instead global constants are recommended

static double x = 3; // module-local variables are recommended as well

double square(double x); // function prototype: call-by-value
double potentiate(double b, int p); // function prototype: call-by-value

void vecadd(double *x, double *y, // call-by-reference (pointer declaration via *)
            double xa, double ya) // call-by-value (local parameter variables xa and ya)
{
    *x += xa; // unary dereferencing operator *
    *y += ya;
}

void swap(int *arr, int i, int j) // function implementation: array-pointer dualism
{
    int tmp = arr[i]; // equivalent to *(arr+i)
    arr[i] = arr[j];
    arr[j] = tmp;
}

int main() // main function
{
    // call function with value
    double s = square(3); // the value 3 is passed as a function parameter value

    // call function again with call-by-value
    double x2 = square(x); // x evaluates to the value 3 which is passed as parameter

    printf("square of %.3f is %.3f\n", x, x2);

    // call function with call-by-reference
    double x = 1; // local variable x
    double y = 2; // local variable y
    double xa = 3; // local variable xa
    double ya = 4; // local variable ya
    printf("vector addition of (%.3f, %.3f) and (%.3f. %.3f) is ", x,y, xa,ya);
    vecadd(&x,&y, xa,ya); // unary address operator &
    printf("(%.3f, %.3f)\n", x,y);

    // call function again via call-by-reference
    vecadd(&x,&y, 7,-1);

    printf("result of vector addition is (%.3f, %.3f)\n", x,y);

    // call function with array as parameter via call-by-reference
    int a[10] = {1,2,3,4,5,6,7,8,9,10};
    swap(a, 3, 8);

    for (int i=0; i<10; i++)
        printf("content at index %d is %d\n", i, a[i]);

    return(0); // returns #errors
}

double square(double x) // function implementation: call-by-value
{
    return(x * x); // binary multiplication operator *
}

double potentiate(double b, int p) // function implementation: multiple parameters
{
    double x = 1; // note: local x shadows module-local x

    for (int i=0; i<p; i++) // definite loop
        x *= b;

    return(x);
}

// note: compile and run with
// > gcc -std=c99 main.c -o main && ./main

/* example run:
square of 3.000 is 9.000
vector addition of (1.000, 2.000) and (3.000. 4.000) is (4.000, 6.000)
result of vector addition is (11.000, 5.000)
content of drawer 0 is 1
content of drawer 1 is 2
content of drawer 2 is 3
content of drawer 3 is 9
content of drawer 4 is 5
content of drawer 5 is 6
content of drawer 6 is 7
content of drawer 7 is 8
content of drawer 8 is 4
content of drawer 9 is 10
*/
