/*----------------------------0.1.c--------------------------*/
/* Hello, world! */

#include <stdio.h>

int main() {
  printf("Hello, world!\n");
  return 0;
}

/*----------------------------0.2.c--------------------------*/
/* Program ilustruje definisanje i ispis 
   celobrojnih promenljivih */

#include <stdio.h>

int main() {
  int a = 3, b = 5, c;
  c = a + b; 
  printf("Zbir je: %d\n", c);

  return 0;
}

/*----------------------------0.2b.c--------------------------*/
/* Program ilustruje ucitavanje, obradu i ispis celih brojeva - sabiranje dva uneta cela broja */
#include <stdio.h>

int main() {
  int a, b, c;
  printf("Unesi prvi broj : ");
  scanf("%d", &a);
  printf("Unesi drugi broj : ");
  scanf("%d", &b);
  c = a + b;
  printf("%d + %d = %d\n", a, b, c);
  return 0;
}

/*----------------------------0.3a.c--------------------------*/
/* Program ilustruje grananje (if) - 
   ispisuje se ukoliko je uneti ceo broj negativan */
#include <stdio.h>

int main() {
  int b;
  printf("Unesi ceo broj:");
  scanf("%d", &b);
  if (b < 0)
	printf("Broj je negativan\n");
  return 0;
}

/*----------------------------0.3b.c--------------------------*/
/* Program ilustruje blok {} */

#include <stdio.h>

int main() {
  int b;
  printf("Unesi ceo broj:");
  scanf("%d", &b);

  /* Ukoliko se telo if iskaza sastoji od vise iskaza, neophodno je
     koristiti blok {} */
  if (b < 0) {
    printf("Uneli ste broj %d\n", b);
    printf("Broj je negativan\n");
  }


  /* 
  Neispravno (bez obzira na ispravno nazubljivanje):
  if (b < 0)
     printf("Uneli ste broj %d\n", b);
     printf("Broj je negativan\n");
  */

  return 0;
}

/*----------------------------0.3c.c--------------------------*/
/* Program ilustruje grananje (if-else) -
   ispisuje se da li je broj negativan ili nije */

#include <stdio.h>

int main() {
  int b;
  printf("Unesi broj: ");
  scanf("%d", &b);

  if (b < 0)
	printf("Broj je negativan\n");
  else
	printf("Broj nije negativan\n");

  return 0;
}

/*----------------------------0.3d.c--------------------------*/
/* Program ilustruje visestruko grananje (if-else) - 
   ispituje se znak broja */
#include <stdio.h>

int main() {
  int b;
  printf("Unesi ceo broj : ");
  scanf("%d", &b);
  if (b < 0)
    printf("Broj je negativan\n");
  else  if (b == 0)
    printf("Broj je nula\n");
  else /* if (b > 0) */
    printf("Broj je pozitivan\n");

  /* Iako se prethodno nazubljivanje cesce koristi
     zbog preglednosti, sintaksna struktura koda
     u sustini odgovara sledecem:
     if (b < 0)
        printf("Broj je negativan\n");
     else
        if (b == 0)
           printf("Broj je nula\n");
        else
           printf("Broj je pozitivan\n");

     cela konstrukcija
         if (uslov) iskaz else iskaz
     predstavlja jedan iskaz te nisu neophodne
     zagrade.
   */

  return 0;
}

/*----------------------------0.3e.c--------------------------*/
/* Program ilustruje grananje (switch) - 
   ispituje se vrsta karaktera */

#include <stdio.h>

int main() {
  /* Cita se karakter sa standardnog ulaza */
  char c = getchar();
  switch(c) {
  case 'a':
  case 'e':
  case 'i':
  case 'o':
  case 'u':
	printf("Srpski samoglasnik\n");
	/* break; */
  case 'y':
	printf("Engleski samoglasnik\n");
	break;
  case ',':
  case '.':
  case ';':
  case ':':
	printf("Interpunkcijski znak\n");
	break;
  default:
	printf("Nesto drugo\n");
	break;
  }
  return 0;
}

/*----------------------------0.4a.c--------------------------*/
/* Program ilustruje petlju (while) */
#include <stdio.h>

int main() {
  int x;
	
  x = 1;
  while (x<10) {
    printf("x = %d\n",x);
    x++; /* x++ je isto kao i x=x+1 */
  }

  return 0;
}

/*----------------------------0.4b.c--------------------------*/
/* Program ilustruje petlju (do-while) */
#include <stdio.h>

int main() {
  int x;
	
  x = 1;
  do {
    printf("x = %d\n",x);
    x++; /* x++ je isto kao i x=x+1 */
  } while (x<=10);
}

/*----------------------------0.4c.c--------------------------*/
/* Program ilustruje petlju (for) */
#include <stdio.h>

int main() {
  int x;

  for (x = 1; x < 10; x++)
    printf("x = %d\n",x);

  return 0;
}

/*----------------------------0.4d.c--------------------------*/
/* Program ilustruje prekide petlje (continue, break) */
#include <stdio.h>

int main() {
  int i, j;

  for (i = 0; i < 10; i++) {
	if (i == 3)
	  break;   /* Prekid petlje */
	printf("i = %d\n", i);
  }

  for (j = 0; j < 10; j++) {
	if (j == 3)
	  continue; /* Prelazak na sledecu iteraciju */
	printf("j = %d\n", j);
  }

  
  return 0;
}

/*----------------------------0.5.c--------------------------*/
/* Program ilustruje definisanje funkcija - funkcija koja sabira dva broja */

#include <stdio.h>

/* Definicija funkcije */
int sum(int a, int b) {
  return a+b;
}

int main() {
  /* Poziv funkcije */
  printf("%d\n", sum(3,5));
  return 0;
}


/*----------------------------0.6.c--------------------------*/
/* Program ilustruje rad sa (staticki alociranim) nizovima - pronalazenje maksimalnog elementa niza */
#include <stdio.h>

int main() {
  int a[] = {5, 8, 1, 3, 9, 4, 7, 2};
  /* Ovo ne moze:
         int a[];
     Ovo moze:
         int a[10];
     Cak i ovo:
         int a[100] = {3, 4};
  */

  int n = sizeof(a)/sizeof(int);

  int i, max;

  max = a[0];
  for (i = 1; i < n; i++)
	if (a[i] > max)
	  max = a[i];

  printf("Najveci je %d\n", max);
}

/*----------------------------0.7.c--------------------------*/
/* Program ilustruje rad sa niskama karaktera - funkcija koja izracunava duzinu niske */
#include <stdio.h>

int strlen(char s[]) {
  int d = 0;
  while (s[d] != '\0')
	d++;
  return d;
}

int main() {
  char s[] = "Poruka";
  /* Moze i ovako:
	 char s[] = {'P', 'o', 'r', 'u', 'k', 'a', '\0'};
	 Obratiti paznju na dodatu nulu na kraju!
	 'a' je razlicito od "a"
  */
  printf("Broj alociranih karaktera: %d\n", 
		 sizeof(s)/sizeof(char));

  printf("Duzina niske \"%s\" je %d\n", s, strlen(s));
}

/*----------------------------0.8.c--------------------------*/
/* Program ilustruje strukture - duzina vektora */
#include <stdio.h>
#include <math.h>

int main() {
  /* Vektori predstavljeni uredjenim parom koordinata */
  struct vector {
	int x, y;
  };

  struct vector a = {3, 4};

  printf("Duzina: %f\n", sqrt(a.x*a.x + a.y*a.y));

  return 0;
}

/*----------------------------0.9.c--------------------------*/
/* Program ilustruje C pretrpocesor - direktiva #define */

#include <stdio.h>

/* Simbolicka konstanta */
#define BROJ 3

/* Kvadrat broja - ne radi u svim slucajevima */
#define square1(a) a*a

/* Kvadrat broja - ispravljena verzija */
#define square2(a) ((a)*(a))

/* Do problema dolazi jer C pretprocesor doslovno vrsi zamene -  
   pogledati obavezno program nakon faze pretprocesiranja: gcc -E 0.9.c
*/

int main() {
	printf("BROJ: %d\n", BROJ);
	printf("square1(3): %d\n", square1(3));
	printf("square1(3+2): %d\n", square1(3+2));
	printf("square2(3+2): %d\n", square2(3+2));
}

/*----------------------------0.10.c--------------------------*/
/* Program ilustruje globalne i lokalne promenljive */

#include <stdio.h>

/* Globalna promenljiva */
int a = 1;

void f() {
  /* Lokalna promenljiva */
  int a = 2;
  printf("a = %d\n", a); /* Odnosi se na lokalno a */
}

void g(int a) {
  printf("a = %d\n", a); /* Odnosi se na formalni parametar a */
}

int main() {
  printf("a = %d\n", a); /* Odnosi se na globalno a */
  f();
  g(3);
  return 0;
}

/*----------------------------1.1.c--------------------------*/
/* Celobrojni tipovi podataka */

/* Pogledati na primer: http://home.att.net/~jackklein/c/inttypes.html */

// C99 kod - npr. deklaracije nisu iskljucivo na pocetku bloka, komentari //, koristi se long long 

#include <stdio.h>
#include <limits.h>

