Domaći zadaci

/* Program sabira 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;
}

/* 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 */
	}

}

/* Brojanje pojavljivanja karaktera 0, 1 i 2. Program ilustruje switch */
#include <stdio.h>

main()
{
	int c;
	int br_0=0, br_1=0, br_2=0;
	
	while ((c = getchar()) != EOF)
	{
		switch(c)
		{
			/* Obratiti paznju da nije case 0: niti case '0'; */
			case '0':	
				br_0++;
				break;	/* Isprobati veziju bez break */
			case '1':
				br_1++;
				break;
			case '2':
				br_2++;
				break;
		}
	}
	printf("Br 0 : %d\nBr 1 : %d\nBr 2 : %d\n",br_0, br_1, br_2);
}

/* Program pronalazi maksimum brojeva sa ulaza - verzija sa nizom */

#include <stdio.h>
#define BR_ELEM 5
main()
{
	int a[BR_ELEM];
	int i;
	int max;

	/* Ucitavamo niz brojeva */
	for (i = 0; i < BR_ELEM; i++)
		scanf("%d",&a[i]);
	
	/* Pronalazimo maksimum */
	max = a[0];
	for (i = 1; i < BR_ELEM; i++)
		if (a[i]>max)
			max = a[i];

	/* Ispisujemo maksimum */
	printf("Max = %d\n",max);
}

/* sum - najjednostavnija funkcija koja sabira dva broja - 
   verzija sa deklaracijom (prototipom)*/

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

main()
{
	/* Poziv funkcije */
	printf("%d\n", zbir(3,5));
}

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


/* power - funkcija koja stepenuje realan broj na celobrojni izlozilac */
#include <stdio.h>

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

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

	if (negative)
		k = -k;

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

main()
{
	/* Poziv funkcije */
	float s = power(2.0,8);
	printf("%f\n", s);
}

/* Funkcija za ispis niza brojeva - demonstrira prenos nizova brojeva u funkciju */

#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));
}

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));
}

/* string_reverse - obrce nisku karaktera */

#include <stdio.h>


/* Zbog funkcije strlen */
#include <string.h> 

/* Ova funkcija racuna duzinu date niske karaktera.
   Umesto nje, moguce je koristiti standardnu funkciju strlen .
 */
int string_length(char s[])
{
	int i;
	for (i = 0; s[i]; i++)
		;
	
	return i;
}

/* Funkcija obrce nisku karaktera */
void string_reverse(char s[])
{
	int i, j;
	for (i = 0, j = string_length(s)-1; i<j; i++, j--)
	{
		int tmp = s[i];
		s[i] = s[j];
		s[j] = tmp;
	}
	
	/* Napomena : razlikovati prethodnu petlju od dve ugnjezdjene petlje:
	for ( i = 0; ....)
	    for ( j = duzina(s)-1; ...
	 */
	
}

main()
{
	char s[] = "Zdravo svima";
	string_reverse(s);
	printf("%s\n", s);
}

/* Ilustracija lenjog izracunavanja logickih operatora */

/* 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 = 0;

/* 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()
{
	/* Funkcija izracunaj() ce se pozivati samo za parne vrednosti a */
	int a;	
	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);

}


/* swap : Demonstracija prenosa argumenata preko pokazivaca */
#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);
}


/* Demonstracija 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;
}

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);
	
}


/* Program demonstrira upotrebu pokazivaca 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;
}

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));
}

/* Demonstracija funkcije calloc - funkcija inicijalizuje sadrzaj memorije na 0*/

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

#define BR_ELEM 10

main()
{
	int *m, *c, i;

	/* Niz m NE MORA garantovano da ima sve nule */
	m = malloc(BR_ELEM*sizeof(int));
	
	/* Niz c MORA garantovano da ima sve nule */
	c = calloc(BR_ELEM, sizeof(int));

	for (i = 0; i<BR_ELEM; i++)
		printf("m[%d] = %d\n", i, m[i]);

	for (i = 0; i<BR_ELEM; i++)
		printf("c[%d] = %d\n", i, c[i]);

	free(m);
	free(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);

}


/* Program demonstrira otvaranje datoteka ("r" - read i "w" - write mod) i osnovne
   tehnike rada sa datotekama */

/* U datoteku se upisuje prvih 10 prirodnih brojeva, a zatim se iz iste datoteke 
   citaju brojevi dok se ne stigne do kraja i ispisuju se na standardni izlaz */

#include <stdio.h>

/* Zbog funkcije exit */
#include <stdlib.h> 

