FUNKCIJE U C PROGRAMSKOM JEZIKU

Programi u programskom jeziku c mogu da imaju veliki broj naredbi i ako bi one bile napisane jedna za drugom u jednom fajlu, programeri bi se teško snalazili u takvom kodu, tj. bilo bi ga teško održavati. S druge strane često se dešava da se jedan algoritam, deo naredbi koje rešavaju jedan mali ili veliki problem unutar aplikacije ponavlja više puta. Može se zaključiti da bi bilo mnogo bolje taj skup naredbi(deo programa) izdvojiti kao jednu celinu samo jednom kao podprogram ili funkcija i onda se po potrebi ta funkcija pozivala svaki put kada je potrebno. Potprogrami su mehanizam razbijanja složenih problema na potprobleme. 
Programski jezik C poznaje samo jednu vrstu potprograma koje se nazivaju funkcijama.

​
Primere iz funkcija možete naći na sledećoj web strani: Funkcije u C/C++ jeziku -primeri

​Treba razlikovati dve stvari vezano za funkcije:

Deklaracija funkcija

Deklaracija funkcije (poznata i kao prototip funkcije) je način da se kompajler unapred obavesti o postojanju funkcije, njenom povratnom tipu i argumentima. Ovo je korisno kada funkcija nije implementirana pre njenog poziva u kodu.Sintaksa deklaracije funkcije:

povratni_tip ime_funkcije(tip_argumenta1 argument1, tip_argumenta2 argument2, ...);
​Primer deklaracije funkcije:
#include <stdio.h>

// Deklaracija funkcije koja računa zbir dva broja
int zbir(int a, int b);

int main() {
int rezultat = zbir(5, 7); // Poziv funkcije zbir sa argumentima 5 i 7
printf("Zbir je: %d\n", rezultat); // Ispis rezultata na ekran
return 0; // Kraj programa
}

// Definicija funkcije zbir koja vraća zbir dva broja
int zbir(int a, int b) {
return a + b; // Vraća zbir unetih brojeva
}
​Napomena: Deklaracija funkcije se obično stavlja na početak koda, ispred funkcije main().

Definisanje funkcija

Defisanje znači da mi te naredbe koje čine funkciju i koje treba da odrede specifičan zadatak u nekoj aplikaciji(programu) napišemo na nekom mestu u programu, da ih na neki način grupišemo, damo neki naziv i odredimo koji podaci treba da se dostave funkciji kao ulazni parametri i kakav podatak funkcija vraća nazad kao povratnu vrednost. Dakle definisanje funkcije treba da obuhvati: Ovo se može videti na sledećoj slici. Prikazana je metoda(funkcija) za računanje maksimuma između dva cela broja:Definicija funkcije - detaljan prikaz
Slika 1: Definisanje funkcije(metode)
U zaglavlju metode se nalaze dve reči.
Prva, u ovom slučaju int, predstavlja tip podatka povratne vrednosti. Ova metoda koja računa veći broj između dva cela broja, vraća taj broj čiji je tip int. To je tip povratne vrednosti.
Druga, predstavlja naziv metode, koji programer bira sam i koji treba da sugeriše svrhu metode.
Telo metode se predstavlja vitičastim zagradama. U telu se nalaze naredbe funkcije.
U zaglavlju funkcije(metode) se, posle naziva, unutar običnih zagrada pišu parametri(argumenti) funkcije. To su podaci koje treba dostaviti funkciji da bi ona mogla da završi postavljen zadatak. U prethodnom primeru zadatak koji funkcija treba da izvrši je određivanje maksimuma između dva cela broja, a podaci koje funkciji preko parametra treba dostaviti su ta dva broja, u ovom slučaju označena kao a i b. Na sledećoj slici je prikazana detaljnije ova metoda.Definisanje funkcije u C/C++ detalji
Slika 2: Definisanje funkcije-detalji
Parametra funkcije može biti nijedan jedan ili više. Ako funkciji nisu potrebni ulazni podaci onda će zagrada u zaglavlju funkcije ostati prazna.
Ukoliko metoda ne vraća vrednost, neće imati u telu naredbu return podatak, ali može imati samo return. kao tip povratne vrednosti se u tom slučaju piše reč void.
U programu mora postojati najmanje jedna funkcija i to je funkcija main(glavna). Primer main funkcije iz prethodnog primera prikazana je na slici ispod. Određivanje maksimuma dva cela broja-main funkcija
Slika 3: Određivanje maksimuma dva cela broja-main funkcija
Unutar glavne funkcije prvo se učitaju dva cela broja, a zatim se određuje maksimum. Naredbe kojima se određuje maksimum nalaze se izdvojene kao posebna metoda pod nazivom max(vidi sliku 2). U main funkciji pomoću naredbe cout treba ispisati ovu vrednost. Na mestu gde se očekuje podatak za ispisivanje nalazi se poziv funkcije max. Njoj se kao parametri prosleđuju podaci A i B, zapravo kopije ovih vrednosti. Funkcija max određuje veću vrednost i vraća je nazad kao povratnu vrednost. Ova povrtna vrednost štampaće se zajedno sa tekstom "Veći broj je" na izlazu. Posle pokretanja i zadavanja vrednosti npr 5 i 10 za A i B, na izlazu će se prikazati:Maksimum dva cela broja-izlaz
Slika 4: Određivanje max dva cela broja-izlaz