int main() {
  /*
    Osnovni tipovi su odredjeni duzinom i nacinom zapisa:
    ---------------------------------------------------------------
                    | oznaceni (signed)    | neoznaceni (unsigned)
    ---------------------------------------------------------------
    karakteri       | signed char          | unsigned char
    (char)          |                      |
    ---------------------------------------------------------------
    kratki          | signed short int     | unsigned short int
    (short int)     |                      |
    ---------------------------------------------------------------
    dugacki         | signed long int      | unsigned long int
    (long int)      |                      |
    ---------------------------------------------------------------
    veoma dugacki   | signed long long int | unsigned long long int
    (long long int) |                      |
    - samo C99 -    |                      |
    ---------------------------------------------------------------


    Uobicajeni zapisi (vazi i na x86 + gcc platformi na kojoj radimo):
    ------------------------------------------------------------------
                    | oznaceni (signed)        | neoznaceni (unsigned)
    ------------------------------------------------------------------
    karakteri       | 1B = 8b                  | 1B = 8b
                    | [-2^7, 2^7-1] =          | [0, 2^8-1] = 
    (char)          | [-128, 127]              | [0, 255]
    ------------------------------------------------------------------
    kratki          | 2B = 16b                 | 2B = 16b
    (short int)     | [-32K, 32K-1] =          | [0, 64K-1] = 
                    | [-2^15, 2^15-1] =        | [0, 2^16-1] = 
                    | [-32768, 32767]          | [0, 65535]
    ------------------------------------------------------------------
    dugacki         | 4B = 32b                 | 4B = 32b
    (long int)      | [-2G, 2G-1] =            | [0, 4G-1] = 
                    | [-2^31, 2^31-1] =        | [0, 2^32-1] = 
                    | [-2147483648,2147483647] | [0, 4294967295]
    ------------------------------------------------------------------
    veoma dugacki   | 8B = 64b                 | 8B = 64b
    (long long int) | [-2^63, 2^63-1] =        | [0, 2^64-1] = 
                    | [-9.2*10^18, 9.2*10^18]  | [0, 1.84*10^19]
    ------------------------------------------------------------------

    Moguci su i izvedeni (skraceni) tipovi:

    char                 - podudara se sa signed char ili sa unsigned char - 
    nedefinisano standardom
                
    int se moze izostaviti:
    short                - isto sto i short int
    signed short         - isto sto i signed short int
    unsigned short       - isto sto i unsigned short int
    long                 - isto sto i long int
    signed long          - isto sto i signed long int
    unsigned long        - isto sto i unsigned long int
    long long            - isto sto i long long int
    signed long long     - isto sto i singed long long int
    unsigned long long   - isto sto i unsinged long long int
    signed               - isto sto i signed int
    unsinged             - isto sto i unsigned int

    signed/unsigned se moze izostaviti za int i tada se podrazumeva signed:
    int                  - isto sto i signed int
    short int            - isto sto i signed short int
    long int             - isto sto i signed long int
    long long int        - isto sto i signed long long int
 
    short/long/long long se moze izostaviti i tada se podrazumeva nativna duzina
    za masinu (obicno long):
    signed int           - obicno se podudara sa signed long int
    unsigned int         - obicno se podudara sa unsigned long int

    Iako se char cesto podudara sa signed char, to su razliciti tipovi podataka.
    Slicno vazi i za tipove int i long int.
  */

  /* Formati za funkciju printf koji se koriste u nastavku koda: 
     %d - dekadni oznaceni broj, %u - dekadni neoznaceni broj,  
     %x - heksadekadni neoznaceni broj, %c - karakter
     %l - dugacki, %ll veoma dugacki
  */
  
  /* Rasponi su definisani simbolickim konstantama u <limits.h> (???_MIN, ???_MAX) */

  signed char sc_min = SCHAR_MIN;
  signed char sc_max = SCHAR_MAX;
  printf("signed char: [%d, %d]\n", sc_min, sc_max);
  unsigned char uc_min = 0;
  unsigned char uc_max = UCHAR_MAX;
  printf("unsigned char: [%d, %d]\n", uc_min, uc_max);
  char c_min = CHAR_MIN;
  char c_max = CHAR_MAX;
  printf("char: [%d, %d]\n", c_min, c_max);
  printf("Number of bits in a character: %d\n", CHAR_BIT);
  printf("Size of character is %d byte\n", sizeof(char));

  int i_min = INT_MIN;
  int i_max = INT_MAX;
  printf("int: [%d, %d]\n", i_min, i_max);
  printf("Size of int is %d bytes\n", sizeof(int));

  signed short int ssi_min = SHRT_MIN;
  signed short int ssi_max = SHRT_MAX;
  printf("signed short int: [%d, %d]\n", ssi_min, ssi_max);
  unsigned short int usi_min = 0;
  unsigned short int usi_max = USHRT_MAX;
  printf("unsigned short int: [%u, %u]\n", usi_min, usi_max);
  printf("Size of short is %d bytes\n", sizeof(short));

  signed long int sli_min = LONG_MIN;
  signed long int sli_max = LONG_MAX;
  printf("signed long int: [%ld, %ld]\n", sli_min, sli_max);
  unsigned long int uli_min = 0;
  unsigned long int uli_max = ULONG_MAX;
  printf("unsigned long int: [%lu, %lu]\n", uli_min, uli_max);
  printf("Size of long is %d bytes\n", sizeof(long));

  signed long long int slli_min = LLONG_MIN;
  signed long long int slli_max = LLONG_MAX;
  printf("signed long long int: [%lld, %lld]\n", slli_min, slli_max);
  unsigned long long int ulli_min = 0;
  unsigned long long int ulli_max = ULLONG_MAX;
  printf("unsigned long long int: [%llu, %llu]\n", ulli_min, ulli_max);
  printf("Size of long long is %d bytes\n", sizeof(long long));

  
  /* Oznaceni brojevi. Obicno se koristi samo int. */
  int i1 = 10;          /* Dekadni celobrojni literal */
  printf("int i1 = 10; --> i1 = %d\n", i1);
  int i2 = 010;         /* Oktalni celobrojni literal */
  printf("int i2 = 010; --> i2 = %d\n", i2);
  int i3 = 0x10;        /* Heksadekadni celobrojni literal */
  printf("int i3 = 0x10; --> i3 = %d\n", i3);
  int i4 = -234;        /* Negativna vrednost */
  printf("int i4 = -234; %%d --> i4 = %d\n", i4);
  printf("int i4 = -234; %%u --> i4 = %u\n", i4);   /* Pogresno navedeno %u umesto %d */
  int i5 = INT_MAX + 1; /* Vece od najvece moguce vrednosti - prekoracenje */
  printf("int i5 = INT_MAX + 1; --> i5 = %d\n", i5);
  int i6 = 14+5*7;      /* Promenljiva se moze inicijalizovati i
                           konstantnim izrazom */
  printf("int i6 = 14+5*7; --> i6 = %d\n", i6);

  /* Neoznaceni brojevi. Obicno se koristi samo unsigned. */
  unsigned u1 = 10u;         /* Dekadni neoznaceni celobrojni literal */
  printf("unsigned u1 = 10u; --> u1 = %u\n", u1);
  unsigned u2 = 10U;         /* u ili U, svejedno je.*/
  printf("unsigned u2 = 10U; --> u2 = %u\n", u2);
  unsigned u3 = 10;         /* nekad moze i da se ne navede */
  printf("unsigned u3 = 10; --> u3 = %u\n", u3);
  unsigned u4 = 0xffffffffu; /* Heksadekadni neoznaceni celobrojni literal */
  printf("unsigned u4 = 0xffffffffu; %%u --> u3 = %u\n", u4);
  printf("unsigned u4 = 0xffffffffu; %%x --> u3 = %x\n", u4);
  printf("unsigned u4 = 0xffffffffu; %%d --> u3 = %d\n", u4);
  unsigned long u4 = 123456789ul; /* l (ili L) oznacava eksplicitno da
                                     je u pitanju dugacki broj*/
  printf("unsigned long u4 = 123456789ul; --> u4 = %lu\n", u4);

  /* Neoznaceni kratki brojevi - primeri prekoracenja i konverzija */
  unsigned short us1 = 1234u;    /* U redu */
  unsigned short us2 = 123456u;  /* Preveliki literal - ne moze da se smesti u unsigned short */
  unsigned short us3 = -1;      /* Negativan literal - ne moze da se smesti u unsigned short */
  unsigned short us4 = u1;      /* U redu - konverzija bez gubitka */
  unsigned short us5 = u3;      /* Konverzija sa gubitkom informacije */

  printf("unsigned short us1 = 1234; --> us1 = %u\n", us1);
  printf("unsigned short us2 = 123456; --> us2 = %u\n", us2);
  printf("unsigned short us3 = -1; --> us3 = %u\n", us3);
  printf("unsigned short us4 = u1; --> us4 = %u\n", us4);
  printf("unsigned short us5 = u3; --> us5 = %u\n", us5);

  /* Karakteri - prikaz sa %d i %c */
  char c1 = 65;
  printf("char c1 = 65; %%d --> c1 = %d\n", c1);
  printf("char c1 = 65; %%c --> c1 = %c\n", c1);

  char c2 = 'A';
  printf("char c2 = 'A'; %%d --> c1 = %d\n", c2);
  printf("char c2 = 'A'; %%c --> c1 = %c\n", c2);

  char c3 = '\x41';
  printf("char c3 = '\\x41'; %%d --> c1 = %d\n", c3);
  printf("char c3 = '\\x41'; %%c --> c1 = %c\n", c3);

  // Nema nikakve razlike izmedju c1, c2 i c3

  /* Specijalne sekvence: \n, \\, \t, ... */
  char c4 = '\n';
  printf("char c4 = '\\n'; %%d --> c4 = %d\n", c4);
  printf("char c4 = '\\n'; %%c --> c4 = %c\n", c4);

  char c5 = '\\';
  printf("char c5 = '\\\\'; %%d --> c4 = %d\n", c5);
  printf("char c5 = '\\\\'; %%c --> c4 = %c\n", c5);

  return 0;
}

