Strukture podataka i algoritmi 1

SPA1 - Vežbe 2

Makro

U programskom jeziku C, makro je predefinisana sekvenca koda koja se može koristiti za automatsku zamenu određenog izraza ili dela koda sa drugim izrazom ili delom koda tokom faze preprocesiranja.

Makroi se definišu koristeći #define direktivu preprocesora. Na primer:

#define PI 3.14159

Ovde, PI je makro koji je definisan kao konstanta sa vrednošću 3.14159. Kada se u kodu pojavi PI, preprocesor će automatski zameniti svako pojavljivanje PI sa vrednošću 3.14159.

Makroi se često koriste za definisanje konstanti, ali se mogu koristiti i za definisanje funkcija, operacija, ili čak kompleksnih blokova koda. Međutim, treba biti oprezan prilikom korišćenja makroa, jer mogu dovesti do neželjenih efekata kao što su nepredviđene zamene ili teško održavanje koda. Na primer:

#include <stdio.h>
#define KVADRAT(x) (x * x)

int main() {
    int y = 3;
    printf("%d\n", KVADRAT(y)); // 9
    printf("%d\n", KVADRAT(y + 2)); // y + 2 * y + 2 = 11
    return 0;
}

Ako koristimo makro za definisanje funkcija, parametri neće biti izračunati nego će samo biti zamenjeni, slično kao u primeru iznad. Nakon preprocesiranja, funkcija main će izgledati ovako:

#include <stdio.h>
#define KVADRAT(x) (x * x)

int main() {
    int y = 3;
    printf("%d\n", y*y); // 9
    printf("%d\n", y + 2*y + 2); // y + 2 * y + 2 = 11
    return 0;
}

Da je makro bio definisan ovako:

#define KVADRAT(x) ((x) * (x))

onda bi se ispisalo 9 i 25.

scanf

Funkcija scanf učitava vrednosti sa standardnog ulaza, smešta ih u promenljive i vraća broj učitanih vrednosti.

Primer 1

#include <stdio.h>

int main() {
    int x,sum=0;
    while(scanf("%d",&x)==1)
        sum+=x;
    printf("Ukupan zbir je %d\n",sum);
    return 0;
}

Ako bi ulaz bio:

10
23
30
15
p

Izlaz bi bio:
Ukupan zbir je 78

Svaki put kada bi uspešno izvršio učitavanje scanf bi vratio jedan jer je učitao samo jednu vrednost. Da smo stavili da scanf učitava dve vrednosti, onda bi vratio 2 ukoliko bi dobro učitao obe vrednosti. Kada korisnik unese nešto što je nevalidno (u ovom slučaju p), program će se završiti.

Učitavanje i ispis karaktera

getchar

getchar je metoda koja sa standardnog ulaza učitava jedan karakter i vraća taj karakter.

#include <stdio.h>

int main() {
    char c;
    c = getchar(); // menja scanf("%c", &c);
    printf("Karakter je %c, a njegova ASCII vrednost je %d\n", c, c);
    return 0;
}

Ako unesem ‘A’ karakter, izlaz će biti “Karakter je A, a njegova ASCII vrednost je 65”.

putchar

putchar je metoda koja ispisuje jedan karakter na standardni izlaz.

putchar('A');

Dozvoljeno je: putchar('A'); printf("abc"); printf("a"); Nije dozvoljeno je: putchar('ABC'); putchar("abc"); printf('a'); printf('abc');

EOF - End Of File

EOF je specijalni karakter koji označava kraj fajla. Ukoliko učitavamo karaktere sa standardnog ulaza sve dok ne naiđemo na karakter EOF učitavanje će se vršiti sve dok korisnik ne pritisne CTRL + D (na Linux-u) ili CTRL + Z (na Windows-u).

Primer 2

#include <stdio.h>

int main()
{
    char znak;
    while((znak=getchar()) != EOF) putchar(znak);

    return 0;
}

Unos će se vršiti sve dok korisnik ne pritisne CTRL + D (na Linux-u) ili CTRL + Z (na Windows-u).

Scope

Scope(opseg) promenljive u C-u je blok ili region u programu gde je promenljiva deklarisana, definisana i korišćena. Izvan ovog regiona, ne možemo pristupiti promenljivoj i tretira se kao nedeklarisani identifikator.

Postoje dve vrste scope-a:

  1. Globalni scope
    • promenljive, koje su deklarisane van funkcija, pripadaju globalnom scope-u i nazivaju se globalne promenljive
    • vidljive su u svim funkcijama u okviru jednog .c fajla
  2. Lokalni ili block scope
    • predstavlja opseg između dve vitičaste zagrade {}
    • promenljive koje su definisane u ovom scope-u nazivaju se lokalne promenljive
    • Lokalne promenljive su vidljive u bloku u kom su deklarisane i svim drugim ugnježdenim blokovima u okviru tog bloka
    • Promenljive nisu vidljive van bloka u kome su deklarisane