Pozivanje funkcija

Jedina funkcija koja se automatski pozove prilikom startovanja aplikacije je main funkcija.

Naredbe u main se izvršavaju redom, odozdo na dole, i kada se završi poslednja naredba, program se završava. Ako u projektu imamo definisano još funkcija, one se neće izvršiti same od sebe. Da bi program iz main nastavio izvršenje u nekoj drugoj funkciji, jedna od naredbi u main mora biti poziv te funkcije.

U primeru na slici 3 poziva se funkcija max:

printf("Veći broj je %d\n", max(A, B));

Deklaracija poziva funkcije, u opštem slučaju, izgleda:

naziv_funkcije(parametar1, parametar2, ...);

Parametri koji se prosleđuju funkciji se kopiraju redom u parametre definisane u funkciji (vidi sliku 2). U definiciji funkcije, ispred naziva parametra stavlja se tip podatka.

int max(int a, int b)

Ovde se zapravo rezerviše nova memorija označena sa a i b, koja prima kopije vrednosti parametara iz poziva funkcije:

max(A, B);

U pozivu se ispred parametra ne stavlja tip podatka. Kopiranje parametra je prikazano na slici 5.

Funkcije C/C++: Prosleđivanje parametara funkciji
Slika 5: Prosleđivanje parametara funkciji max-šematski prikaz

Primer: Odeđivanje maksimuma dva broja-rešenje u jeziku c

Zadatak: Napraviti funkciju koja određuje maksimum dva cela broja koji su prosleđeni kao parametri funkcije.
Učitati dva cela broja i odrediti njihov maksimum koristeći prethodno definisanu funkciju.Picture
Slika 6: Funkcija za određivanje maksimuma brojeva a i b. Kod u programskom jeziku C

Prosleđivanje parametra po vrednosti i po referenci

U prethodnom primeru prikazano je prosleđivanje parametra po vrednosti. Pošto parametri u drugoj funkciji predstavljaju novu memoriju koja samo iz memorije parametara glavne funkcije dobijaju kopije vrednosti, svaka eventualna promena vrednosti unutar druge funkcije neće se odraziti na podatke definisane u prvoj.
​Ovo možemo ilustrovati kroz sledeći primer:

Primer 2: Zamena vrednosti podatku

Zadati celobrojnom podatku vrednost 20, a zatim napraviti metodu koja ovu vrednost menja na 100.
Napravimo funkciju koja će promeniti vrednost poslatom podatku: Primer „zamene vrednosti podataka“ - po vrednosti
Slika 7: Primer „zamene vrednosti podataka“ - po vrednosti
#include <stdio.h>

// Deklaracija funkcije koja menja vrednost lokalno
void promeni_vr(int x);