/*----------------------------1.2.c--------------------------*/
/* Realni tipovi podataka */

/* C99 kod - npr. mesanje deklaracija i koda */

#include <stdio.h>
#include <float.h>

int main() {
  /* Rasponi */
  float f_min = FLT_MIN;
  float f_max = FLT_MAX;
  printf("float [%g, %g]\n", f_min, f_max);
  printf("float [%f, %f]\n", f_min, f_max);
  printf("float - decimal digits: %d\n", FLT_DIG);
  printf("Size of float is %d bytes\n", sizeof(float));

  double d_min = DBL_MIN;
  double d_max = DBL_MAX;
  printf("double [%g, %g]\n", d_min, d_max);
  printf("double [%f, %f]\n", d_min, d_max);
  printf("double - decimal digits: %d\n", DBL_DIG);
  printf("Size of double is %d bytes\n", sizeof(double));

  long double ld_min = LDBL_MIN;
  long double ld_max = LDBL_MAX;
  printf("long double [%Lg, %Lg]\n", ld_min, ld_max);
  printf("long double [%Lf, %Lf]\n", ld_min, ld_max);
  printf("long double - decimal digits: %d\n", LDBL_DIG);
  printf("Size of long double is %d bytes\n", sizeof(long double));

  float f1 = 1.3f;      /* f naglasava da je float literal u pitanju */
  printf("float f1 = 1.3f; --> f1 = %f\n", f1);
  float f2 = .3e7f;     /* Literali se mogu zapisivati i u naucnoj notaciji */
  printf("float f2 = .3e7f; --> f2 = %f\n", f2);
  float f3 = 34.56f;    /* Vrednosti se predstavljaju samo do na odredjenu preciznost */
  printf("float f3 = 34.56f; --> f3 = %f\n", f3);
  float f4 = 123456789;         /* Konverzija celobrojnog literala - opet problem sa preciznoscu */
  printf("float f4 = 123456789; --> f4 = %f\n", f4);
  float f5 = 0.1;       /* f nije navedeno - konverzija double literala */
  printf("float f5 = 0.1f; --> f5 = %f\n", f5);

  double d1 = 34.56;    /* Double ima vecu preciznost */
  printf("double d1 = 34.56f; --> d1 = %f\n", d1);
  double d2 = 123456789;
  printf("double d2 = 123456789; --> d2 = %f\n", d2);

}

/*----------------------------1.3.c--------------------------*/
/* Logicki tip - 0 - netacno, razlicito od 0 - tacno*/

// C99 kod - npr. mesanje deklaracija i koda, komentari oblika //, zaglavlje <stdbool.h>

#include <stdio.h>
#include <stdbool.h>

int main() {
  int a;

  printf("Unesite ceo broj: ");
  scanf("%d", &a);
  if (a)
	printf("Logicka vrednost broja %d je: tacno\n", a);
  else
	printf("Logicka vrednost broja %d je: netacno\n", a);

  /* C99 uvodi tip bool i konstante true i false - potrebno je ukljuciti <stdbool.h> */
  bool b1 = false, b2 = true;
  if (b1) printf("b1 je tacno\n");
  if (b2) printf("b2 je tacno\n");

  /* True ima vrednost 1, a false 0 */
  if (b1 == 0)
	printf("b1 = 0\n");
  if (b2 == 1) 
	printf("b2 = 1\n");
  if (b2 == 3) 
	printf("b2 = 3\n");
}


/*----------------------------1.4a.c--------------------------*/
/* Aritmeticki operatori -  sabiranje, oduzimanje, mnozenje, celobrojno i realno deljenje */

#include <stdio.h> 

int main()  {
  int a, b;
  printf("Unesi prvi broj : ");
  scanf("%d",&a);

  printf("Unesi drugi broj : ");
  scanf("%d",&b);

  printf("Zbir a+b je : %d\n",a+b); 
  printf("Razlika a-b je : %d\n",a-b); 
  printf("Proizvod a*b je : %d\n",a*b); 
  printf("Celobrojni kolicnik a/b je : %d\n", a/b);
  printf("Pogresan pokusaj racunanja realnog kolicnika a/b je : %f\n", a/b);
  printf("Realni kolicnik a/b je : %f\n", (float)a/(float)b);
  printf("Ostatak pri deljenju a/b je : %d\n", a%b);
}



/*----------------------------1.4b.c--------------------------*/
/* Aritmeticki operatori - celobrojno i realno deljenje */
#include <stdio.h>

main() {
  int a = 5;
  int b = 2;
  int d = a/b;    /* Celobrojno deljenje - rezultat je 2 */
  float c = a/b;  /* Iako je c float, vrsi se celobrojno deljenje jer su i a i b celi */

  /* Neocekivani rezultat 3.000000 */
  printf("c = %f\n",c); 
  printf("Uzrok problema : 5/2 = %f\n", 5/2); 
  printf("Popravljeno : 5.0/2.0 = %f\n", 5.0/2.0); 
  printf("Moze i : 5/2.0 = %f i 5.0/2 = %f \n", 5/2.0, 5.0/2); 
  printf("Za promenjive mora da se primeni operator konverzije tipa (cast): %f\n", (float)a/(float)b);
}

/*----------------------------1.4c.c--------------------------*/
/* Aritmeticki operatori - prefiksni i postfiksni operator ++ */

/* Operator ++ uvecava vrednost promenjive za 1. 
   Operator -- je potpuno analogan operatoru ++ osim sto umanjuje vrednost za 1 */

#include <stdio.h>
main()
{
  int x, y;
  int a = 0, b = 0;
 
  printf("Na pocetku : \na = %d\nb = %d\n", a, b);
  
  /* Ukoliko se vrednost izraza ne koristi, prefiksni i 
	 postfiksni operator se ne razlikuju */
  a++;
  ++b;
  printf("Posle : a++; ++b; \na = %d\nb = %d\n", a, b);
  
  /* Prefiksni operator uvecava promenjivu, i rezultat 
	 je uvecana vrednost */
  x = ++a;
  
  /* Postfiksni operator uvecava promenjivu, i rezultat je 
	 stara (neuvecana) vrednost */
  y = b++;
  
  printf("Posle : x = ++a; \na = %d\nx = %d\n", a, x);
  printf("Posle : y = b++; \nb = %d\ny = %d\n", b, y);
}

/*----------------------------1.5a.c--------------------------*/
/* Logicki i relacijski operatori - 
      manje(<), vece(>), jednako(==), razlicito(!=), manje jednako(<=), vece jednako(>=), i(&&), ili(||), ne(!)
*/
#include <stdio.h>

main() {
  /* Rezultat primene relacijskih operatora su logicke vrednosti koje
     se predstavljaju vrednoscu nula i nekom vrednoscu razlicitom od
     nule (najcesce je to 1) */
  printf("5<3 - %d\n5>3 - %d\n3==5 - %d\n3!=5 - %d\n", 5<3, 5>3, 3==5, 3!=5);

  /* Konjunkcija, disjunkcija i negacija su definisane nad logickim
     vrednostima */
  printf("Konjunkcija : 3>5 && 5>3 - %d\n", 3>5 && 5>3);
  printf("Disjunkcija : 3>5 || 5>3 - %d\n", 3>5 || 5>3);
  printf("Negacija : !(3>5) - %d\n", !(3>5));

  /* Aritmeticki operatori imaju veci prioritet u odnosu na
     relacijske, a ovi u odnosu na logicke pa zagrade u prethodnim
     izrazima kao ni u narednom izrazu nisu neophodne */
  printf("2+3 <= 4+5 && 1+2 >= 3+5 = %d\n", 2+3 <= 4+5 && 1+2 >= 3+5); 

  /* Ipak, negacija (kao unarni operator) ima prioritet u odnosu na
     sve binarne operatore pa je zagrada u izrazu !(3>5) neophodna */
}

/*----------------------------1.5b.c--------------------------*/
/* Logicki operatori - lenjo izracunavanje */

/* Prilikom izracunavanja izraza - A && B, ukoliko je A netacno, izraz B se ne izracunava.
   Prilikom izracunavanja izraza - A || B, ukoliko je A tacno, izraz B se ne izracunava.
*/

#include <stdio.h>

int b;

/* Funkcija ispisuje da je pozvana i uvecava promenjivu b.
   Funkcija uvek vraca vrednost 1 (tacno)
*/
int izracunaj() {
  printf("Pozvano izracunaj()\n");
  b++;
  return 1;
}

main() {
  int a;
  
  /* Funkcija izracunaj() ce se pozivati samo za parne vrednosti a */
  b = 0;
  for (a = 0; a < 10; a++)
	if (a%2 == 0 && izracunaj())
	  printf("Uslov ispunjen : a = %d, b = %d\n", a, b);
	else 
	  printf("Uslov nije ispunjen : a = %d, b = %d\n", a, b);

  printf("----------------------------\n");
  
  /* Funkcija izracunaj() ce se pozivati samo za neparne vrednosti a */
  b = 0;
  for (a = 0; a < 10; a++)
	if (a%2 == 0 || izracunaj())
	  printf("Uslov ispunjen : a = %d, b = %d\n", a, b);
	else 
	  printf("Uslov nije ispunjen : a = %d, b = %d\n", a, b);

}