main()
{
	int i;

	/* Otvaramo datoteku sa imenom podaci.txt za pisanje */
	FILE* f = fopen("podaci.txt", "w");

	/* Ukoliko otvaranje nije uspelo, fopen vraca NULL. U tom slucaju,
	   prijavljujemo gresku i zavrsavamo program */ 
	if (f == NULL)
	{
		printf("Greska prilikom otvaranja datoteke podaci.txt za pisanje\n");
		exit(1);
	}

	/* Upisujemo u datoteku prvih 10 prirodnih brojeva (svaki u posebnom redu) */
	for (i = 0; i<10; i++)
		fprintf(f, "%d\n", i);

	/* Zatvaramo datoteku */
	fclose(f);

	/* Otvaramo datoteku sa imenom podaci.txt za citanje */
	f = fopen("podaci.txt", "r");

	/* Ukoliko otvaranje nije uspelo, fopen vraca NULL. U tom slucaju,
	   prijavljujemo gresku i zavrsavamo program */ 
	if (f == NULL)
	{
		printf("Greska prilikom otvaranja datoteke podaci.txt za citanje\n");
		exit(1);
	}

	/* Citamo brojeve iz datoteke dok ne stignemo do kraja i ispisujemo ih 
	   na standardni izlaz */
	while(1)
	{
		int br;
		/* Pokusavamo da procitamo broj */
		fscanf(f, "%d", &br);

		/* Ukoliko smo dosli do kraja datoteke, prekidamo */
		if (feof(f))
			break;

		/* Ispisujemo procitani broj */
		printf("Procitano : %d\n", br); 
	}

	/* Funkciju feof ne bi trebalo pozivati pre pokusaja citanja.
	   Sledeci kod moze dovesti do greske:
	
		while (!feof(f))
			scanf("%d",&br);
	
	*/


	/* Zatvaramo datoteku */
	fclose(f);

	
	
}

/* Program demonstrira "a" - append mod datoteka - nadovezivanje */
#include <stdio.h> 

main() 
{   
	FILE* datoteka;

	/* Otvaramo datoteku za nadovezivanje i proveravamo da li je doslo do greske */
	if ( (datoteka=fopen("dat.txt","a"))==NULL)
	{    
		fprintf(stderr,"Greska : nisam uspeo da otvorim dat.txt\n");
		return 1;
    	}
	
	/* Upisujemo sadrzaj  u datoteku */
    	fprintf(datoteka,"Zdravo svima\n");

	/* Zatvaramo datoteku */
	fclose(datoteka);
}

/* Rekurzija : faktorijel */
long factorial(int n)
{
	/* 
	if (n == 1)
		return 1;
	else
		return n*factorial(n-1);
	*/
	
	/* Krace */
	return n == 1 ? 1 : n*factorial(n-1);
}

long factorial_iterative(int n)
{
	long f = 1;
	int i;
	for (i = 1; i<=n; i++)
		f *= i;
	return f;
}

main()
{
	printf("5! = %d\n", factorial(5));
}


/* Linearna pretraga niza brojeva */
#include <stdio.h>

/* Funkcija proverava da li se dati element x nalazi 
   u datom nizu celih brojeva. 
   Funkcija vraca poziciju u nizu na kojoj je x pronadjen
   odnosno -1 ukoliko elementa nema.
*/
int linear_search(int a[], int n, int x) 
{
	int i;
	for (i = 0; i<n; i++)
		if (a[i] == x)
			return i;
		/* nikako else */

	return -1;	
}

main()
{
	int a[] = {4, 3, 2, 6, 7, 9, 11};
	int n = sizeof(a)/sizeof(int);
	int x, i;
	printf("Unesi broj koji trazimo : ");
	scanf("%d",&x);
	
	i = linear_search(a, n, x);
	if (i == -1)
		printf("Element %d nije nadjen\n",x);
	else	
		printf("Element %d je nadjen na poziciji %d\n",x, i);
}

/* Ubacivanje na pocetak jednostruko povezane liste - verzija sa **.
   Ispis i oslobadjanje liste realizovani iterativno. */

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

typedef struct cvor
{
	int br;
	struct cvor* sl;
} CVOR;

/* Pomocna funkcija koja kreira cvor liste sa datim sadrzajem. 
   Funkcija kreira cvor i postavlja mu sadrzaj na dati broj. 
   Polje sl ostaje nedefinisano. 
   Funkcija vraca pokazivac na kreirani cvor. */

CVOR* napravi_cvor(int br)
{
	CVOR* novi = (CVOR*)malloc(sizeof(CVOR));
	if (novi == NULL)
	{
		fprintf(stderr, "Greska prilikom alokacije memorije\n");
		exit(1);
	}
	novi->br = br;
	return novi;
}

/* Zbog prenosa po vrednosti, sledeca funkcija ne radi ispravno */
/*
void ubaci_na_pocetak(CVOR* l, int br)
{
	CVOR* novi = napravi_cvor(br);
	novi->sl = l;
	l = novi;  /* Ovde se menja lokalna kopija pokazivaca l, a 
		      ne l iz funkcije pozivaoca (main) */
}
*/


/* Ubacuje dati broj na pocetak liste.  
   Pokazivac na pocetak liste se prenosi preko pokazivaca, umesto po 
   vrednosti, kako bi mogla da mu se izmeni vrednost. */