int main() {
// Inicijalizacija podatka sa vrednošću 20
int broj = 20;
printf("Početna vrednost: %d\n", broj);

// Poziv funkcije koja menja vrednost lokalno
promeni_vr(broj);

printf("Nakon promene u main: %d\n", broj);

return 0; // Završetak programa
}

// Definicija funkcije koja menja vrednost lokalno
void promeni_vr(int x) {
// Promena vrednosti samo unutar funkcije
x = 200;
printf("Vrednost unutar funkcije: %d\n", x);
}
Kad pokrenemo ovaj program na izlazu dobijamoFunkcije C/C++: Zamena vrednosti podatku-izlaz
Slika 8: Primer "Zamena vrednosti podatku" - izlaz
Vidimo da u glavnoj funkciji ova vrednost nije promenjena i ako na prvi pogled izgleda da je u kodu sve ispravno.
Ova vrednost se jeste promenila unutar funkcije promeni_vr, ali se ova promena ne odražava na podatke u glavnoj funkciji.
Da bi ovo bilo ispravno, parametri se moraju preneti po pokazivaču.

​Prenos parametara funkcije po pokazivaču

Umesto referenci, mogu se koristiti i pokazivači na podatke. Efekat je sličan prosleđivanju po referenci, što znači da će se promene nastale unutar te funkcije nad podacima, kojima se pristupa preko pokazivača, odraziti na originalne podatke definisane u glavnoj funkciji. To je zbog toga što pokazivači pokazuju originalni podatak, a ne na neki novi, koji samo ima istu vrednost kao originalni. 
Više o pokazivačima vidi u lekciji Pokazivači u jeziku C.
Prethodni primer sada izgleda kao na slici 10:Slika 10.1 prikazuje varijantu zadatka u C programskom jeziku:Programski jezik C: Primer
Slika 11.1: Programski jezik C: Primer "zamena vrednosti podatku" , po pokazivaču.
Isti zadatak u programskom jeziku C++ je prikazan na slici 11.2Programski jezik C:  Primer
Slika 11.2: Programski jezik C: Primer "zamena vrednosti podatku" - po pokazivaču
Posle pokretanja posle izmene na izlazu dobijamo:Funkcije C/C++:  Primer
Slika 12: Primer "zamena vrednosti podatku" - po pokazivaču-izlaz

​Primeri funkcija sa različitim tipovima povratnih vrednosti i argumentima

1. Funkcija bez povratne vrednosti (void)Funkcije koje ne vraćaju vrednost koriste povratni tip void. Koriste se za izvršavanje akcija, kao što je ispis na ekran.
Primer: ​
// Funkcija za ispis pozdravne poruke
voidpozdrav() {
printf("Dobrodošli u svet programiranja!\n");
}

intmain() {
pozdrav(); // Poziv funkcije
return 0;
}

Objašnjenje: ​​

​2. Funkcija sa povratnom vrednošću tipa int

Funkcija može vraćati numeričke vrednosti koje se koriste u daljem toku programa.
​
Kod:
// Funkcija koja vraća zbir dva broja
intzbir(int a, int b) {
return a + b;
}

intmain() {
int rezultat = zbir(5, 7); // Poziv funkcije
printf("Zbir je: %d\n", rezultat);
return 0;
}
Objašnjenje:
​
Funkcija zbir uzima dva argumenta (a i b) i vraća njihov zbir kao rezultat.

3. Funkcija sa povratnom vrednošću tipa double

Koristi se kada su potrebni decimalni brojevi, npr. za matematičke proračune.

Kod:
// Funkcija koja računa površinu kruga
doublepovrsinaKruga(double r) {
return 3.14159 * r * r;
}

intmain() {
double r = 5.0;
double povrsina = povrsinaKruga(r);
printf("Površina kruga je: %.2lf\n", povrsina);
return 0;
}
Objašnjenje:
Funkcija povrsinaKruga računa površinu kruga pomoću formule π · r2 i vraća rezultat tipa double.

4. Funkcija sa povratnom vrednošću tipa string

​Omogućava rad sa tekstualnim vrednostima.
// Funkcija koja vraća pozdravnu poruku
voidpozdravPoruka(char ime[], char rezultat[]) {
sprintf(rezultat, "Zdravo, %s!", ime);
}