/*----------------------------1.6a.c--------------------------*/
/* Operatori dodele - =, += */

#include <stdio.h>

int main() {
  /* Inicijalizacija je slicna dodeli, ali postoje razlike */
  int a = 3;
  printf("a = %d\n", a);

  /* Dodela je specijalni operator. Dodela je izraz, a ako se zavrsi
     sa ; postaje i iskaz (koji se veoma cesto koristi). */ 
  a = 3 + 5; /* a se postavlja na 8 */
  printf("a = %d\n", a);

  /* Proizvoljni izraz (ne samo dodela) moze da postane iskaz, ali
     uglavnom dodele (i izrazi sa bocnim efektima) imaju smisla */
  3 + 5; /* Ovaj izkaz nema puno smisla, ali je korektan */

  a = a + 3;  /* a se uvecava za 3 */
  printf("a = %d\n", a);

  a += 3;  /* a se uvecava za 3 - operator += */
  printf("a = %d\n", a);

  /* X += Y ne mora uvek da bude isto sto i X = X + Y;
     Npr. 
     a[f()] += 3           - garantuje se da se izraz f() jednom izracunava
     a[f()] = a[f()] + 3   - izraz f() se najverovatnije dva puta izracunava i 
                             moze da ima razlicitu vrednost pri svakom 
                             izracunavanju
  */
}

/*----------------------------1.6b.c--------------------------*/
/* Operator dodele - vrednost izraza dodele */

#include <stdio.h>

int main() {
  int a, b, c;

  /* Vrednost izraza dodele je vrednost njegove desne strane, pri cemu
     se, kao bocni efekat, ta vrednost smesta na adresu (u
     promenljivu) odredjenu njegovom levom stranom. */

  /* Ovo omogucava ulancavanje (pri cemu je zagrade moguce izostaviti
     zbog ugradjene desne asocijativnosti. */
  a = b = c = 3;
  printf("a = %d, b = %d, c = %d\n", a, b, c);

  /* Vrednost dodele se moze, na primer, iskoristiti da se veoma
     kompaktno iskaze citanje karaktera do pojave nekog terminirajuceg
     karaktera */
  while((c = getchar()) != '\n') 
    putchar(c); 

  /* Operatori dodele su veoma niskog prioriteta - nizeg od
     relacijskih. Zato su zagrade u izrazu (c = getchar()) != '\n'
     neophodne */

  /* Prethodni kod je ekvivalentan sa:
    c = getchar();
    while (c != '\n') {
       putchar(c);
       c = getchar();
    }
  */
}

/*----------------------------1.6c.c--------------------------*/
/* Odnos operatora dodele i poredjenja jednakosti */ 
#include <stdio.h>

int main()
{
  int b;
  printf("Unesi ceo broj : ");
  scanf("%d", &b);

  /* Obratiti paznju na = umesto == 
     Analizirati rad programa za razlicite ulaze. */
  if (b = 0)
	printf("Broj je nula\n");
  else if (b < 0)
	printf("Broj je negativan\n");
  else
	printf("Broj je pozitivan\n");
  return 0;
}


/*----------------------------1.7.c--------------------------*/
/* Uslovni ternarni operator - ?: */

#include <stdio.h>

int main() {
  int a = 3, b = 5;
  printf("min(%d, %d) = %d\n", a, b, a < b ? a : b);
  printf("max(%d, %d) = %d\n", a, b, a > b ? a : b);
}

/*----------------------------2.1.c--------------------------*/
/* if-else viseznacnost */

#include <stdio.h>

/* Bez obzir na nacin kako je kod nazubljen, 
   else se uvek odnosi na najblizi if */
int main() {
  int a = -3, b = -3;
  if (a > 0)
    if (b > 0)
      printf("b je pozitivan\n");
  else
    printf("a je negativan\n");

  /*
  C prevodilac kod tumaci na sledeci nacin:
  if (a > 0)
    if (b > 0)
      printf("b je pozitivan\n");
    else
      printf("a je negativan\n");

  Gornja struktura bi morala da se nametne kao:
  if (a > 0) {
    if (b > 0)
      printf("b je pozitivan\n");
  } else
    printf("a je negativan\n")

  */
  return 0;
}

/*----------------------------2.2a.c--------------------------*/
/* petlja sa dva brojaca */
#include <stdio.h>

int main() {
  int i, j;

  for (i = 0, j = 10; i < j; i++, j--)
	printf("i = %d,  j = %d\n", i, j);
  return 0;
}

/*----------------------------2.2b.c--------------------------*/
/* ugnjezdjene petlje */
#include <stdio.h>

#define MAX 3
/* int MAX = 3; */

int main() {
  int i, j;
  for (i = 0; i < MAX; i++)
	for (j = 0; j < MAX; j++) 
	  printf("i = %d,  j = %d\n", i, j);
  return 0;
}

/*----------------------------2.2c.c--------------------------*/
/* ugnjezdjene petlje - tablica mnozenja */
#include <stdio.h>

int main() {
  int i, j;

  printf("    |");
  for (j = 1; j <= 10; j++)
	  printf("%4d", j);
  printf("\n");

  for (j = 0; j < 45; j++)
	printf("-");
  printf("\n");
	
  for (i = 1; i <= 10; i++) {
	printf("%4d|", i);
	for (j = 1; j <= 10; j++) {
	  printf("%4d", i*j);
	}
	printf("\n");
  }
  return 0;
}

/*----------------------------2.3a.c--------------------------*/
/* atoi - konverzija niske karaktera u ceo broj */
#include <stdio.h>
#include <ctype.h>

unsigned atoi(char s[]) {
  unsigned v = 0, i;
  /* Na ASCII sistemima isdigit(c) je ekvivalentno sa:
     '0' <= c && c <= '9'. Ipak, preporucuje se koriscenje 
     funkcija iz <ctype.h>*/
  for (i = 0;  isdigit(s[i]); i++) 
    v = v * 10 + (s[i] - '0');
  return v;
}

int main() {
  char s[] = "1234abc";
  printf("Vrednost niske %s je %d\n", s, atoi(s));
  return 0;
}

/* Vezba: dopuniti funkciju tako da u obzir uzima i znak broja. */

/*----------------------------2.3b.c--------------------------*/
/* atof - konverzija niske karaktera s u realni broj */
#include <stdio.h>
#include <ctype.h>

double atof(char s[]) {
  double value, power;
  int i, sign;

  /* preskacemo pocetne beline */
  for (i=0; isspace(s[i]); i++)
    ;
  
  /* odredjujemo znak broja */
  sign = (s[i] == '-') ? -1 : +1;
  if (s[i] == '+' || s[i] == '-')
    i++;

  /* celobrojni deo */
  for (value = 0.0; isdigit(s[i]); i++)
    value = 10.0 * value + (s[i] - '0');
  
  /* preskacemo decimalnu tacku */
  if (s[i] == '.')
    i++;

  /* razlomljeni deo */
  for(power=1.0; isdigit(s[i]); i++) {
    value = 10.0 * value + (s[i] - '0');
    power *= 10.0;
  }
  
  /* izracunavamo i vracamo krajnji rezultat */
  return sign * value / power;
}

int main() {
  char s[] = "-123.456";
  printf("Vrednost niske %s je %f\n", s, atof(s));
  return 0;
}

/*----------------------------2.3c.c--------------------------*/
/* btoi - konverzija iz datog brojnog sistema u dekadni */
#include <stdio.h>
#include <ctype.h> 

/* Pomocna funkcija koja izracunava vrednost koju predstavlja karakter u datoj osnovi 
   Funkcija vraca -1 ukoliko cifra nije validna.
   
   Npr. 
   cifra 'B' u osnovi 16 ima vrednost 11
   cifra '8' nije validna u osnovi 6

*/
   
int digit_value(char c, int base) {
  /* Proveravamo obicne cifre */
  if (isdigit(c) && c < '0'+base)
	return c-'0';

  /* Proveravamo slovne cifre za mala slova */
  if ('a'<=c && c < 'a'+base-10)
	return c-'a'+10;

  /* Proveravamo slovne cifre za velika slova */
  if ('A'<=c && c < 'A'+base-10)
	return c-'A'+10;
  
  return -1;
}

/* Funkcija izracunava vrednost celog broja koji je zapisan u datom 
   nizu karaktera u datoj osnovi. Za izracunavanje se koristi Hornerova shema. 
*/
int btoi(char s[], int base) {
  int sum = 0;
  
  /* Obradjuju se karakteri sve dok su cifre */
  int i, vr;
  for (i = 0; (vr = digit_value(s[i], base)) != -1; i++)
	sum = base*sum + vr;
  
  return sum;
  
}

int main() {
  char bin[] = "11110000";
  char hex[] = "FF";

  printf("Dekadna vrednost binarnog broja %s je %d\n", bin, btoi(bin, 2));
  printf("Dekadna vrednost heksadekadnog broja %s je %d\n", hex, btoi(hex, 16));
  
  return 0;
}

/*----------------------------2.4a.c--------------------------*/
/* Mnozenje preko sabiranja */
#include <stdio.h>