Primer 3

#include <stdio.h>
 
int main()
{
    {
        int x = 10, y = 20;
        {
            //spoljanji blok sadrži deklaracije i zbog toga ovo radi
            printf("x = %d, y = %d\n", x, y);
            {
                // iste te promenljive su vidljive i ovde
                x++;
 
                y++;
 
                printf("x = %d, y = %d\n", x, y);
            }
 
            // promene x++ i y++ će biti primenjene i biće ispisane njihove nove vrednosti
            printf("x = %d, y = %d\n", x, y);
        }
    }

    // x i y ne postoje u ovom bloku
    return 0;
}

Prekrivanje promenljivih

Prekrivanje promenljivih, poznato i kao skrivanje promenljivih ili promenljivih istog imena (engl. variable hiding), je koncept u programiranju gde promenljiva sa istim imenom u unutrašnjem opsegu bloka sakriva promenljivu sa istim imenom u spoljnom opsegu bloka. Ovo znači da pristupanje promenljivoj unutar unutrašnjeg bloka zapravo se odnosi na promenljivu unutar tog bloka, a ne na promenljivu spolja.

Na primer, ako imamo promenljivu x definisanu globalno i unutar funkcije imamo novu promenljivu x, promenljiva x unutar funkcije će prekriti (prekriti) globalnu promenljivu x unutar funkcije. To znači da se pristupanje promenljivoj x unutar funkcije odnosi na lokalnu promenljivu x, a ne na globalnu promenljivu x.

Prekrivanje promenljivih može biti korisno za izbegavanje konflikata imena promenljivih i upotrebu istog imena promenljive unutar različitih opsega bez brige o uticaju na promenljive iz spoljnog opsega. Međutim, prekomerna upotreba prekrivanja promenljivih može dovesti do nepredvidljivog ponašanja i teškoća u razumevanju koda, pa se preporučuje oprezno korišćenje ovog koncepta.

#include <stdio.h>

int pom = 10;

int main()
{
    printf("Globalno pom je pom=%d\n", pom); // pom=10
    int pom=1;
    printf("Pre ulaska u unutrasnji blok pom=%d\n",pom); // pom=1

    {
        int pom=50;
        printf("Pre izlaska iz unutrasnjeg bloka pom=%d\n", pom); // pom=50
    }

    printf("Nakon izlaska iz unutrasnjeg bloka pom=%d\n", pom); // pom=1
    
    return 0;
}

Korisni linkovi - Scope

Scope

static

Statičke promenljive u jeziku C su promenljive koje zadržavaju svoju vrednost tokom trajanja programa i imaju lokalni opseg. Osim toga, one se inicijalizuju samo jednom, pre nego što program uđe u funkciju ili blok koda u kojem su definisane, i zadržavaju tu vrednost sve dok se program izvršava.

Postoji nekoliko ključnih karakteristika statičkih promenljivih:

  1. Trajnost vrednosti: Vrednost statičke promenljive ostaje nepromenjena između poziva funkcije ili bloka koda. Ovo je korisno kada želimo da promenljiva zadrži svoju vrednost između različitih poziva iste funkcije.

  2. Lokalni opseg: Statičke promenljive imaju opseg bloka u kojem su definisane, slično običnim lokalnim promenljivama. To znači da su vidljive samo unutar funkcije ili bloka u kojem su deklarisane.

  3. Jednokratna inicijalizacija: Statičke promenljive se inicijalizuju samo jednom, pre nego što program uđe u funkciju ili blok koda u kojem su definisane. Ako se ne inicijalizuju eksplicitno, staticke promenljive tipa podataka se automatski inicijalizuju na nulu.

Statičke promenljive bi trebalo da budu inicijalizovane prilikom deklaracije, ali nije obavezno. Ne sme im se dodeliti rezultat neke funkcije, već samo konstante.

Primer 4

#include<stdio.h>

void funkcija();

int main() {
    int br;
    for(br=1;br<=5;br++) 
        funkcija();
    
    return 0;
}

void funkcija() {
    static int a=0;
    int b=0;
    printf("static=%d auto=%d\n",a,b);
    a++;
    b++;
}

Ispis: static=0 auto=0 static=1 auto=0 static=2 auto=0 static=3 auto=0 static=4 auto=0

Objašnjenje:

Statička promenljiva a se deklariše i inicijalizuje samo jednom i njena vrednost se pamti, iako je funkcija izvršena, za razliku od promenljive b koja se deklariše i inicijalizuje svaki put kada se funkcija poziva.

Korisni linkovi - static

Statičke promenljive