intmain() {
char ime[] = "Ana";
char rezultat[50]; // Prostor za rezultat
pozdravPoruka(ime, rezultat);
printf("%s\n", rezultat);
return 0;
}
Objašnjenje:

Rekurzivne funkcije

Rekurzivne funkcije su funkcije koje pozivaju same sebe, direktno ili indirektno. Ovaj pristup omogućava rešavanje problema koji se prirodno mogu podeliti na manje podprobleme.

Za detaljnije objašnjenje i praktične primere, posetite našu stranicu: Rekurzivni algoritmi.

Primeri sa funkcijama

Primer 1: Štampanje niza

Napišite program u C jeziku koji koristi funkciju za ispis članova niza. Kreirajte funkciju stampaj_niz koja prima ceo niz i njegovu dužinu, i ispisuje elemente niza u jednom redu. U main funkciji:

  • Pročitajte ceo broj n (veličina niza) sa ulaza.
  • Napravi­te niz dužine n i popunite ga unosom od korisnika.
  • Pozovite funkciju stampaj_niz da prikažete unesene elemente.

Kratko objašnjenje zadatka:

Cilj je da praktično primenite deklarišanje i definisanje funkcije, način prosleđivanja niza u C (pogled na argument A[]) i poziv funkcije iz main. Obratite pažnju na redosled operacija: prvo unos veličine, zatim unos elemenata, pa poziv funkcije za ispis.

#include <stdio.h>#include <stdlib.h>/* Funkcija koja prima niz i njegovu duzinu i ispisuje elemente */voidstampaj_niz(int A[], int n)
{
// Ispis zaglavlja radi preglednostiprintf("stampaj_niz:\n"); // štampa naslov// Prolazimo kroz sve elemente niza i štampamo ihfor(int i = 0; i < n; i++){
printf("%d ", A[i]);
} printf("\n"); // prelaz u novi red nakon ispisa
} intmain() {
int n; // Ucitavanje velicine nizascanf("%d", &n); // Dinamicki alociran lokalni niz: VAZNO: u standardnom C-u pre C99 ovaj nacin nije podrzan; pri C99 i kasnije VLAs su dozvoljeniint niz[n]; // Unos elemenata nizafor(int i = 0; i < n; i++){
printf("Unesi %d. element niza\n", (i+1)); // Pitamo za element (i+1) radi citljivostiscanf("%d", &niz[i]); // Citamo vrednost u niz[i]
} // Poziv funkcije koja ispisuje nizstampaj_niz(niz, n); return0; // Signal da je program uspešno završen
}

Objašnjenje (nastavak)

Kreirana je funkcija void tipa — stampaj_niz — koja:
  • prima parametreint A[] i int n (niz i njegova dužina). Napomena: u C-u A[] u deklaraciji zapravo postaje pokazivač na prvi element, tj. A je ekvivalentno int *.
  • ne vraća vrednost (zato je tip void) — njena jedina svrha je da prikaže (ispisuje) podatke na standardni izlaz.

Zašto ne možemo da odštampamo ceo niz "odjednom"? U C-u ne postoji ugrađena funkcija koja prima ceo niz i zna kako da ga formatira za ispis — zato moramo da prođemo kroz elemente jedan po jedan.

U implementaciji koristimo for petlju:
for(int i = 0; i < n; i++) { ... }

U telu petlje pozivamo printf sa format specifierom "%d " kako bismo ispisali trenutni element:
printf("%d ", A[i]);
  • Šta znači "%d"? — to je mesto u format stringu gde će printf ubaciti vrednost celobrojnog tipa (integer) koja je navedena kao sledeći argument.
  • Šta znači A[i]? — to je i-ti element niza; u semantičkom smislu A[i] je isto što i *(A + i) (aritmetika pokazivača).

Po završetku petlje često pozovemo printf("\n") da pređemo u novi red i da ispis bude uredan.