int main() {
  unsigned x, y, z, i;

  /* Unos sabiraka */
  printf("Unesi x i y: ");
  scanf("%u %u", &x, &y);

  /* Proizvod se inicijalizuje na 0 */
  z = 0;
  /* Zatim se x puta proizvod uveca za y */
  for (i = 0; i < x; i++)
    z += y;

  printf("Proizvod je: %u\n", z);

  /*
    Nekoliko alternativnih formulacija istog algoritma:

    while petlja: 
    -------------
    z = 0;
    i = 0;
    while(i < x) {
      z = z + y;
      i = i + 1;
    }


    kombinovanje izraza koriscenjem , u for petlji:
    -----------------------------------------------
    for (z = 0, i = 0; i < x; z+=y, i++)
          ;

    izbegavanje pomocne promenljive uz izmenu promenljive x:
    --------------------------------------------------------
    z = 0;
    while(x > 0) {
      z += y;
      x--;
    }

  */
  return 0;
}

/*----------------------------2.4b.c--------------------------*/
/* Stepenovanje preko mnozenja */
#include <stdio.h>

int main() {
  float x, s;
  unsigned i, n;

  /* Unos cinilaca */
  printf("Unesi x i n: ");
  scanf("%f %u", &x, &n);

  /* Stepen se inicijalizuje na 1.0 */
  s = 1.0;
  /* Zatim se n puta pomnozi sa x */
  for (i = 0; i < n; i++)
    s *= x;

  printf("Stepen je: %f\n", s);

  /*
    Nekoliko alternativnih formulacija istog algoritma:

    s = 1.0;
    i = 0;
    while(i < n) {
      s = s * x;
      i = i + 1;
    }



    for (s = 1.0, i = 0; i < n; s*=x, i++)
          ;


    s = 1.0;
    while (n > 0) {
       s *= x;
       n--;
    }
  */
  return 0;
}

/*----------------------------2.4c.c--------------------------*/
/* power - funkcija za stepenovanje - obuhvaceni i negativni izlozioci */
#include <stdio.h>

/* stepenuje x^k tako sto k puta pomnozi x */
float power(float x, unsigned n) {
  unsigned i;
  float s = 1.0;
  for (i = 0; i<n; i++)
    s*=x;
  return s;
}

/* Verzija koja radi i za negativne izlozioce */
float power_n(float x, int n) {
  unsigned i;
  int negative = n<0;

  if (negative)
    n = -n;

  float s = 1;
  for (i = 0; i < n; i++)
    s*=x;
    
  return negative ? 1.0/s : s;  
}

int main() {
  printf("%f\n", power(2.0, 8));
  printf("%f\n", power_n(2.0, -3));
  return 0;
}

/*----------------------------2.5a.c--------------------------*/
/* Deljenje preko oduzimanja */
#include <stdio.h>

int main() {
  unsigned x = 19, y = 5, q, r;
  /* Kolicnik i ostatak su takvi brojevi q i r
	 za koje vazi: 
	    x = q*y + r,  0 <= r < y
  */

  /* Inicijalno postavljamo q na 0 i uvecavamo ga postepeno za po
	 jedan, podesavajuci r tako da sve vreme zadovoljava uslov x = q*y
	 + r.  Iteracija se prekida u trenutku kada r postane manje od y.
  */
  q = 0; r = x;
  while (r >= y) {
	q++;
	r-=y;
  }

  printf("Kolicnik: %u, ostatak: %u\n", q, r);
  return 0;
}

/*----------------------------2.6a.c--------------------------*/
/* Euklidov algoritam za odredjivanje NZD - preko oduzimanja -
   rekurzivna definicija */
#include <stdio.h>

/* O rekurziji vise u kursu P2 - predstavlja prirodan nacin za
   formulaciju nekih algoritama. */
unsigned nzd(unsigned a, unsigned b) {
  /* printf("%u, %u\n", a, b); */
  if (a == 0)
    return b;
  if (b == 0)
    return a;
  if (a > b)
    return nzd(a - b, b);
  else
    return nzd(a, b - a);
}


int main() {
  unsigned a = 105, b = 252;
  printf("NZD(%u, %u) = %u\n", a, b, nzd(a, b));
  return 0;
}

/*----------------------------2.6b.c--------------------------*/
/* Euklidov algoritam za odredjivanje NZD - preko oduzimanja - uklonjena rekurzija */
#include <stdio.h>

unsigned nzd__(unsigned a, unsigned b) {
  /* Beskonacna petlja - oslanjamo se na cinjenicu da return naredba
	 prekida petlju */
  while (true) {
	/* printf("%u, %u\n", a, b); */
    if (a == 0)
      return b;
    if (b == 0)
      return a;
    if (a > b)
      a -= b;
    else
      b -= a;
  }
}

unsigned nzd_(unsigned a, unsigned b) {
  /* Uklonjena beskonacna petlja */
  while (a != 0 && b != 0) {
	/* printf("%u, %u\n", a, b); */
    if (a > b)
       a -= b;
    else
      b -= a;
  }
  if (a == 0)
	return b;
  if (b == 0)
	return a;
}


/* Uslov a == 0 u prethodnoj funkciji je moguc samo na pocetku, posto
   se u slucaju da je a == b umanjuje b. Ovim se implementacija moze
   ubrzati. */
unsigned nzd(unsigned a, unsigned b) {
  if (a == 0)
	return b;

  while (b != 0) {
	/* printf("%u, %u\n", a, b); */
	if (a > b)
	  a -= b;
	else
	  b -= a;
  }

  return a;
}


int main() {
  unsigned a = 105, b = 252;
  printf("NZD(%u, %u) = %u\n", a, b, nzd(a, b));
  return 0;
}

/*----------------------------2.6c.c--------------------------*/
/* Euklidov algoritam za odredjivanje NZD - preko deljenja -
   rekurzivna definicija*/
#include <stdio.h>

/* O rekurziji vise u kursu P2 - predstavlja prirodan nacin za
   formulaciju nekih algoritama. */
unsigned nzd(unsigned a, unsigned b) {
  /* printf("%u, %u\n", a, b); */
  if (b == 0)
	return a;
  else
	return nzd(b, a % b);
}

int main() {
  unsigned a = 105, b = 252;
  printf("NZD(%u, %u) = %u\n", a, b, nzd(a, b));
  return 0;
}

/*----------------------------2.6d.c--------------------------*/
/* Euklidov algoritam za odredjivanje NZD - preko deljenja - uklonjena rekurzija */
#include <stdio.h>

unsigned nzd(unsigned a, unsigned b) {
  while (b != 0) {
    unsigned r = a % b;
    a = b;
    b = r;
  }
  return a;
}

int main() {
  unsigned a = 105, b = 252;
  printf("NZD(%u, %u) = %u\n", a, b, nzd(a, b));
  return 0;
}

/*----------------------------3.1.c--------------------------*/
/* Demonstrira zivotni vek i oblasti vazenja promenjivih (scope) */
#include <stdio.h>

/* Globalna promenjiva */
int a = 0; 

/* Uvecava se globalna promenjiva a */ 
void increase() {
  a++;
  printf("increase::a = %d\n", a);
}

/* Umanjuje se lokalna promenjiva a. Globalna promenjiva zadrzava svoju vrednost. */
void decrease() {
  /* Ovo a je nezavisna promenjiva u odnosu na globalno a */
  int a = 0;
  a--;
  printf("decrease::a = %d\n", a);

}

void nonstatic_var() {
  /* Nestaticke promenjive ne cuvaju vrednosti kroz pozive funkcije */
  int s=0;
  s++;
  printf("nonstatic::s=%d\n",s);
}

void static_var() {
  /* Staticke promenjive cuvaju vrednosti kroz pozive funkcije. 
	 Inicijalizacija se odvija samo u okviru prvog poziva. */
  static int s=0;
  s++;
  printf("static::s=%d\n",s);
}

main() {
  /* Promenjive lokalne za funkciju main */
  int i;
  int x = 3;
  
  printf("main::x = %d\n", x);
  
  
  for (i = 0; i<3; i++) {
	/* Promenjiva u okviru bloka je nezavisna od spoljne promenjive.
	   Ovde se koristi promenjiva x lokalna za blok petlje koja ima 
	   vrednost 5, dok originalno x i dalje ima vrednost 3*/
	int x = 5;
	printf("for::x = %d\n", x);
  }
  
  /* U ovom bloku x ima vrednost 3 */
  printf("main::x = %d\n", x);
  
  increase();
  decrease();
  
  /* Globalna promenjiva a */
  printf("main::a = %d\n", a);
  
  /* Demonstracija nestatickih promenjivih */
  for (i = 0; i<3; i++)
	nonstatic_var();
  
  /* Demonstracija statickih promenjivih */
  for (i = 0; i<3; i++)
	static_var();
}


/*----------------------------3.2a.c--------------------------*/
/* Deklaracije i definicije - sum - verzija sa definicijom */

/* Definicija funkcije */
int sum(int a, int b) {
  return a+b;
}

int main() {
  /* Poziv funkcije */
  printf("%d\n", sum(3,5));
  /* Neispravan poziv bi prijavio gresku */
  /* printf("%d\n", sum(3)); */

  return 0;
}

/*----------------------------3.2b.c--------------------------*/
/* Deklaracije i definicije - sum - verzija sa deklaracijom */

/* Prototip (deklaracija) funkcije */
int zbir(int, int);

int main() {
  /* Poziv funkcije */
  printf("%d\n", zbir(3,5));
  /* Neispravan poziv bi prijavio gresku */
  /* printf("%d\n", zbir(3)); */

  return 0;
}

