Programski jezik C je programski jezik srednjeg nivoa koji ima neke karakteristike nižih programskih jezika a to su:
-ima mogućnost indirektog pristupa vrednostima promenljivih koje se čuvaju na memorijskim lokacijama preko adresa tih memorijskih lokacija
- u svojoj sintaksi sadrži operatore za operacije nad bitovima podataka (~,&,|,<<,>>)
- ima mogućnost pristupa registrima procesora
Operativna memorija
Koliko koji tip podatka zauzima prostora u operativnoj memoriji?
char a = ‘b’;
int b = 33;
short int c = 88;
Koliko bajtova zauzima promenljiva int a[50]?
Pokazivač je prost tip podatka u čijoj promenljivoj može da se smesti adresa memorijske lokacije neke promenljive.
Pomoću kog unarnog operatora može da se dobije adresa nekog podatka u memoriji?
Primeri:
int x;
int niz[50];
&x; // adresa memorijske lokacije promenljive x
&niz[5]; //adresa memorijske lokacije šestog elementa niza
&5; //GREŠKA!!!
&(x+1); //GREŠKA!!!
Vrednosti podatka u memoriji se na osnovu njegove adrese može pristupiti pomoću unarnog operatora *
DEFINICIJA POKAZIVAČA
Pokazivači se definišu kao i podaci svih ostalih tipova s tim što se ispred identifikatora odnosno naziva podatka dodaje znak *.
Opšti oblik definicije
tip *naziv_podatka;
Primer:
int *p;
PRE NEGO ŠTO POKAZIVAČ MOŽE DA SE KORISTI MORA MU SE DODELITI ADRESA NEKOG PODATAKA U OPERATIVNOJ MEMORIJI.
Primer 1:
double h, *ph=&h;
*ph = 8.8; //promenljiva h dobija vrednost 8.8
Primer 2:
int a, *pa;
pa = &a;
*pa = 7; //promenljiva a dobija vrednost 7//Primer za direktno i indirektno pristupanje adresi i vrednosti određene promenljive:
# include <stdio.h>
int main ()
{
int x=10;
int *px=&x;
printf("\n pristup na direktan nacin vrednosti promenljive x: %d",x);
printf("\n pristup na direktan nacin adresi date promenljive: %d",&x);
printf("\n pristun na indirektan nacin vrednosti promenljive: %d",*px);
printf("\n pristun na indirektan nacin vrednosti promenljive: %d",*&x);
printf("\n pristup na indirektan nacin adresi promenljive: %d", px);
}
Zadatak: Potrebno je nacrtati na koji način svaka promenljiva zauzima prostor u operativnoj memoriji i kako se sa promenom vrednosti promenljive menja sadržaj memorijske lokacije. Ukoliko neka od operacija nije dozovljena napisati poruku greška!!!
REŠENJE
DOMAĆI ZADATAK:
Potrebno je nacrtati na koji način svaka promenljiva zauzima prostor u operativnoj memoriji i kako se sa promenom vrednosti promenljive menja sadržaj njene memorijske lokacije. Ukoliko neka od operacija nije dozovljena napisati poruku greška!!!
int a=12,b=18;
float niz[]={8.8, 9.21, -13.81, 23.22, 44.78};
char c=’a’;
int *pi;
float *pf;
char *pc = &c;
*pi=21;
pi=38;
pi=&b;
*pi=121;
*pc = ’d’;
pf = &niz[2];
pf = niz[4];
*pf = niz[0];
&pi = &a;ADRESNA ARITMETIKA KOD POKAZIVAČA
Pokazivači su prosti podaci i nad njima se mogu obavljati sledeće operacije:
1. Dodeljivanje vrednosti jednog pokazivača drugom pokazivaču
2. Izračunavanje zbira i razlike pokazivača i celobrojnog podatka
3. Uvećanje odnosno umanjenje vrednosti pokazivača za jedan
4. Izračunavanje razlike dva pokazivača
5. Upoređivanje vrednosti dva pokazivača
6. Upoređivanje vrednosti pokazivača sa NULL simboličkom konstantom (ime vrednost nula) i dodela NULL vrednosti pokazivaču
Dodeljivanje vrednosti jednog pokazivača drugom se vrši pomoću operatora dodele vrednosti =.
Primeri:
int a=12, *pi1=&a, *pi2
pi2=pi1;
*pi2=15;Sabiranjem ili oduzimanjem pokazivača sa nekim celim brojem dobija se vrednost adrese neke memorijske lokacije.
int a[5]={1,3,5,7,9};
int *pi;
pi = &a[0]; // vrednost pi je 1 a *pi je 1
pi+=3;// sada je vrednost pi 13 a *pi je 7
pi-=2;// sada je vrednost pi 5 a *pi je 3
*pi = 9; // sada je vrednost a[1] 9Unarni operatori ++ i -- se mogu primenjivati na pokazivače i time se vrednost pokazivača smanjuje odnosno uvećava za jedan .
int a[5]={1,3,5,7,9},*pi;
pi = &a[2]; // vrednost pi je 9 a *pi je 5
pi++; // vrednost pi je 13 a *pi je 7
*pi = 12; // sada je vrednost a[3] 12
pi--; // vrednost pi je 9 a *pi je 5
*pi = 18; // sada je vrednost a[2] 18Razlika dva pokazivača predstavlja ceo broj. Izračunavanje razlike dva pokazivača se koristi ako želimo da dobijemo broj elemenata između dve memorijske lokacije
int a[5]={1,3,5,7,9}, *pi1, *pi2, r;
pi1 = &a[1]; // vrednost pi1 je 5 a *pi je 3
pi2 = &a[4]; // vrednost pi2 je 17 a *pi je 9
r = pi2-pi1; //vrednost r je 3Za poređenje vrednosti dva pokazivača možemo koristiti sledeće operatore: ==, <, >, !=, <=,>=.
int a,b,*pi1=&a,*pi2=&b;
if(pi1>pi2)
BN1
else if(pi2>pi1)
BN2Dozvoljeno je pokazivaču proizvoljnog tipa dodeliti nultu vrednost i upoređivati ga sa nultom vrednošću. Kada pokazivač ima vrednost nula to označava da on ne pokazuje ni na jedan podatak.
int *pi=NULL; VOID (GENERIČKI) POKAZIVAČ
Ako se neki pokazivač deklariše pomoću reči void tada je on generički pokazivač i nije određeno na koji tip promenljive on pokazuje.
int a
void *p = &a ;
*p = 7; //GRESKA
POKAZIVAČI I NIZOVI
Identifikator odnosno naziv niza bez navođenja indeksa predstavlja početnu adresu niza odnosno adresu elementa sa indeksom 0.
//Primer: izračunati zbir elemenata
//niza pomoću naziva niza
void main()
{
int n, i;
double a[100], s=0;
printf ("Unesite broj elemenata niza:");
scanf("%d",&n);
for(i=0;a+i<a+n;i++)
{
printf("Unesite %d. broj:",i);
scanf("%lf",a+i); // scanf("%lf",&a[i]);
s+= *(a+i); // s+= a[i];
}
printf("Zbir unetih brojeva je:%lf",s);
}//Primer: izračunati zbir elemenata
//niza pomoću pokazivača
void main()
{
int n;
double a[100], *p, s=0;
printf ("Unesite broj elemenata niza:");
scanf("%d",&n);
for(p=a,i=1;p<a+n;p++,i++)
{
printf("Unesite %d. broj:",i);
scanf("%lf",p);
s+= *p;
}
printf("Zbir unetih brojeva je:%lf",s);
}
Postoje dva načina za definisanje niza:
1) Statičko (int a[100]) –Memorijske lokacije zauzima kompajler u toku kompajliranja (prevođenja) programa.
2) Dinamički - Memorijske lokacije se zauzimaju u toku izvršavanja programa i zbog ovoga zauzeti memorijski prostor može da bude bolje iskorišćen.
Za dinamičku dodelu memorije koristimo dve funkcije:
1) malloc čiji prototip glasi: void *malloc(int vel);
2) calloc čiji prtototip glasi: void * calloc(int broj_blokova, int vel_bloka);
Kada se zauzme memorija dinamički potrebno je posle i da se oslobodi. Za to se koristi funkcija free čiji prototip je
void free(void *p)
Primer 1: program za dinamičko
definisanje niza celih brojeva. (malloc)
void main()
{
int *p,n;
printf("Unesite broj članova niza:");
scanf("%d",&n);
p = (int *)malloc(n*sizeof(int));
free(p);
}
Primer 2: program za dinamičko
definisanje celih brojeva. (calloc)
void main()
{
int *p,n;
printf("Unesite broj članova niza:");
scanf("%d",&n);
p = (int *)calloc(n,sizeof(int));
free(p);
}//Primer 3: program za izračunavanje sume brojeva korišćenjem
//dinamičkog niza sa jednom pokazivačkom promenljivom.
void main()
{
int *p1,n,s=0,i;
printf("Unesite broj članova niza:");
scanf("%d",&n);
p1 = (int *)calloc(n,sizeof(int));
for(i=0;i<n;i++) // for(i=0;p1+i<p1+n;i++)
{
printf("Unesite %d. broj:",i);
scanf("%d",p1+i); // scanf("%d",&p1[i]);
s+= *(p1+i); //može s+= p1[i];
}
printf("Zbir unetih brojeva je:%d",s);
free(p1);
}Realloc (realociranje)
Za menjanje veličine dinamičkog niza koristi se funkcija void *realloc(void *ptr, int vel).
void main()
{
int n,i;
int *niz;
char odg;
printf("\n Unesite broj elemenata niza:");
scanf("%d",&n);
niz = (int *) calloc(n,sizeof(int));
for(i=0;i<n;i++)
{
printf("\n Unesite %d. element niza:",i+1);
scanf("%d",&niz[i]);
}
do{
printf("\n Da li zelite da unesete novi element niza 'D'/'d'");
odg = getch();
if((odg=='d')||(odg=='D'))
{
niz=(int *)realloc(niz,++n*sizeof(int));
printf("\n Unesite nov element niza:");
scanf("%d",&niz[n-1]);
}
}while((odg=='d')||(odg=='D'));
printf("\n Elemenati niza su:");
for(i=0;i<n;i++)
{
printf("%d ",niz[i]);
}
free(niz);
getch();
}
Primer: dinamički definisati karakternu promenljivu
char *a = (char *) calloc(1,sizeof(char));
*a = ‘k’;
free(a);
Pomoću funkcija malloc i calloc moguće je dinamički definisati i promenljive osnovnih tipova podataka (za jednu promenljivu dve memorijske lokacije).
NAČIN ZAUZIMANJA OPERATIVNE MEMORIJE OD STRANE PROGRAMSKOG KODA
Zadatak:
Koristeći dinamičke nizove napisati sledeći program u kojem za uneti broj elemenata niza celih brojeva treba napisati i testirati sledeće potprograme za: unos elemenata niza, ispis elemenata niza, za izračunavanje sume elemenata niza, za izračunavanje prosečne vrednosti elemenata niza, za određivanje najvećeg elementa niza, za određivanje najmanjeg elementa niza, za prebrojavanje elemenata niza koji su deljivi sa određenim brojem, za prebrojavanje koliko ima određenog elementa niza. Teži: za određivanje najvećeg proizvoda cifara elementa niza. Pri tome cifru nula računati kao jedinicu. Voditi računa da se memorija oslobodi na kraju programa.
Potprogrami se dele na funkcije i procedure.
int Kvadrat(int x) // Vraća kvadrat broja
{
return x * x;
}
//Poziv funkcije
rez1 = Kvadrat(5);
rez2 = Kvadrat(5) + Kvadrat(10)+ Kvadrat(a)+c;
void ispisiPoruku()
{
printf("Procedura u programskom jeziku C.\n");
}
void unesiElementeUNiz(int niz[], int velicina)
{
for (int i = 0; i < velicina; i++)
{
printf("Unesite element [%d]: ", i + 1);
scanf("%d", &niz[i]);
}
}
//Pozi procedure
ispisiPoruku();
unesiElementeUNiz(niz,velicina);
ČISTE I NEČISTE FUNKCIJE
// Zavisi samo od ulaznih parametara
//i vraća tačno jedan rezultat
int saberi(int a, int b)
{
return a + b;
} //Primer1:
int rezultat = 0; //globalna promenljiva
// Menja globalnu promenljivu
void Saberi(int a, int b)
{
rezultat = a + b;
}
//Primer2:
int sabirak = 0; //globalna promenljiva
//Globalna promenljiva utiče
//na rezultat rada funkcije
int Saberi(int a)
{
return sabirak+a;
}
Primer 3:
//menja stanje sadržaja ekrana
void ispisiBroj(int broj)
{
printf("Uneti broj je: %d\n", broj);
}
BOČNI EFEKTI FUNKCIJA
//Prosledjivanje argumenata po vrednosti
int Zbir(int a, int b);
void main()
{
int a=5,b=7,c;
c = Zbir(a,b);
printf ("%d+%d=%d",a,b,c);
//5+7 = 45
}
int Zbir(int a, int b)
{
printf("Unesite vrednost prvog sabirka:");
scanf("%d", &a); //20
printf("Unesite vrednost drugog sabirka:");
scanf("%d", &b); //25
return a + b;
}
//Prosledjivanje argumenata po adresi
int Zbir(int *a, int *b);
void main()
{
int a=5,b=7,c;
c = Zbir(&a,&b);
printf ("%d+%d=%d",a,b,c);
//20+25 =45
}
int Zbir(int *a, int *b)
{
printf("Unesite vrednost prvog sabirka:");
scanf("%d", a);//20
printf("Unesite vrednost drugog sabirka:");
scanf("%d", b);//25
return (*a) + (*b);
}
Tekst zadatka
Prosleđivanje argumenata po vrednosti:
Zadatak: Nacrtajte kako će promenljive (po funkcijama main i zbir) da zauzmu memorijske lokacije u operativnoj memoriji u sledećim fazama izvršavanje koda pre poziva funckije zbir, za vreme poziva funkcije zbir, za vreme izvršavanja i posle završetka rada fukcije zbir. Napisati takođe šta će biti ispisano u okviru funkcije printf.
Prosleđivanje argumenata po vrednosti
Tekst zadatka
Prosleđivanje argumenata po adresi
Zadatak: Nacrtajte kako će promenljive (po funkcijama main i zbir) da zauzmu memorijske lokacije u operativnoj memoriji u sledećim fazama izvršavanje koda pre poziva funckije zbir, za vreme poziva funkcije zbir, za vreme izvršavanja i posle završetka rada fukcije zbir. Napisati takođe šta će biti ispisano u okviru funkcije printf.
Prosleđivanje argumenata po adresi
Zadatak 1: Napisati fukciju čiji će rezultat kroz bočni efekat da bude najveća i najmanja cifra unetog broja.
Zadatak 2: Napisati fukciju čiji će rezultat kroz bočni efekat da bude proizvod cifara i zbir cifara unetog broja.
Zadatak 3: Napisati fukciju čiji će rezultat kroz bočni efekat da bude zbir i proizvod dva broja.
Zadatak 4: Napisati program koji će za odabranu opciju da računa obim i površinu sledećih geometrijskih figura: Pravougaonik, Trougao, Krug i Romb (preko dijagonala). Za svaku figuru napišite posebnu funkciju čiji rezultat treba da bude i vrednost obima i površine. U slučaju trougla napravite zaštitu da zbir bilo koje dve stranice mora da bude veći od treće. Napravite sistem menija koji takođe realizujte preko funkcije.
printf("\t\t\tProgram za izracunavanje obima i povrsine geomterijskih figura");
printf("\n\tOdaberite zeljenu opciju");
printf("\n\t1) Pravougoanik");
printf("\n\t2) Trougao");
printf("\n\t3) Krug");
printf("\n\t4) Romb");
printf("\n\t5) Kraj programa");
printf("\n\tOdaberite opciju:");FUNKCIJE I NIZOVI
//Primer
int Suma(int a[], int n)
{
int i,s=0;
for(i=0;i<n;i++)
s+=a[i];
return s;
}
void main()
{
int niz[30],d=5,i,z;
for(i=0;i<d;i++)
{
printf("Unesite %d. broj:",i+1);
scanf("%d",&niz[i]);
//moze i scanf("%d",niz+i);
}
z= Suma(niz,d);
printf("Zbir unetih brojeva je:%d",z);
}
int Suma(int *a, int n)
{
int i,s=0;
for(i=0;i<n;i++)
s+=*(a+i);
return s;
}
void main()
{
int *p,d=5,i,z;
p = (int *)malloc(d*sizeof(int));
for(p,i=0;i<d;i++)
{
printf("Unesite %d. broj:",i+1);
scanf("%d",p+i);
//moze i scanf("%d",&p[i]);
}
z= Suma(p,d);
free(p);
}
//Primer 2:
int Suma(int a[], int n)
{
int i,s=0;
for(i=0;i<n;i++)
s+=a[i];
return s;
}
void main()
{
int *p,*niz,d=5,i,z;
p = (int *)malloc(d*sizeof(int));
for(niz=p,i=0;i<d;i++)
{
printf("Unesite %d. broj:",i+1);
scanf("%d",niz+i);
//moze i scanf("%d",&niz[i]);
}
z= Suma(p,d);
free(p);
}
FUNKCIJE KOJE VRAĆAJU POKAZIVAČE (imaju povratnu vrednost koja je pokazivač)
#include<stdio.h>
#include<conio.h>
#include<stdlib.h>
int *Unos(int n);
void main()
{
int n,i,*niz;
printf("\n Unesite broj elemenata niza:");
scanf("%d",&n);
niz = Unos(n);
printf("\n Elemenati niza su:");
for(i=0;i<n;i++)
{
printf("%d ",niz[i]);
}
free(niz);
getch();
}int *Unos(int n)
{
int *niz,i;
niz = (int *) calloc(n,sizeof(int));
for(i=0;i<n;i++)
{
printf("\n Unesite %d. element niza:",i+1);
scanf("%d",&niz[i]);
}
return niz;
}Zadatak: Koristeći dinamičke nizove
Potrebno je napisati program za rad sa dinamičkim nizovima korišćenjem funkcija (za svaku od opcija treba napisati posebnu funkciju). Pomoću switch-case upravljačke strukture potrebno je napravit meni. U okviru prve opcije je potrebno da se unese n elemenata niza korišćenjem funkcije malloc. U okviru druge opcije potrebno je da se ispišu elementi niza. U okviru treće opcije potrebno je da se ispiše najveći i najmanji element niza. U okviru četvrte opcije potrebno je pronaći sumu elemenata niza i prosečnu vrednost elemenata niza. Treću i četvrtu opciju uraditi koristeći bočne efekte funckija i rezultate rada ispisati u funkciji main. Peta opcija je kraj programa. Osnovni meni takođe realizovati preko funkcije.
printf("\t\t\tProgram za manipulaciju elementima niza");
printf("\n\tOdaberite zeljenu opciju");
printf("\n\t1) Unos elemenata niza");
printf("\n\t2) Ispis elemenata niza");
printf("\n\t3) Ispsi najveceg i najmanjeg elementa niza");
printf("\n\t4) Ispis sume i prosecna vrednosti elemenata niza");
printf("\n\t5) Kraj programa");
printf("\n\tOdaberite opciju:");