Dodatne napomene koje su korisne studentima:
  • Obavezno proslediti dužinu niza — funkcija ne može sama da sazna koliko je elemenata u nizu.
  • Bezbednost: uvek vodite računa da n bude validna (npr. nenegativna) pre nego što pristupate A[i], kako biste izbegli pristup van granica niza.
  • Alternativa za starije C standarde: ako ne koristite VLA (variable length arrays), umesto int niz[n]; koristite dinamičku alokaciju (malloc) ili fiksni maksimalni niz.
  • Mogućno proširenje zadatka: napišite dodatne funkcije, npr. int suma(int A[], int n) ili int max(int A[], int n), i testirajte ih iz main.

Ukratko: stampaj_niz demonstrira osnovne principe rada sa funkcijama u C — deklarisanje, prosleđivanje pokazivača/niza, iteraciju kroz elemente i upotrebu printf za formatiran ispis.

Primer 2 Pomeri elemente niza ulevo (rotacija)

Napišite funkciju u C jeziku koja pomera sve elemente niza za jedno mesto ulevo (ciklična rotacija). Funkcija treba da modifikuje niz in-place i pri tome poslednji element treba da postane prethodno prvi element.

  • Kreirajte funkciju ciklus_levo koja prima parametre int A[] i int n.
  • U main funkciji: pročitajte veličinu n, unesite n elemenata niza, pozovite ciklus_levo i zatim prikažite rezultat pozivom pomoćne funkcije stampaj_niz.
  • Obratite pažnju na ivične slučajeve: n <= 1 (niz se ne menja).

Kratko objašnjenje zadatka:

Cilj je da demonstrirate kako se niz menja direktno u funkciji (prosleđivanjem pokazivača na prvi element) i da razumete jednostavnu algoritamsku operaciju pomeranja elemenata (O(n) vremenska složenost).

#include <stdio.h>#include <stdlib.h>/* Funkcija ciklicnog pomeranja niza ulevo za jedno mesto */voidciklus_levo(int A[], int n) {
// Ako je n manje ili jednako 1 nema sta da se pomeraif (n <= 1) {
return;
} // Sacuvamo prvi element u privremenu promenljivuint b = A[0]; // Pomeramo svaki element ulevo: A[i-1] = A[i]for (int i = 1; i < n; i++) {
A[i - 1] = A[i];
} // Na kraj stavljamo sacuvani prvi element A[n - 1] = b;
} voidstampaj_niz(int A[], int n) {
printf("stampaj_niz:\n"); for (int i = 0; i < n; i++) {
printf("%d ", A[i]);
} printf("\n");
} intmain() {
int n; // Ucitavanje velicine nizascanf("%d", &n); // Napomena: koristi se VLA (C99). Ako trebate kompatibilnost sa starijim standardima, koristite malloc.int niz[n]; for (int i = 0; i < n; i++) {
printf("Unesi %d. element niza\n", (i + 1)); scanf("%d", &niz[i]);
} // Poziv funkcije za pomeranje ulevociklus_levo(niz, n); // Ispis rezultatastampaj_niz(niz, n); return0;
}

Objašnjenje rešenja

  • Funkcija ciklus_levo je tipa void — ne vraća vrednost, već menja sadržaj niza koji je prosleđen (u C-u se niz prosleđuje kao pokazivač na prvi element).
  • Prvo proveravamo if (n <= 1) — kod nizova dužine 0 ili 1 nema pomeranja i odmah izlazimo.
  • Sačuvamo prvi element u promenljivu b, jer će on biti prepisan prilikom pomeranja ostalih elemenata.
  • for petljom prolazimo od indeksa 1 do n-1 i dodeljujemo A[i-1] = A[i] — time pomeramo svaki element ulevo za jedno mesto.
  • Nakon petlje, na poslednju poziciju A[n-1] postavljamo prethodno sačuvani prvi element b, čime je rotacija kompletirana.
  • Algoritam radi u mestu (in-place), koristi konstantnu dodatnu memoriju (samo jednu promenljivu b) i ima vremensku složenost O(n).
  • Bezbednosne napomene: uvek proverite validnost n pre pristupa elementima (da nije negativan), i kod produkcijskih rešenja razmislite o upotrebi dinamičke alokacije umesto VLA ako vam je potrebna kompatibilnost sa starijim C standardima.