/* Definicija funkcije */
int zbir(int a, int b) {
  return a+b;
}

/*----------------------------3.2c.c--------------------------*/
/* Deklaracije i definicije - sum - verzija bez deklaracije */

int main() {
  /* Poziv funkcije */
  printf("%d\n", zbir(3,5));
  /* Neispravan poziv ne prijavljuje gresku */
  printf("%d\n", zbir(3));

  return 0;
}

/* Definicija funkcije */
int zbir(int a, int b) {
  return a+b;
}

/*----------------------------3.3a.c--------------------------*/
/* Demonstrira prenos nizova brojeva u funkciju - 
   funkcija za ispis niza brojeva */

#include <stdio.h>

/* Nizovi se prenose tako sto se prenese adresa njihovog pocetka.
   Uglaste zagrade ostaju prazne!
   Nizove je neophodno prenositi zajedno sa dimenzijom niza 
   (osim niski karaktera)
*/
void print_array(int a[], int n) {
  int i;
  for (i = 0; i < n; i++)
	printf("%d ",a[i]);
  putchar('\n');

  /* Obratite paznju na ovo : */
  printf("sizeof(a) - u okviru fje : %d\n", sizeof(a));
}

int main() {
	int a[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};

	printf("sizeof(a) - u okviru main : %d\n", sizeof(a));
	print_array(a, sizeof(a)/sizeof(int));

	return 0;
}

/*----------------------------3.3b.c--------------------------*/
/* Demonstrira prenos niske karaktera u funkciju - 
   funkcija za ispis niske karaktera */
#include <stdio.h>

/* Uz nisku karaktera nije potrebno prenositi dimenziju ukoliko se postuje 
   dogovor da se svaka niska zavrsava karakterom '\0'. */
void print_string(char s[]) {
  int i;
  for (i = 0; s[i]; i++)
	putchar(s[i]);
}


int main() {
  char s[] = "Zdravo\n";
  print_string(s);
  s[2] = '\0';
  print_string(s);
  return 0;
}

/*----------------------------3.3c.c--------------------------*/
/* Demonstrira prenos parametara po vrednosti 
	- preneti parametri se ne mogu menjati */
#include <stdio.h>

/* Funkcija pokusava da ucita ceo broj. 
   Zbog prenosa parametara po vrednosti ovo ne uspeva */
void get_num(int a)
{
	scanf("%d", &a);
	printf("a = %d\n", a);
}


main()
{
	int x = 0;
	printf("Unesi broj : ");
	get_num(x);
	printf("x = %d\n", x);
}

/*----------------------------3.3d.c--------------------------*/
/* Demonstrira prenos nizova u funkciju - preneti niz se moze menjati */

#include <stdio.h>

/* Funkcija ucitava rec sa standardnog ulaza i smesta je u niz karaktera s.
   Ovo uspeva zbog toga sto se po vrednosti prenosi adresa pocetka niza, 
   a ne ceo niz */
void get_word(char s[])
{
	int c, i = 0;	
	while (!isspace(c=getchar()))
		s[i++] = c;
	s[i] = '\0';
}

main()
{
	/* Obavezno je alocirati memoriju za niz karaktera */
	char s[100];

	get_word(s);
	printf("%s\n", s);
}

/*----------------------------4.1.c--------------------------*/
/* Pokazivaci - osnovni pojam */
#include <stdio.h>
main() {
  int x = 3;
  
  /* Adresu promenjive x zapamticemo u novoj promeljivoj.
	 Nova promenljiva je tipa pokazivaca na int (int*) */
  int* px; 
  /* isto je i int *px; */
  /* int* px, py; -> tumaci se kao int *px, py; */
        

  printf("Adresa promenljive x je : %p\n", &x);
  printf("Vrednost promenljive x je : %d\n", x);
  
     
  px = &x;
  printf("Vrednost promenljive px je (tj. px) : %p\n", px);
  printf("Vrednost promenljive na koju ukazuje px (tj. *px) je : %d\n", *px);
  
  /* Menjamo vrednost promenljive na koju ukazuje px */
  *px = 6;
  printf("Vrednost promenljive na koju ukazuje px (tj. *px) je : %d\n", *px);
  
  /* Posto px sadrzi adresu promenljive x, ona ukazuje na x tako da je 
	 posredno promenjena i vrednost promenljive x */
  printf("Vrednost promenljive x je : %d\n", x);
  

}


/*----------------------------4.2a.c--------------------------*/
/* Demonstrira prenos argumenata preko pokazivaca - swap */
#include <stdio.h>

/* Pogresna verzija funkcije swap. Zbog prenosa po vrednosti, funkcija 
   razmenjuje kopije promenljivih iz main-a, a ne samih promenljivih */
void swap_wrong(int x, int y)
{
	int tmp;
	
	printf("swap_wrong: ");
	printf("Funkcija menja vrednosti promenljivim na adresama : \n");
	printf("x : %p\n", &x);
	printf("y : %p\n", &y);
	
	
	tmp = x;
	x = y;
	y = tmp;
}

/* Resenje je prenos argumenata preko pokazivaca */
void swap(int* px, int* py)
{
	int tmp;
	
	printf("swap : Funkcija menja vrednosti promenljivim na adresama : \n");
	printf("px = %p\n", px);
	printf("py = %p\n", py);
	
	tmp = *px;
	*px = *py;
	*py = tmp;
}

main()
{
	int x = 3, y = 5;
	printf("Adresa promenljive x je %p\n", &x);
	printf("Vrednost promenljive x je %d\n", x);
	printf("Adresa promenljive y je %p\n", &y);
	printf("Vrednost promenljive y je %d\n", y);	
	
	/* Pokusavamo zamenu koristeci pogresnu verziju funkcije */
	swap_wrong(x, y);
	
	printf("Posle swap_wrong:\n");
	printf("Vrednost promenljive x je %d\n", x);
	printf("Vrednost promenljive y je %d\n", y);
	
	/* Vrsimo ispravnu zamenu. Funkciji swap saljemo adrese promenljvih 
	   x i y, a ne njihove vrednosti */
	swap(&x, &y);
	
	printf("Posle swap:\n");
	printf("Vrednost promenljive x je %d\n", x);
	printf("Vrednost promenljive y je %d\n", y);
}


/*----------------------------4.2b.c--------------------------*/
/* Demonstrira vise povratnih vrednosti funkcije koristeci prenos preko 
   pokazivaca */

/* Funkcija istovremeno vraca dve vrednosti - kolicnik i ostatak dva
   data broja.  Ovo se postize tako sto se funkciji predaju vrednosti
   dva broja (x i y) koji se dele i adrese dve promenljive na koje ce
   se smestiti rezultati */
void div_and_mod(int x, int y, int* div, int* mod) {
  printf("Kolicnik postavljam na adresu : %p\n", div);
  printf("Ostatak postavljam na adresu : %p\n", mod);
  *div = x / y;
  *mod = x % y;
}

int main() {
  int div, mod;
  printf("Adresa promenljive div je %p\n", &div);
  printf("Adresa promenljive mod je %p\n", &mod);

  /* Pozivamo funkciju tako sto joj saljemo vrednosti dva broja (5 i 2)
	 i adrese promenljvih div i mod na koje ce se postaviti rezultati */
  div_and_mod(5, 2, &div, &mod);
	
  printf("Vrednost promenljive div je %d\n", div);
  printf("Vrednost promenljive mod je %d\n", mod);
	
  return 0;
}


/*----------------------------4.3.c--------------------------*/
/* Demonstrira pokazivacku aritmetiku */

#include <stdio.h>

int main() {
  char s[] = "abcde";
  int t[] = {1, 2, 3, 4, 5};
	
  /* Inicijalizujmo pokazivace ps i pt na pocetke nizova s i t */
  char* ps = &s[0];
  int* pt =  &t[0];
	
  /* Pokazivace je moguce sabirati sa celim brojevima i 
	 od njih je moguce oduzimati cele brojeve*/
  /* Ispisimo vrednosti pokazivaca */
  printf("ps = %p\n", ps);
  printf("ps+1 = %p\n", ps+1);
  printf("ps+2 = %p\n", ps+2);
  printf("ps-1 = %p\n", ps-1);
  printf("ps-2 = %p\n", ps-2);

	
  /* Prilikom sabiranja pokazivaca i celih brojeva, 
	 dodaje se velicina odgovarajuceg tipa. */
  printf("pt = %p\n", pt);
  printf("pt+1 = %p\n", pt+1);
  printf("pt+2 = %p\n", pt+2);
  printf("pt-1 = %p\n", pt-1);
  printf("pt-2 = %p\n", pt-2);
	
  /* Na pokazivace je moguce primenjivati i operatore ++ i -- */
  for (ps = s; *ps; ps++)
	putchar(*ps);
  putchar('\n');
	
  /* Slicno, dva pokazivaca istog tipa se mogu oduzimati. Prilikom sracunavanja
	 rezultata, uzima se u obzir velicina tipa. */
  ps = &s[3];
  printf("s = %p\n", s);
  printf("ps = %p\n", ps);
  printf("ps - s = %d\n", ps - s);
  pt = &t[3];
  printf("t = %p\n", t);
  printf("pt = %p\n", pt);
  printf("pt - t = %d\n", pt - t);	

  return 0;
}


/*----------------------------4.4.c--------------------------*/
/* Demonstrira vezu izmedju pokazivaca i nizova */