void ubaci_na_pocetak(CVOR** pl, int br)
{
	CVOR* novi = napravi_cvor(br);
	novi->sl = *pl;
	*pl = novi;
}

/* Ispisivanje liste : iterativna verzija */
void ispisi_listu(CVOR* l)
{
	CVOR* t;
	for (t = l; t != NULL; t=t->sl)
		printf("%d ", t->br);
}


/* Sledeca funkcija je neispravna */
/*
void oslobodi_listu(CVOR* l)
{
	CVOR* t;	
	for (t = l; t!=NULL; t = t->sl)
		free(t); 
		/* Ovde se unistava sadrzaj cvora na koji ukazuje t.
		   Korak petlje t = t->sl nece moci da se izvrsi */
	
}
*/

/* Oslobadjanje liste : iterativna verzija */
void oslobodi_listu(CVOR* l)
{
	while (l)
	{
		CVOR* tmp = l->sl;
		free(l);
		l = tmp;
	}
}

main()
{
	CVOR* l = NULL;
	int i;
	for (i = 0; i<10; i++)
		ubaci_na_pocetak(&l, i);

	ispisi_listu(l);
	putchar('\n');

	oslobodi_listu(l);
}

/* Binarno pretrazivacko drvo - drvo sadrzi cele brojeve. 
   Ubacivanje realizovano preko ** */

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

/* Struktura jednog cvora drveta */
typedef struct _cvor
{
	/* Podatak */
	int broj;
	/* Pokazivac na levo i desno podstablo */
	struct _cvor *l, *d;
} cvor;

/* Pomocna funkcija koja kreira novi cvor na osnovu datog broja */
cvor* napravi_cvor(int b)
{
	cvor* novi = (cvor*)malloc(sizeof(cvor));
	if (novi == NULL)
	{
		fprintf(stderr, "Greska prilikom alokacije memorije");
		exit(1);
	}
	
	/* Postavljamo brojnu vrednost */	
	novi->broj = b;

	/* Novi cvor se kreira kao list */
	novi->l = NULL;
	novi->d = NULL;
	return novi;
}

/* Rekurzivna funkcija koja ubacuje dati broj u dato drvo */
void ubaci_u_drvo(cvor** pdrvo, int b)
{
	/* Ukoliko je drvo prazno kreira se novi cvor */
	if (*pdrvo == NULL)
	{
		*pdrvo = napravi_cvor(b);
		return;
	}

	/* Ukoliko je broj koji se ubacuje manji od broja u korenu, 
	   rekurzivno ga ubacujemo u levo podstablo. 
	   Ukoliko je broj koji se ubacuje veci od broja u korenu, 
	   rekurzivno ga ubacujemo u desno podstablo. 
	*/

	if (b < (*pdrvo)->broj)
		ubaci_u_drvo(&((*pdrvo)->l), b);
	else if (b > (*pdrvo)->broj)
		ubaci_u_drvo(&((*pdrvo)->d), b);
}


/* Rekurzivna funkcija koja proverava da li dati broj postoji u drvetu */
int pronadji(cvor* drvo, int b)
{	
	/* U praznom drvetu ne postoji broj */
	if (drvo == NULL)
		return 0;
	
	/* Ukoliko je jednak vrednosti u korenu, onda postoji */
	if (drvo->broj == b)
		return 1;

	/* Ukoliko je broj koji trazimo manji od vrednosti u korenu, 
	   trazimo ga samo u levom podstablu, a inace ga trazimo 
	   samo u desnom podstablu */
	if (b < drvo->broj)
		return pronadji(drvo->l, b);
	else
		return pronadji(drvo->d, b);
}

/* Rekurzivna funkcija koja ispisuje drvo u inorder redosledu */
void ispisi_drvo(cvor* drvo)
{
	if (drvo != NULL)
	{
		ispisi_drvo(drvo->l);
		printf("%d ", drvo->broj);
		ispisi_drvo(drvo->d);
	}
}


/* Rekurzivna funkcija koja uklanja drvo. Obilazak mora biti postorder. */
void obrisi_drvo(cvor* drvo)
{
	if (drvo != NULL)
	{
		obrisi_drvo(drvo->l);
		obrisi_drvo(drvo->d);
		free(drvo);
	}
}

main()
{
	cvor* drvo = NULL;
	ubaci_u_drvo(&drvo, 1);
	ubaci_u_drvo(&drvo, 8);
	ubaci_u_drvo(&drvo, 3);
	ubaci_u_drvo(&drvo, 5);
	ubaci_u_drvo(&drvo, 7);
	ubaci_u_drvo(&drvo, 6);
	ubaci_u_drvo(&drvo, 9);

	if (pronadji(drvo, 3))
		printf("Pronadjeno 3\n");
	if (pronadji(drvo, 2))
		printf("Pronadjeno 2\n");
	if (pronadji(drvo, 7))
		printf("Pronadjeno 7\n");

	ispisi_drvo(drvo);
	putchar('\n');

	obrisi_drvo(drvo);	
}