Proširenje zadatka (opciono): Napišite funkciju ciklus_desno koja pomera elemente niza ciklično udesno za jedno mesto, ili generičku funkciju rotate(int A[], int n, int k) koja rotira niz za k pozicija (pozitivno ulevo, negativno udesno).

Primer 3: Funkcija za brojanje karaktera u C stringu

Napišite funkciju u C jeziku koja prima C-style string (niz tipa char) i vraća broj karaktera u tom nizu (bez završnog null znaka). Funkcija treba da prebroji znakove i vrati tu vrednost kao int. U main-u pročitajte string sa ulaza, pozovite funkciju i ispišite rezultat.

  • Kreirajte funkciju duzina sa potpisom intduzina(constchar s[]).
  • U main-u učitajte liniju teksta (koristeći fgets) i uklonite mogući završni newline prije poziva funkcije.
  • Testirajte za prazan string (treba vratiti 0) i za niz sa razmacima.

Kratko objašnjenje zadatka:

Cilj je pokazati kako u C-u funkcija prima niz (koji je u funkciji zapravo pokazivač na prvi element), kako se stringovi završavaju sa posebim znakom '\0' i kako iteracijom prebrojavamo elemente do prvog null znaka.

#include <stdio.h>#include <stdlib.h>/* Funkcija koja prebrojava karaktere u C-stringu (bez '\\0') */intduzina(constchar s[]) {
int i = 0; while (s[i] != '\0') {
i++;
} return i;
} intmain() {
char s[256]; // Učitaj liniju sa standardnog ulaza (do 255 karaktera + '\\0')if (fgets(s, sizeof(s), stdin) == NULL) {
return0;
} // Uklanjamo eventualni '\\n' koji dodaje fgetsint j = 0; while (s[j] != '\0') {
if (s[j] == '\n') {
s[j] = '\0'; break;
} j++;
} // Poziv funkcije koja vraća dužinuint len = duzina(s); printf("Length: %d\n", len); return0;
}

Objašnjenje rešenja

  • Funkcija duzina prima parametar const char s[]. U deklaraciji to je ekvivalentno const char * s — dakle, u funkciji radimo sa pokazivačem na prvi karakter niza.
  • String u C-u je niz karaktera koji se završava nul-znakom '\0'. Funkcija prebrojava elemente dok ne naiđe na taj terminator. Svako A[i] (ovde s[i]) predstavlja pojedinačni karakter.
  • U main-u koristimo fgets da bismo bezbedno pročitali liniju (umesto scanf sa %s, koji prestaje na prvom razmaku). Pošto fgets uključuje znak novog reda ako ga ima, uklanjamo ga pre poziva duzina da bismo dobili broj korisnih karaktera.
  • Funkcija vraća int koji predstavlja broj karaktera (0 za prazan string). Algoritamski vremenska složenost je O(n), gde je n dužina stringa.
  • Važno: ne pokušavajte da koristite sizeof u funkciji da biste odredili dužinu stringa — sizeof(s) u funkciji će vratiti veličinu pokazivača, ne dužinu niza. Zato je neophodno iterativno prebrojavanje ili korišćenje standardne strlen funkcije iz <string.h>.
  • Edge cases: Ako je ulazna linija prazna (samo enter), funkcija vraća 0. Ako je string duži od bafera (255 znakova), fgets će učitati samo početni deo — za potpunu podršku koristite dinamičku alokaciju i loop za čitanje.

Proširenje (opciono): Implementirajte varijantu koja vraća size_t i koristi const unsigned char * za ispravno brojanje byte/karaktera kod proširenih ASCII/UTF-8 scenarioa, ili jednostavno pozovite strlen iz <string.h>.

Više o radu sa tekstom u C jeziku pročitajte u članku: Stringovi u C jeziku

Naprednije funkcije

1. Funkcija koja vraća pokazivač

P​rimer funkcije koja kreira dinamički alociran niz i vraća pokazivač na njega:
// Funkcija koja kreira niz i popunjava ga vrednostima
#include<stdio.h>
#include<stdlib.h>