#include <stdio.h>

void print_array(int* pa, int n);

int main() {
  int a[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
  int num_of_elements = sizeof(a)/sizeof(int);
  int* pa;

  /* Niz je isto sto i adresa njegovog prvog elementa */
  printf("Niz a : %p\n", a);
  printf("Adresa prvog elementa niza a (&a[0]) : %p\n", &a[0]);
	
  /* Moguce je dodeliti niz pokazivacu odgovarajuceg tipa */
  pa = a;
	
  printf("Pokazivac pa ukazuje na adresu : %p\n", pa);
	
  /* Nizu nije moguce dodeljivati vrednost
	 (nizove mozemo smatrati KONSTANTNIM pokazivacima na prvi element) */
  /* a = pa; */

  /* Niz je moguce koristiti kao pokazivac tj. vaze pravila pokazivacke aritmetike */
  printf("a + 3 = %p\n", a + 3);

  /* Vazi da je 
	 a + i =  &a[i]  
	 odnosno 
	 *(a + i) = a[i]
  */
  printf("&a[3] = %p\n", &a[3]);

  /* Identiteti
	 a + i =  &a[i]  
	 odnosno 
	 *(a + i) = a[i]
	 vazi i za pokazivace i za nizove 
  */
	
  /* Pokazivace je na osnovu prethodnog moguce indeksirati kao nizove */
  printf("pa[5] = %d\n", pa[5]);
  printf("*(pa + 5) = %d\n", *(pa+5));
	
	
  /* Medjutim, sizeof(pa) je samo velicina pokazivaca, a ne niza */
  printf("sizeof(a) = %d\n", sizeof(a));
  printf("sizeof(pa) = %d\n", sizeof(pa));
	
  /* Pozivamo funkciju za stampanje niza i saljemo joj niz */
  print_array(a, num_of_elements);
  /* Pozivamo funkciju za stampanje niza i saljemo joj pokazivac na pocetak niza */
  print_array(pa, num_of_elements);

  return 0;
}

/* Proslednjivanje niza u funkciju 
   	void print_array(int pa[], int n);
   je ekvivalentno prosledjivanju pokazivaca u funkciju 
   	void print_array(int* pa, int n);
   Izmedju ovih konstrukcija nema nikakve razlike.
*/
void print_array(int* pa, int n)
{
	int i;
	for (i = 0; i<n; i++)
		printf("%d ", pa[i]);
	putchar('\n');
}

/*----------------------------4.5a.c--------------------------*/
/* strlen, strcpy, strcat, strcmp, strchr, strstr - 
   verzije sa nizovima */
/* Vezbe radi, implementirane su funkcije biblioteke string.h */
#include <stdio.h>

/* Izracunava duzinu stringa */
int string_length(char s[])
{
	int i;
	for (i = 0; s[i]; i++)
		;
	return i;
}


/* Kopira string src u string dest. 
  Pretpostavlja da u dest ima dovoljno prostora. */
void string_copy(char dest[], char src[])
{
	/* Kopira karakter po karakter, sve dok nije iskopiran karakter '\0' */
	int i;
	for (i = 0; (dest[i]=src[i]) != '\0'; i++)
		;

	/* Uslov != '\0' se, naravno, moze izostaviti :
	
	for (i = 0; dest[i]=src[i]; i++)
		;
	*/
	
}

/* Nadovezuje string t na kraj stringa s. 
   Pretpostavlja da u s ima dovoljno prostora. */
void string_concatenate(char s[], char t[])
{
	int i, j;
	/* Pronalazimo kraj stringa s */
	for (i = 0; s[i]; i++)
		;
	
	/* Vrsi se kopiranje, slicno funkciji string_copy */
	for (j = 0; s[i] = t[j]; j++, i++)
		;
}

/* Vrsi leksikografsko poredjenje dva stringa. 
    Vraca :
        0 - ukoliko su stringovi jednaki
        <0 - ukoliko je s leksikografski ispred t
        >0 - ukoliko je s leksikografski iza t
*/
int string_compare(char s[], char t[])
{
	/* Petlja tece sve dok ne naidjemo na prvi razliciti karakter */
	int i;
	for (i = 0; s[i]==t[i]; i++)
		if (s[i] == '\0') /* Naisli smo na kraj oba stringa, 
				     a nismo nasli razliku */
			return 0;

	/* s[i] i t[i] su prvi karakteri u kojima se niske razlikuju. 
	   Na osnovu njihovog odnosa, odredjuje se odnos stringova */
	return s[i] - t[i];
}

/* Pronalazi prvu poziciju karaktera c u stringu s, odnosno -1 
   ukoliko s ne sadrzi c */
int string_char(char s[], char c)
{
	int i;
	for (i = 0; s[i]; i++)
		if (s[i] == c)
			return i;
		/* nikako 
		else 
			return -1;
		*/			
	/* Nije nadjeno */				
	return -1;
}

/* Pronalazi poslednju poziciju karaktera c u stringu s, odnosno -1 
   ukoliko s ne sadrzi c */
int string_last_char(char s[], char c)
{
	/* Pronalazimo kraj stringa s */
	int i;
	for (i = 0; s[i]; i++)
		;
	
	/* Krecemo od kraja i trazimo c unazad */
	for (i--; i>=0; i--)
		if (s[i] == c)
			return i;
			
	/* Nije nadjeno */				
	return -1;
	
	/*
	Koristeci string_length :
		
	for (i = string_length(s) - 1; i>0; i--)
		if (s[i] == c)
			return i;
			
	return -1;	 
	*/
}

/* Proverava da li string str sadrzi string sub.
   Vraca poziciju na kojoj sub pocinje, odnosno -1 ukoliko ga nema 
*/
int string_string(char str[], char sub[])
{
	int i, j;
	/* Proveravamo da li sub pocinje na svakoj poziciji i */
	for (i = 0; str[i]; i++)
		/* Poredimo sub sa str pocevsi od poziciji i 
		   sve dok ne naidjemo na razliku */
		for (j = 0; str[i+j] == sub[j]; j++)
			/* Nismo naisli na razliku a ispitali smo 
			   sve karaktere niske sub */
			if (sub[j+1]=='\0') 
				return i;
	/* Nije nadjeno */				
	return -1;
}

main()
{
	char s[100];
	char t[] = "Zdravo";
	char u[] = " svima";
	
	string_copy(s, t);
	printf("%s\n", s);
	
	string_concatenate(s, u);
	printf("%s\n", s);
	
	printf("%d\n",string_char("racunari", 'n'));
	printf("%d\n",string_last_char("racunari", 'a'));
	
	printf("%d\n",string_string("racunari", "rac"));
	printf("%d\n",string_string("racunari", "ari"));
	printf("%d\n",string_string("racunari", "cun"));
	printf("%d\n",string_string("racunari", "cna"));
	
	
}

/*----------------------------4.5b.c--------------------------*/
/* strlen, strcpy, strcat, strcmp, strchr, strstr - 
   verzije sa pokazivacima */
/* Vezbe radi, implementirane su funkcije biblioteke string.h */
#include <stdio.h>
#include <stdlib.h> /* Zbog NULL */

/* Izracunava duzinu stringa */
int string_length(char *s)
{
	char* t;
	for (t = s; *t; t++)
		;
	return t - s;
}


/* Kopira string src u string dest. Pretpostavlja da u dest ima dovoljno prostora. */
void string_copy(char *dest, char *src)
{
	/* Kopira karakter po karakter, sve dok nije iskopiran karakter '\0' */
	while(*dest++ = *src++)
		;
	
}

/* Nadovezuje string t na kraj stringa s. Pretpostavlja da u s ima dovoljno prostora. */
void string_concatenate(char *s, char *t)
{
	/* Pronalazimo kraj stringa s */
	while (*s)
		s++;

	/* Vrsi se kopiranje, slicno funkciji string_copy */
	while (*s++ = *t++)
		;
}

/* Vrsi leksikografsko poredjenje dva stringa. 
    Vraca :
        0 - ukoliko su stringovi jednaki
        <0 - ukoliko je s leksikografski ispred t
        >0 - ukoliko je s leksikografski iza t
*/
int string_compare(char *s, char *t)
{
	/* Petlja tece sve dok ne naidjemo na prvi razliciti karakter */
	for (; *s == *t; s++, t++)
		if (*s == '\0') /* Naisli smo na kraj oba stringa, a nismo nasli razliku */
			return 0;


	/* *s i *t su prvi karakteri u kojima se niske razlikuju. 
	   Na osnovu njihovog odnosa, odredjuje se odnos stringova */
	return *s - *t;
}

/* Pronalazi prvu poziciju karaktera c u stringu s, i vraca pokazivac na nju, 
   odnosno NULL ukoliko s ne sadrzi c */
char* string_char(char *s, char c)
{
	for (; *s; s++)
		if (*s == c)
			return s;
			
	/* Nije nadjeno */				
	return NULL;
}

/* Pronalazi poslednju poziciju karaktera c u stringu s, i vraca pokazivac na nju,
   odnosno NULL ukoliko s ne sadrzi c */
char* string_last_char(char *s, char c)
{
	char *t = s;
	/* Pronalazimo kraj stringa s */
	while (*t++)
		;
	
	/* Krecemo od kraja i trazimo c unazad */
	for (t--; t >= s; t--)
		if (*t == c)
			return t;
			
	/* Nije nadjeno */				
	return NULL;
	
}

/* Proverava da li string str sadrzi string sub.
   Vraca poziciju na kojoj sub pocinje, odnosno -1 ukoliko ga nema 
*/
char* string_string(char *str, char *sub)
{
	char *s, *t;
	/* Proveravamo da li sub pocinje na svakoj poziciji i */
	for (; *str; str++)
		/* Poredimo sub sa str pocevsi od poziciji i sve dok ne naidjemo na razliku */
		for (s = str, t = sub; *s == *t; s++, t++)
			/* Nismo naisli na razliku a ispitali smo sve karaktere niske sub */
			if (*(t+1) == '\0') 
				return str;
	/* Nije nadjeno */				
	return NULL;
}

int main() {
	char s[100];
	char t[] = "Zdravo";
	char u[] = " svima";
	char r[] = "racunari";
	
	string_copy(s, t);
	printf("%s\n", s);
	
	string_concatenate(s, u);
	printf("%s\n", s);
	
	printf("%d\n",string_char(r, 'n') - r);
	printf("%d\n",string_last_char(r, 'a') - r);
	
	printf("%d\n",string_string(r, "rac") - r);
	printf("%d\n",string_string(r, "ari") - r);
	printf("%d\n",string_string(r, "cun") - r);
	printf("%p\n",string_string(r, "cna"));

	return 0;
}

/*----------------------------4.6.c--------------------------*/
/* Demonstrira pokazivace na funkcije */
#include <stdio.h>

int kvadrat(int n) {   
  return n*n;
}

int kub(int n) {
  return n*n*n;
}

int parni_broj(int n) {
  return 2*n;
}


/* Funkcija izracunava sumu \sum_{i=1}^n f(i), gde je f data funkcija 
   prvi argument funkcije sumiraj je 
		int (*f) (int) 
   sto je pokazivac na funkciju koja ima jedan argument tipa int i 
   vraca vrednost tipa int
*/
int sumiraj(int (*f) (int), int n) {
  int i, suma=0;
  for (i=1; i<=n; i++)
	suma += (*f)(i);

  return suma;
}

int main() {
   printf("Suma kvadrata brojeva od jedan do 3 je %d\n",
          sumiraj(kvadrat,3));
   printf("Suma kubova brojeva od jedan do 3 je %d\n",
          sumiraj(kub,3));
   printf("Suma prvih pet parnih brojeva je %d\n",
          sumiraj(parni_broj,5));

   return 0;
}

/*----------------------------5.1.c--------------------------*/
/* Program uvodi strukture - geometrijske figure */
#include <stdio.h>

/* Zbog funkcije sqrt. */
#include <math.h>
/* Upozorenje : pod linux-om je potrebno program prevoditi sa 
      gcc -lm 7.4.c 
   kada god se koristi <math.h>
*/

/* Tacke su predstavljene sa dve koordinate. Strukturom gradimo novi tip podataka. */
struct point
{
	int x;
	int y;
};

/* Izracunava duzinu duzi zadatu sa dve tacke */
float segment_length(struct point A, struct point B)
{
	int dx = A.x - B.x;
	int dy = A.y - B.y;
	return sqrt(dx*dx + dy*dy);
}

/* Izracunava povrsinu trougla Heronovim obrascem. 
   Argumenti funkcije su tri tacke koje predstavljaju temena trougla */
float Heron(struct point A, struct point B, struct point C)
{
	/* Duzine stranica */
	float a = segment_length(B, C);
	float b = segment_length(A, C);
	float c = segment_length(A, B);

	/* Poluobim */
	float s = (a+b+c)/2;

	return sqrt(s*(s-a)*(s-b)*(s-c));
}

/* Izracunava obim poligona. Argumenti funkcije su niz tacaka 
   koje predstavljaju temena poligona kao i njihov broj */
float circumference(struct point polygon[], int num)
{
	int i;
	float o = 0.0;
	
	/* Dodajemo duzine stranica koje spajaju susedna temena */
	for (i = 0; i<num-1; i++)
		o += segment_length(polygon[i], polygon[i+1]);

	/* Dodajemo duzinu stranice koja spaja prvo i poslednje teme */
	o += segment_length(polygon[num-1], polygon[0]);

	return o;
}

/* Izracunava povsinu konveksnog poligona. Argumenti funkcije su niz tacaka 
   koje predstavljaju temena poligona kao i njihov broj */
float area(struct point polygon[], int num)
{
	/* Povrsina */
	float a = 0.0;
	int i;

	/* Poligon delimo na trouglove i posebno izracunavamo povrsinu svakoga od njih */
	for (i = 1; i < num -1; i++)
		a += Heron(polygon[0], polygon[i], polygon[i+1]);

	return a;
}

main()
{
	/* Definisemo dve promenljive tipa tacke */
	struct point a;

	/* Inicijalizujemo tacku b na (1,2) */
	struct point b = {1, 2};

	/* triangle je niz od tri tacke - trougao (0,0), (0,1), (1,0) */
	struct point triangle[3];

	/* square je niz od cetiri tacke - jedinicni kvadrat. 
	   Obratiti paznju na nacin inicijalizacije niza struktura */
	struct point square[4] = 
	  {{0, 0}, {0, 1}, {1, 1}, {1, 0}};

	/* Postavljamo vrednosti koordinata tacke a*/
	a.x = 0; a.y = 0;

	/* Gradimo trougao (0,0), (0,1), (1,0) */
	triangle[0].x = 0;	triangle[0].y = 0;
	triangle[1].x = 0;	triangle[1].y = 1;
	triangle[2].x = 1;	triangle[2].y = 0;


	/* Ispisujemo velicinu strukture tacka */
	printf("sizeof(struct point) = %d\n", sizeof(struct point));

	/* Ispisujemo vrednosti koordinata tacaka */
	printf("x koordinata tacke a je %d\n", a.x);
	printf("y koordinata tacke a je %d\n", a.y);
	printf("x koordinata tacke b je %d\n", b.x);
	printf("y koordinata tacke b je %d\n", b.y);

	printf("Obim trougla je %f\n",  
		circumference(triangle, 3));
	printf("Obim kvadrata je %f\n", 
		circumference(square, 4));
	printf("Povrsina trougla je %f\n", 
		Heron(triangle[0], triangle[1], triangle[2]));
	/* Broj tacaka je moguce odrediti i putem sizeof */
	printf("Povrsina kvadrata je %f\n", 
		area(square, sizeof(square)/sizeof(struct point)));

}


/*----------------------------5.1a.c--------------------------*/
/* Koriscenje typedef radi lakseg rada */
#include <stdio.h>

#include <math.h>
/* Ovim se omogucava da se nadalje u programu umesto int moze 
   koristiti ceo_broj */
typedef int ceo_broj ;

/* Ovim se omogucuje da se nadalje u programu umesto struct point 
  moze koristiti POINT */
typedef struct point POINT;

struct point
{
	int x;
	int y;
};

main()
{
	/* Umesto int mozemo koristiti ceo_broj */
	ceo_broj x = 3;

	/* Definisemo promenljivu tipa tacke. 
	   Umesto struct point mozemo koristiti POINT */
	POINT a;

	printf("x = %d\n", x);

	/* Postavljamo vrednosti koordinata tacke a*/
	a.x = 1; a.y = 2;
	/* Ispisujemo velicinu strukture tacka */
	printf("sizeof(struct point) = %d\n", sizeof(POINT));

	/* Ispisujemo vrednosti koordinata tacaka */
	printf("x koordinata tacke a je %d\n", a.x);
	printf("y koordinata tacke a je %d\n", a.y);

}


/*----------------------------5.1b.c--------------------------*/
/* Koriscenje typedef radi lakseg rada */
#include <stdio.h>

#include <math.h>

/* Deklaraciju strukture i typedef mozemo spojiti */
typedef struct point
{
	int x;
	int y;
} POINT;

main()
{
	/* Definisemo promenljivu tipa tacke. 
	   Umesto struct point mozemo koristiti POINT */
	POINT a;
	/* Postavljamo vrednosti koordinata tacke a*/
	a.x = 1; a.y = 2;
	/* Ispisujemo velicinu strukture tacka */
	printf("sizeof(struct point) = %d\n", sizeof(POINT));

	/* Ispisujemo vrednosti koordinata tacaka */
	printf("x koordinata tacke a je %d\n", a.x);
	printf("y koordinata tacke a je %d\n", a.y);

}


/*----------------------------5.2.c--------------------------*/
/* Strukture se u funkcije prenose po vrednosti. 
   Moguce je koristiti pokazivace na strukture */

#include <stdio.h>

typedef struct point
{
	int x, y;
} POINT;

/* Zbog prenosa po vrednosti tacka ne moze biti ucitana */
void get_point_wrong(POINT p)
{
	printf("x = ");
	scanf("%d", &p.x);
	printf("y = ");
	scanf("%d", &p.y);
}

/* Koriscenjem prenosa preko pokazivaca, uspevamo */
void get_point(POINT* p)
{
	/* p->x je skraceni zapis za (*p).x */

	printf("x = ");
	scanf("%d", &p->x);
	printf("y = ");
	scanf("%d", &p->y);
}


main()
{
	POINT a = {0, 0};

	printf("get_point_wrong\n");
	get_point_wrong(a);
	printf("a: x = %d, y = %d\n", a.x, a.y);

	printf("get_point\n");
	get_point(&a);
	printf("a: x = %d, y = %d\n", a.x, a.y);

}