int*kreirajNiz(int n) {
int* niz = (int*)malloc(n * sizeof(int));
if (niz == NULL) {
printf("Greška pri alokaciji memorije!\n");
returnNULL;
}
for (int i = 0; i < n; i++) {
niz[i] = i * 2; // Popunjavanje niza nekim vrednostima
}
return niz;
}

intmain() {
int n = 5;
int* niz = kreirajNiz(n);

if (niz != NULL) {
printf("Generisani niz: ");
for (int i = 0; i < n; i++) {
printf("%d ", niz[i]);
}
printf("\n");
free(niz); // Oslobađanje memorije
}

return 0;
}
Objašnjenje:

2. Korišćenje funkcijskih pokazivača

Funkcijski pokazivači omogućavaju da prosleđujemo funkcije kao argumente drugim funkcijama.
#include<stdio.h>

// Deklaracija funkcije koja sabira dva broja
intsaberi(int a, int b) {
return a + b;
}

// Funkcija koja oduzima dva broja
intoduzmi(int a, int b) {
return a - b;
}

// Funkcija koja prima pokazivač na funkciju
intobradi(int x, int y, int (*operacija)(int, int)) {
return operacija(x, y);
}

intmain() {
int a = 10, b = 5;

printf("Sabiranje: %d\n", obradi(a, b, saberi));
printf("Oduzimanje: %d\n", obradi(a, b, oduzmi));

return 0;
}
Objašnjenje:

3. Funkcija koja sortira niz pomoću pokazivača na funkciju

​Ovo omogućava fleksibilno sortiranje niza koristeći različite kriterijume.
#include<stdio.h>

// Funkcija za poređenje rastućeg reda
intrastuce(int a, int b) {
return a - b;
}

// Funkcija za poređenje opadajućeg reda
intopadajuce(int a, int b) {
return b - a;
}

// Implementacija bubble sort algoritma sa pokazivačem na funkciju
voidbubbleSort(int arr[], int n, int (*compare)(int, int)) {
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j < n - i - 1; j++) {
if (compare(arr[j], arr[j + 1]) > 0) {
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}

// Ispis niza
voidprikaziNiz(int arr[], int n) {
for (int i = 0; i < n; i++) {
printf("%d ", arr[i]);
}
printf("\n");
}

intmain() {
int niz[] = {5, 2, 9, 1, 5, 6};
int n = sizeof(niz) / sizeof(niz[0]);

printf("Originalni niz: ");
prikaziNiz(niz, n);

bubbleSort(niz, n, rastuce);
printf("Sortiran rastuće: ");
prikaziNiz(niz, n);

bubbleSort(niz, n, opadajuce);
printf("Sortiran opadajuće: ");
prikaziNiz(niz, n);

return 0;
}
Objašnjenje:

Primeri sa funkcijama i njihova memorijska organizacija

1. Osnovni primer funkcije sa objašnjenjem memorijske organizacije

​U ovom primeru funkcija prima dva broja, sabira ih i vraća rezultat.
Pogledaćemo kako se podaci prenose u memoriji.
#include<stdio.h>

// Funkcija koja prima dva cela broja i vraća njihov zbir
intsaberi(int a, int b) {
int rezultat = a + b; // Promenljiva rezultat se kreira na steku
return rezultat; // Povratna vrednost se skladišti u registar (ili stek u zavisnosti od arhitekture)
}

intmain() {
int x = 5, y = 10; // x i y su smešteni na stek unutar main funkcije
int zbir = saberi(x, y); // Poziv funkcije - argumenti se stavljaju na stek ili u registre

printf("Zbir: %d\n", zbir);
return 0;
}

Šta se dešava u memoriji prilikom poziva saberi(x, y)?

Alokacija memorije na steku

  • x i y su promenljive u main funkciji i čuvaju se na steku.
  • Kada se pozove saberi(x, y), vrednosti x i y se stavljaju na stek ili prosleđuju putem registara (zavisi od kompajlera).

Izvršavanje funkcije

  • Funkcija saberi dobija kopije vrednosti x i y.
  • Nova promenljiva rezultat se kreira na steku i dodeljuje joj se zbir a + b.

Vraćanje rezultata

  • Povratna vrednost funkcije se skladišti u posebnom registru procesora (npr. EAX u x86 arhitekturi) ili na steku.
  • Nakon povratka iz funkcije, zbir u main funkciji dobija ovu vrednost.

Čišćenje steka

  • Memorija zauzeta parametrima i promenljivom rezultat se oslobađa kada funkcija završi.

2. Funkcija sa pokazivačima i promene u memoriji

​Kod ovog primera koristićemo pokazivače da bismo direktno menjali vrednosti van funkcije.
#include <stdio.h>

// Funkcija koja menja vrednosti preko pokazivača
void zameni(int* a, int* b) {
int temp = *a; // Pristup vrednosti na adresi a
*a = *b; // Menja vrednost na adresi a
*b = temp; // Menja vrednost na adresi b
}

int main() {
int x = 5, y = 10;

printf("Pre zamene: x = %d, y = %d\n", x, y);
zameni(&x, &y); // Prosleđujemo adrese promenljivih

printf("Posle zamene: x = %d, y = %d\n", x, y);
return 0;
}

Šta se dešava u memoriji prilikom zameni(&x, &y)?

Alokacija memorije na steku

x i y su promenljive smeštene na steku main funkcije.
Kada pozovemo zameni(&x, &y), u stek funkcije zameni se smeštaju pokazivači na x i y.

Manipulacija podacima kroz pokazivače

*a pokazuje na vrednost x, a *b na y.
Zamena se odvija direktno u memoriji, tako da se x i y u main funkciji menjaju.

Povratak iz funkcije

Po završetku zameni, memorija zauzeta parametrima i temp promenljivom se oslobađa.
Pošto su vrednosti x i y promenjene na originalnim adresama, rezultat je trajna promena.

3. Funkcija sa dinamičkom alokacijom memorije

​Koristimo malloc za kreiranje dinamičkog niza.
#include <stdio.h>
#include <stdlib.h>

// Funkcija koja kreira dinamički niz i vraća pokazivač na njega
int* kreirajNiz(int n) {
int* niz = (int*)malloc(n * sizeof(int)); // Alokacija memorije na HEAP-u
if (niz == NULL) {
printf("Greška pri alokaciji memorije!\n");
return NULL;
}
for (int i = 0; i < n; i++) {
niz[i] = i + 1;
}
return niz; // Vraćamo pokazivač na prvi element
}

int main() {
int n = 5;
int* niz = kreirajNiz(n);

if (niz != NULL) {
printf("Generisani niz: ");
for (int i = 0; i < n; i++) {
printf("%d ", niz[i]);
}
printf("\n");

free(niz); // Oslobađanje memorije
}

return 0;
}

Šta se dešava u memoriji?

Poziv kreirajNiz(5)

  • Alocira se memorija na HEAP-u za n celih brojeva.
  • Pokazivač niz u kreirajNiz pokazuje na početak tog bloka memorije.

Vraćanje pokazivača

  • Pokazivač niz se prenosi nazad u main, gde se koristi za ispis vrednosti.

Oslobađanje memorije (free(niz))

  • Memorija na HEAP-u ostaje zauzeta sve dok eksplicitno ne pozovemo free(niz).
  • Bez free, imali bismo curenje memorije (memory leak).

Povezivanje sa srodnim temama

Da biste stekli dublje razumevanje funkcija u C jeziku, preporučujemo da pogledate sledeće srodne teme:

  • Pokazivači u C jeziku – Osnovni koncepti pokazivača, njihova uloga u funkcijama i rad sa dinamičkom memorijom.
  • Dinamički nizovi u C – Objašnjenje alokacije i dealokacije memorije pomoću malloc, free i drugih funkcija.
  • Rekurzija u C – Kako funkcije mogu pozivati same sebe i kada je rekurzija korisna.
  • Nizovi u C jeziku – Prolazak nizova kroz funkcije i razlike između prolaza vrednošću i referencom.

Ove teme su usko povezane sa funkcijama i omogućavaju bolje razumevanje kako funkcije upravljaju podacima i memorijom u C jeziku.


​Prethodno
​|< Pokazivači