Tamara Luarasi – Tomi Thomo
SHTËPIA BOTUESE E TEKSTEVE MËSIMORE TIRANË, 2014
Teksti është miratuar dhe financuar nga Ministria e Arsimit dhe e Sportit.
Botues: Shtëpia Botuese e Teksteve Mësimore (BOTEM) Adresa: Rruga e Durrësit, Nr. 219, Tiranë, Shqipëri : + 355 4 2225659; botem1mas@gmail.com
Redaktimi letrar: Nirvana Lazi Arti grafik: Nirvana Lazi Kopertina Andi Nallbani Recensues: dr.Mimoza Durrësi dr.Oltion Fociro
© Shtëpia Botuese e Teksteve Mësimore, 2014. Të gjitha të drejtat janë të rezervuara. Nuk lejohet shumëfishimi me çdo mjet apo formë, pa lejen me shkrim të botuesit.
ISBN 978-99927-0-670-1
7 1.1. Kompilatori 1.2. Linkeri
9 10
12 2.1. Programimi i një kompjuteri-njeri – Roboti 2.2. Algoritmi 2.3. Programi 2.4. Bllokskemat 2.5. Përdorimi i simbolit “terminal” 2.6. Përdorimi i vijës së rrjedhës së logjikës dhe i simbolit lidhës 2.7. Simbolet e hyrje / daljeve (input / output) Ushtrime
12 12 13 15 16 17 18 19
3 22 3.1. Llogaritja e sipërfaqes së një mjedisi në formë drejtkëndëshi me përmasa të përcaktuara 3.2. Llogaritja e sipërfaqes së një drejtkëndëshi me përmasa të papërcaktuara 3.3. Llogaritja e sipërfaqes së një drejtkëndëshi me përmasa që plotësojnë kushtet e dhëna 3.4. Llogaritja e veprimeve me dy numra Ushtrime
22 23 24 25 26
27 4.1. Llogaritja e sipërfaqes së disa mjediseve 4.2. Llogaritja e shumës së sipërfaqeve të disa drejtkëndëshave
27 28
4.2. Përsëritja e futjes së të dhënave kur ato janë jokorrekte 4.2.1. Llogaritja e sipërfaqes 4.2.2. Veprimet me dy numra Ushtrime
29 29 30 31
32 5.1. Gjetja e shumës së 100 numrave të parë natyralë 5.2. Gjetja e shumës së disa numrave të parë natyralë 5.3. Gjetja e shumës së thyesave përderisa thyesa të jetë më e madhe se Ushtrime
32 33 34 35
36 Ushtrim
38
39 Ushtrime
41
44 8.1. Identifikimi i variablave 8.1.1. Identifikuesit 8.1.2. Konstantet
44 45 46
47 Ushtrime
49
52 9.1. Dhënia e vlerës(Assignment) (=)
52
+, -, *, /, % 11.1. Operatorët e përbërë të dhënies së vlerës (+=, -=, *=, /=, %=, >>=, <<=, &=, ^=, |=) 11.2. Shtimi dhe zbritja (++, --) Ushtrime
(==, !=, >, <, >=, <=) 12.1. Operatorët logjikë (!, &&, ||) Ushtrime
54 54 55 56
60 62 63
65 13.1. Përparësia e operatorëve Ushtrime
65 66
67 14.1. Dalja standarde (cout) 14.2. Hyrja standarde (cin) 14.3. cin dhe stringjet Ushtrime
67 70 71 72
75 15.1. Struktura e një kushti: if dhe else Ushtrime
76 80
86 16.1. Cikli while 16.2. Cikli do-while 16.3. Cikli for
87 89 90
16.4. Statementi break 16.5. Statementi continue Ushtrime
92 93 94
98 17.1. Shembuj funksionesh 17.1.1. Shembull i një funksioni pa parametra Ushtrime 17.2. Fusha e veprimit të variablave 17.3. Funksionet pa tip. Përdorimi i void 17.4. Rekursiviteti 17.4.1. Shembuj përdorimi funksionesh rekursive 17.4.2. Funksion që llogarit shumën e një vargu numrash natyralë 17.5. Deklarimi i funksioneve Ushtrime
98 103 103 104 107 110 113 114 115 115
Në një kompjuter të ri nuk do të mund të bënim asnjë veprim nëse ai (kompjuteri) nuk do të ishte i pajisur me një bashkësi programesh, e quajtur sistemi operativ i kompjuterit. Një nga sistemet më të njohura të kompjuterit është sistemi Windows, i cili është edhe sistemi që njohim në kompjuterat tanë personalë, si dhe në çdo kompjuter tjetër në shtëpi, në shkollë etj. Kompjuteri përbëhet nga pjesa fizike, e cila quhet hardueri (harware) i kompjuterit, dhe nga bashkësia e programeve, që përbën softuerin (softwere) e tij. Për ta kuptuar se si funksionon një program në kompjuter, më parë duhet të dimë diçka mbi harduerin e tij. Në figurën e mëposhtme (fig. 1.1) është dhënë një pamje e përgjithshme e harduerit të kompjuterit. Kompjuteri ka pjesën qendrore, e cila përbëhet nga procesori dhe kujtesa (qendrore dhe dytësore); ka pajisjet e veta hyrëse (tastiera, pajisja e ruajtjes USB, mausi, skaneri), si dhe pajisjet dalëse (monitori, pajisja e ruajtjes USB, hard disku ose printeri).
Kur kompjuteri ekzekuton një program, vihen në punë të gjitha pjesët e tij harduerike. Programi dhe të dhënat futen nga pajisjet hyrëse dhe vendosen në kujtesë e ndërkohë procesori përpunon instruksionet e programit. Po, përveç programeve-bazë që ka kompjuteri në fillim, kur blihet, mund të hartojmë edhe programet tona, duke e pasuruar kështu pjesën e tij të softuerit. -Çfarë është një program dhe si duhet të mendojmë para se të shkruajmë një program? Materiali i këtij teksti është një ndërthurje e këtyre dy aspekteve, pra, si duhet të mendojmë për ta zgjidhur një problem në kompjuter dhe si e realizojmë atë me një program në gjuhën e programimit C++. Kur fillojmë të mësojmë një gjuhë programimi, në fillim mund të na duket se pjesa më e vështirë e zgjidhjes së një problemi në kompjuter është të shprehurit e ideve tona në gjuhën e programimit. Por, në të vërtetë, pjesa më e rëndësishme në procesin e zgjidhjes së një problemi është gjetja e metodës së zgjidhjes së problemit. Në këtë fazë të punës nuk kemi pse të mendojmë për gjuhën me të cilën do të punojmë në kompjuter, por duhet të jemi në gjendje të shprehim me fjalët tona radhën e hapave që duhen ndjekur për zgjidhjen e një problemi të caktuar. Këta hapa duhet t’i mendojmë si instruksione që mund t’ia jepnim dikujt, një personi p.sh., sesa instruksione për një kompjuter. Pikërisht kjo radhë instruksionesh që do të mund të realizonte zgjidhjen e një problemi, quhet algoritëm dhe mënyra e të shprehurit të algoritmit me fjalët tona, quhet pseudokod. Algoritmi shpreh mënyrën se si e konceptojmë zgjidhjen e një problemi, të cilin mund ta paraqesim në mënyra të ndryshme, me fjalët tona (pseudokodi) ose me simbole të ndryshme (bllokskema). Gjuha e programimit na ndihmon që pseudokodin ose bllokskemën t’ia shprehim kompjuterit në një mënyrë të kuptueshme ose në formën e kodit-burim të një programi. -Ç’është instruksioni për kompjuterin? Instruksioni është një komandë-bazë për të cilën ekziston një mekanizëm hardueri që e ekzekuton atë. Kompjuteri është një makinë programuese e ndërtuar për të ekzekutuar instruksione. Programi përbëhet nga instruksione dhe, kur themi “programi ekzekutohet”, këto instruksione janë në kujtesë dhe ekzekutohen. Në të vërtetë, kur e shkruajmë atë që quajmë kod-burim të një programi, ne nuk shkruajmë instruksione, por një bashkësi të tërë instruksionesh njëherësh, si një rresht të kodit-burim, të cilin e quajmë statement. Këtë lehtësi na e japin gjuhët e programimit të nivelit të lartë, siç është edhe gjuha C++. Kompjuteri ekzekuton vetëm instruksionet në formën e tyre binare (me zero dhe njësha) ose, e thënë ndryshe, instruksionet e shprehura në gjuhën-makinë si për shembull: 1011010000000101 Gjuha-makinë ose gjuhë të afërta me të quhen gjuhë të nivelit të ulët. Është vështirë ta shkruajmë kodin-burim të një programi në gjuhë të nivelit të ulët, mbasi gjuhë të tilla
përshkruajnë në detaje çdo komandë që duhet të ekzekutojë kompjuteri për zgjidhjen e një problemi. Në vend që të shkruhen programe në gjuhën-makinë, përdoren gjuhët e programimit të nivelit të lartë. Kodi-burim kthehet në gjuhën-makinë nëpërmjet kompilatorëve, të cilët janë gjithashtu programe të kompjuterit. Ka disa gjuhë programimi të nivelit të lartë siç janë: C, C++, Java, C#, Python etj.1 Në figurën e mëposhtme (fig.1.1) jepet një pamje e thjeshtë e ekzekutimit të një programi. Hyrja në kompjuter mund të mendohet nga dy pjesë: një program dhe të dhënat.
Kompjuteri ndjek instruksionet e programit, që përdorin edhe disa të dhëna hyrëse të nevojshme në mënyrë që programi të realizojë veprimet e tij. Për shembull, një program mbledh dy numra dhe, atëherë, të dhënat janë pikërisht këta dy numra. Me fjalë të tjera, të dhënat janë informacionet hyrëse për programin, ndërsa programi bashkë me të dhënat përbëjnë hyrjen për kompjuterin. Kështu themi se kompjuteri ekzekuton programin mbi të dhënat.
Kompilatorët janë programe që e përkthejnë kodin-burim në gjuhë-makinë. Pra, hyrja në një kompilator është një program dhe dalja është përsëri një program, por në një formë tjetër. Programin hyrës zakonisht e quajmë program-burim ose kod-burim, ndërsa daljen e quajmë programin-objekt ose kod-objekt. Kodi-objekt përbëhet nga instruksione që mund t’i ekzekutojë makina. Figura në vijim jep procesin e përkthimit të kodit-burim të një programi. 1
Në këtë tekst ne do të punohet vetëm me gjuhën e programimit C++, që mund të konsiderohet si një gjuhë e cila ka edhe elemente të një gjuhe të nivelit të ulët dhe njëherësh është gjuhë e nivelit të lartë.
Para se të ekzekutohet një program, programit-objekt që prodhon kompilatori nga programiburim, i shtohen dhe pjesë të tjera, të cilat i ofron gjuha C++, duke e lehtësuar kështu punën tonë. Lidhja e programit që e kemi shkruar vetë dhe e atyre pjesëve që na jepen të gatshme realizohet me një tjetër program, i cili quhet linker. Një skemë e përgjithshme e ndërveprimit të kompilatorit dhe linkerit paraqitet në figurën e mëposhtme.
Sistemi operativ bën të mundur komunikimin tonë me të gjitha pajisjet hyrëse dhe dalëse të kompjuterit. Një nga detyrat e sistemit operativ është dhe ekzekutimi i programeve që krijojmë vetë. Pyetje: 1. Ç’është një algoritëm? 2. Ç’është një program? 3. Cili është ndryshimi midis gjuhës-makinë dhe gjuhëve të nivelit të lartë? 4. Çfarë është programi-burim? 5. Cili është roli i kompilatorit? 6. Çfarë është programi-objekt? 7. Çfarë është linkeri?
Për të krijuar idenë e një algoritmi, të pseudokodit me të cilin shprehet algoritmi, si dhe të kthimit të tij në një program që është i kuptueshëm nga kompilatori, marrim si shembull një problem praktik dhe e shtrojmë për zgjidhje: ndërrimin e rrotës së makinës. Hamendësojmë se qëllimi ynë do të ishte krijimi i një mekanizmi “njeri-robot”, që do të realizonte veprimet e kërkuara për ndërrimin e një rrote makine.
Për ndërrimin e rrotës së makinës është e nevojshme të ndiqet kjo rrugë: Hapi 1:
Ngrihet makina.
Hapi 2:
Hiqen vidat.
Hapi 3:
Hiqet rrota.
Hapi 4:
Montohet rrota e re.
Hapi 5:
Vendosen vidat.
Hapi 6:
Ulet makina.
Të gjitha këto instruksione përbëjnë një algoritëm të paraqitur me një pseudokod. Për të shkruar një program, më parë duhet krijuar një gjuhë e veçantë, e cila do të përdoret nga të gjithë, por që kuptohet edhe nga roboti (në rastin tonë duhet gjuha e ndërrimit të rrotave).1 GNR-ja përfshin disa emra të përgjithshëm, të cilët i përdorim në fjalorin e ndërrimit të rrotave, siç janë: makinë rrotë 1
Edhe pse në këtë tekst do të përdoret gjuha C++, për shembullin në fjalë do të përdorim një gjuhë të krijuar pikërisht për këtë rast, pra, gjuhën e ndërrimit të rrotave (shkurtimisht GNR).
vidë krik kuti e veglave rrotë rezervë xhiro-makine, kryq. 5
GNR-ja përfshin gjithashtu edhe foljet: merr vendos lësho rrotullo.
Së fundi, procesori që do të ekzekutojë GNR-në, duhet të ketë aftësinë për të numëruar dhe për të marrë vendime të thjeshta. Kjo është gjithçka që kupton një robot i ndërrimit të rrotave, çdo gjë tjetër është e pakuptueshme për të.
Pasi u bënë hapat e mësipërm: u krijua fjalori me emra dhe folje, është momenti që të konvertohet algoritmi në gjuhën e kuptueshme nga roboti. Duke e analizuar algoritmin rresht për rresht, shohim se fjalia e hapit 3:“Hiqen vidat” mbetet e papërcaktuar, pasi folja “heq” nuk është e përfshirë në fjalorin e procesorit. Në këtë rast për të shprehur veprimin që duhet bërë, është e nevojshme të krijohen fjali të formuara vetëm me fjalët që përmbahen në gjuhën e kuptueshme nga roboti. Kështu, në rastin tonë për të shprehur fjalinë “Hiqen vidat” veprohet duke ndjekur këta hapa: Hapi 1:
Merr xhiro-makinën.
Hapi 2:
Vendos xhiro-makinën te vidat.
Hapi 3:
Rrotulloj xhiro-makinën pesë herë.
Hapi 4:
Vendos xhiro-makinën te kutia e veglave.
Hapi 5:
Lësho xhiro-makinën.
Këtu nuk merret parasysh forma apo ndërtimi gjuhësor i fjalëve dhe fjalive (morfologjia apo sintaksa, d.m.th. rasa, gjinia apo numri i emrave; kohët, mënyrat apo vetat e foljeve; nyjat e ndryshme që mund të përdoren). Por, kur do të përdorim gjuhën C++, do të kemi rregulla të asaj gjuhe të përcaktuara plotësisht. Programi fillon në hapin 1 dhe vijon me hapat e tjerë deri sa të arrijë në hapin 5. Në terminologjinë e programit themi se “programi ecën nga hapi 1 deri në hapin 5”. Çdo hap
përshkruhet në një gjuhë programimi me një statement. Por mund të ngrihen edhe probleme të tjera si p.sh.: Çfarë do të ndodhë nëse nuk ka vida? Në këtë rast na nevojitet një statement “nëse” dhe atëherë do të veprohet me këta hapa: Hapi 1: Merr xhiro-makinën Hapi 2: Nëse ka vida { Hapi 3: Vendos xhiro-makinën te vida. Hapi 4: Rotullo xhiro-makinën pesë herë në të kundërt të akrepave të orës. } Hapi 5: Vendos xhiro-makinën në kutinë e veglave.
Programi fillon në hapin 1, ashtu si dhe më parë. Në hapin 2, para se të vendosë xhiromakinën, sigurohet se ka vidë. Kemi të bëjmë me një shprehje logjike “ka vidë”, që, ose është e vërtetë dhe vazhdon procesi (më poshtë do të themi se shprehja ka vlerën true), ose nuk është e vërtetë dhe procesi ndërpritet (më poshtë do të themi se shprehja ka vlerën false). Në qoftë se vlera e shprehjes është true, vijohet me hapin 3 dhe 4, si dhe më parë. Por, nëse shprehja ka vlerë false, atëherë programi i kapërcen këta hapa dhe shkon drejt hapit 5, duke e kthyer xhiro-makinën në kutinë e veglave dhe ndërkohë procesi ndërpritet. Një shprehje është një tip statementi që prodhon një vlerë, siç është shprehja 1 + 2. Një shprehje logjike merr vlerën true ose false. Në rastin kur ecuria e procesit varet nga vlera që merr shprehja logjike, shprehja quhet kusht. Kllapat gjarpërushe në GNR janë të nevojshme për t’i treguar programit se cilët hapa duhen kapërcyer, po qe se kushti nuk është true. Hapat 3 dhe 4 ekzekutohen vetëm nëse kushti është true. Ky program i përmirësuar ka ende një problem: -Si do të kuptohet se duhet të bëhen 5 rrotullime të xhiro-makinës për ta hequr vidën? -Si mund t’i realizojë programi më pak ose më shumë rrotullime, sipas rastit? Një mënyrë e zgjidhjes së këtij problemi është që në GNR të shtojmë një tip statementi të formës “përderisa nuk është plotësuar diçka, vazhdo të testosh”. Hapi 1:
Merr xhiro-makinën.
Hapi 2:
Nëse ka vidë. { Hapi 3: Vendos xhiro-makinën te vida. Hapi 4:Përderisa (vida është në makinë) {
Hapi 5: Rrotullo xhiro-makinën pesë herë në të kundërt të akrepit të orës. } } Hapi 6: Vendos xhiro-makinën në kutinë e veglave. Hapi 7: Lësho xhiro-makinën.
Hapat nga 1 deri në 3 janë si më parë. Në hapin 4 procesori duhet të marrë një vendim: vida vazhdon të jetë në makinë. Kur në hapin 4 kushti merr vlerë true, vida është në makinë, procesori kalon në hapin 5. Pas tij programi kthehet në hapin 4 dhe përsërit testimin. Po qe se vida hiqet nga makina, kushti në hapin 4 merr vlerë false dhe në moment program kalon në hapin 6, ndërsa procesi vazhdon si më parë.
Për të dokumentuar logjikën e një programi që është algoritmi, tanimë është bërë e zakonshme që të përdoren dy mënyra: bllokskema dhe pseudokodi. Përgjithësisht bllokskema punon mirë për probleme të vogla dhe pseudokodi për probleme më komplekse. Disa nga simbolet e përdorur në bllokskema, janë paraqitur si në figurën e mëposhtme.
Simboli “terminal” tregon një pikë fillimi dhe një pikë mbarimi të logjikës së një procesi. Një bllokskemë duhet të ketë vetëm një simbol fillimi dhe një simbol mbarimi për çdo proces.
Në figurën e mëposhtme paraqitet një shembull përdorimi korrekt i simbolit terminal, po ashtu edhe një shembull jokorrekt i përdorimit të tij.
Fillimi dhe mbarimi i programit në një kod C++ mund të jepet si në figurën që vijon (fig.2.4). int main () // fillimi i programit { return 0; //fundi i programit }
Kjo është dhe struktura e një programi në C++. Kur ekzekutohet një program C++, kontrolli fillon pikërisht nga rreshti: int main () dhe mbaron kur takon statementin return 0; main() ë ë një funksion2; gjithçka brenda {} përbën trupin e funksionit ku vendosen statementet. Me return 0 do të kuptojmë se, në mbarim të ekzekutimit të rregullt, programi i kthen vlerën 0 sistemit operativ, i cili është përgjegjës për ekzekutimin e programit dhe, meqenëse është një vlerë e plotë, atëherë përdoret int, çka shpreh faktin se kjo vlerë që kthehet, është e plotë.
Qëllimi i vijës së rrjedhës logjike është që të lidhë hapa të ndryshëm në procesin logjik të një bllokskeme, ndërsa simboli lidhës përdoret për të lidhur dy ose më shumë vija në mënyrë që të ndjekin të njëjtën rrugë logjike. Në figurën e mëposhtme (fig.2.5) vija e rrjedhës së logjikës paraqitet me anë të një një shigjetë me një kahe, ndërsa simboli lidhës paraqitet me një rreth. fillim
fund
Disa përdorime jo të rregullta të vijave të rrjedhës së logjikës dhe të simbolit lidhës ose mungesa të përdorimit të tyre ilustrohen në figurën vijuese (fig.2.6). 2
Në këtë tekst funksionet nuk janë objekt trajtimi.
Simbolet e hyrjeve dhe daljeve janë simbolet e leximit dhe të shkrimit nga / dhe në pajisje të ndryshme. Kështu, p.sh. kemi lexim nga një skedar (më poshtë do ta quajmë file) ose nga tastiera; shkrim në ekranin e një kompjuteri etj. Një simbol hyrje përdoret për leximin e informacionit nga pajisje të ndryshme. Ky veprim specifik zakonisht përshkruhet si një veprim leximi, duke hapur dhe duke lexuar një file ose nga tastiera. Është e rëndësishme të kuptohet që, nëse një veprim leximi kërkon informacionin që duhet të përdoret, bllokskema duhet, së pari, të paraqesë një futje të dhënash (hyrje), e cila merr informacion për proceset e mëtejshme. Për veprimet hyrëse mund të përdoren: Një pajisje rezervimi, e cila përdoret si kujtesë dytësore, siç janë: hard-disqet, pajisjet usb, disqet kompakte (cd) ose disqet dixhitale video (dvd). Një tastierë Një monitor elektronik, që nuk është pajisje e zakonshme (shpeshherë është në formën e një ekrani të prekshëm). Shembujt më lart nuk janë tipat e vetëm të pajisjeve hyrëse ose burimeve të të dhënave hyrëse
tastjeara
Në figurën e mësipërme (fig.2.7) janë dhënë dy shembuj të simbolit hyrës: njëri nga një përdorues dhe njëri nga një skedar. Zakonisht nuk është e nevojshme të specifikohet burimi ose pajisja, por megjithatë, për qartësi, nganjëherë edhe mund të specifikohen. Një simbol dalje përdoret për shkrim në pajisje të ndryshme. Tipat specifikë të veprimeve përshkruhen si një veprim shkrimi, si shkrimi në një printer ose shkrim në skedar, po ashtu dhe mbyllje të tij. Është e rëndësishme të vihet në dukje që disa pajisje mund të jenë pajisje hyrje dhe dalje njëkohësisht. Për shembull, një ekran elektronik ose një pajisje rezervimi mund të jetë edhe pajisje hyrje, edhe pajisje dalje. Si pajisje dalje mund të përdoren: Një pajisje rezervimi (mund të jetë jo vetëm pajisje dalje, por dhe hyrje). Një monitor elektronik. Një printer.
Shembull 1
Shembull 2
tastjeara
1. Simboli fundor paraqitet si ______________ në bllokskemën e një programi. a)
b) c) ç)
2. Simboli fundor përdoret për __________________ në rrjedhën e një procesi. a) Hyrje dhe dalje b) Hapje dhe mbyllje c) Fillim dhe mbarim ç) Dy nga opsionet e mësipërme a) dhe c).
3. Bllokskema e mëposhtme konsiderohet jokorrekte për këto arsye: a) Ka më shumë se një simbol fillimi; b) Ka më shumë se një simbol fundor; c) Duhet të ketë 6 simbole fundore; ç) Ka vetëm tre simbole fundore.
4. Në lidhje me vijat e rrjedhjes, bllokskema e mësipërme do të konsiderohej jokorrekte për këto arsye: a) Përdorimi i një simboli lidhës për të lidhur vijat e rrjedhjes logjike. b) Përdorimi i dy vijave të rrjedhës logjike, që paraqiten dydrejtimëshe. c) Mospërdorimi i një simboli lidhës për lidhjen e dy vijave. ç) Për dy nga opsionet e mësipërme b) dhe c).
5. Një simbol hyrje / dalje mund të tregojë hyrjen në një bllokskemë nga një: a) Pajisje rezervimi. b) Tastierë. c) Monitor elektronik. ç) Të gjitha opsionet e mësipërme: a), b), c).
6. Simboli i hyrje / daljeve shfaqet në një bllokskemë si: a)
b)
c)
ç)
7. Një simbol hyrje / dalje mund të tregojë daljen në një bllokskemë prej një: a) Pajisje rezervimi. b) Simboli-bllokskemë. c) Printeri. ç) Dy nga opsionet e mësipërme: a) dhe c).
Le të shprehim disa algoritme të thjeshta nëpërmjet bllokskemave. Të shkruhet një algoritëm dhe të vizatohet një bllokskemë, e cila llogarit sipërfaqen e një drejtkëndëshi me gjerësi 3.5 metra dhe gjatësi 5.7 metra.
Siҫ vihet re nga figura e mësipërme, për zgjidhjen e një problemi, së pari duhet të mendojmë të dhënat që do të duheshin për ta zgjidhur atë problemi, pra, veprimi i parë që bëjmë është vendosja e të dhënave në kujtesë. Më tej, duke pasur të dhënat, me to realizojmë veprimin që duam të kryejmë, i cili, në këtë rast, është shumëzimi i të dhënave. Rezultatin që marrim, e kalojmë përsëri në një vend në kujtesë, për të mund ta përdorur edhe herë tjetër, ndërkohë mund ta afishojmë edhe në ekran. Duhet të kemi parasysh se emrat që përdorim: gjerësi, gjatësi, sipërfaqe, janë
thjesht emërtime të vendeve të caktuara të kujtesës qendrore të kompjuterit, ku vendosen vlerat hyrëse ose rezultati.
Le ta zëmë se do të realizojmë një program që llogarit sipërfaqen e një drejtkëndëshi. Gjatësia dhe gjerësia e drejtkëndëshit nuk janë të paracaktuara, por kërkohen nga kompjuteri në momentin që ekzekutohet programi. Të gjitha veprimet që do të kryhen në këtë rast, shprehen në pseudokod ose në bllokskemë si në figurën e mëposhtme (fig.3.2).
Siҫ mund ta kuptojmë, problema e dytë është më e përgjithshme se e para, dhe zgjidhja e dhënë me algoritmin e mësipërm u jep përgjigje gjithë rasteve, pavarësisht nga përmasat konkrete.
Siҫ e shohim nga bllokskema e figurës më lart (fig.3.3.), dallimi me shembullin e figurës 3.2 qëndron në faktin se këtu kemi vendosur një kusht për të dhënat, dhe e kemi shprehur me simbolet më të djathtë:
Të hamendësojmë që do të realizojmë një program i cili kryen veprimet midis dy numrave dhe më pas e afishon rezultatin. Së pari, kompjuteri duhet t’i dijë numrat me të cilët do të veprojmë; së dyti, duhet të dijë se cilin veprim do të donim të kryenim me këta numra.
1. Të shkruhet pseudokodi dhe bllokskema që llogarit shprehjen
Ku:
π = 3.14 r=5
2. Të shkruhet pseudokodi dhe bllokskema që llogarit shprehjen
ku:
a = 2, b = 4, c=8
3. Të rishkruhet ushtrimi 2, por a, b, c duhet të jenë të paracaktuar: Kujdes: c nuk duhet të jetë zero.
4. Të shkruhet bllokskema që i përgjigjet pseudokodit të mëposhtëm për llogaritjen e pagës bruto të një punonjësi në bazë të orëve të punës dhe të pagesës për orë. Për të llogaritur pagën bruto të një punonjësi duhet të ndjekim hapat që vijojnë: Afishohet një mesazh në ekran: “Sa orë keni punuar?” Kompjuteri duhet të jetë në gjendje pritjeje që përdoruesi të fusë orët e punës. Sapo përdoruesi shkruan numrin, ai regjistrohet në kujtesë. Afishohet një mesazh në ekran: “Sa paguheni për një orë?” Kompjuteri duhet të jetë në gjendje pritjeje në mënyrë që përdoruesi të fusë numrin përkatës. Sapo përdoruesi shkruan numrin, ai regjistrohet në kujtesë. Shumëzohen orët e punës me vlerën e pagesës për një orë (vlera ndërkohë është regjistruar në kujtesë). Rezultati afishohet në ekran. Përdorni një bllokskemë për paraqitjen e këtij algoritmi.
Shpesh zgjidhja e një probleme lidhet me përsëritjen e një ose disa hapave. Në këtë rast në programim përdoren ciklet. Gjuhët e programimit, pra, edhe gjuha C++, kanë disa rregulla shkrimi për ciklet.
gjatesia
5
Le të marrim një shembull: hamendësojmë se duam të llogarisim sipërfaqen e çdo nga mjedisi të një shtëpie me dy dhoma, një kuzhinë, korridor, banjë. Gjithsej janë 5 mjedise, pra, llogaritja e sipërfaqes, që do të bëjmë, do të përsëritet 5 herë. Në këtë rast kemi një cikël me 5 hapa, ku në ҫdo hap do të kryheshin të gjitha hapat e llogaritjes së sipërfaqes së një mjedisi. Me një pseudokod e një bllokskemë do të kemi një skemë si në figurën më parë (fig.4.1). Një element të rëndësishëm që vëmë re në këtë shembull, është akumulimi i një vlere të një vendi në kujtesë dhe pikërisht te vendi i kujtesës i quajtur numërator. Fillimisht ai duhet të marrë një vlerë 0, më pas kësaj vlere i shtohet 1 për ҫdo hap të ciklit. Kjo gjë do të siguronte që në një moment vlera të bëhej 5, gjë që do t’i jepte fund ciklit ose përsëritjes së llogaritjeve. Përndryshe, cikli nuk do të mbaronte së vepruari.
Në pikat 3.3 dhe 3.4 të kreut 3 pamë se, kur të dhënat nuk ishin korrekte ose nuk plotësonin kushtet tona, ne e mbyllnim programin. Megjithatë është mirë të mos e mbyllim programin, por personit që e përdor atë, t’i japim mundësi për t’i futur përsëri të dhënat në mënyrë korrekte. Atëherë figurat 3.3 dhe 3.4 do të kishin ndryshime në pseudokod dhe bllokskemë:
1. Të shkruhet pseudokodi dhe bllokskema që fut emrat e 5 nxënësve dhe i afishon ata në ekran.
2. Të shkruhet 10 herë fjala “Përshëndetje”, duke e shoqëruar atë me një numërator, si më poshtë: Përshëndetje 1 Përshëndetje 2 Përshëndetje 3 ...................
3. Të shkruhet pseudokodi dhe bllokskema që llogarit shprehjen
, duke përdorur një
cikël. Udhëzim: fillimisht rezultatit i jepini vlerën 1 (në shumëzim 1 nuk ndikon në rezultat). Më pas shumëzojeni rezultatin 4 herë me vlerën 5 me anën e një cikli. Rezultati = rezultati * 5
4. Të rishkruhet ushtrimi 2, ku shprehja që do të llogaritet, është
, ku
dhe b nuk janë të
paracaktuar: Kujdes: a duhet të jetë në intervalin [2-10] dhe b në intervalin [1-5].
5. Të shkruhet pseudokodit dhe bllokskema që llogarit pagën e 10 punëtorëve, në bazë të orëve të punës dhe të pagesës për një orë.
6. Të ribëhet ushtrimi 6, duke llogaritur totalin e pagave dhe duke e afishuar atë.
Shpesh të dhënat hyrëse në një program janë vargje numrash për të cilët mund të përcaktohet një rregull në përcaktimin e secilit prej tyre duke ditur numrat paraardhës. Përdorimi i të dhënave të tilla në një program e lehtëson programin në kuptimin e shmangies së futjes së të dhënave një nga një, mbasi ato mund të krijohen në bazë të një formule.
Të dhënat që përdoren janë 1, 2, 3,..., 100. Karakteristikë e të dhënave në këtë rast është se mes dy elementeve të njëpasnjëshme ekziston kjo lidhje: numri = numri paraardhës + 1
o
Lidhja ndërmjet elementeve të njëpasnjëshme na ndihmon që ne t’i bëjmë të ditur programit vetëm numrin e parë në këtë varg numrash, po ashtu edhe sa të tillë janë. Veprimi i mësipërm (numri = numri paraardhës + 1 përsëritet 100 herë, pra, duhet të interesohemi që t’i numërojmë hapat derisa ata të arrijnë vlerën 100. Për këtë duhet një numërator, i cili fillimisht merr vlerën zero. Gjithë puna do të bëhet në një cikël, brenda të cilit, me ndihmën e formulës numri = numri paraardhës + 1, krijohen një pas një të gjithë numrat e vargut. Këtë proces e realizon më së miri pseudokodi dhe bllokskema në figurën e mësipërme (fig. 5.2).
Kjo problemë nuk ndryshon shumë nga problema e shtruar në paragrafin e mëparshëm (5.1). Ndryshimi i vetëm është që duhet t’i bëjmë të ditur programit sa numra do të mbledhim.
Në probleme të tjera formula lidhëse midis dy elementeve të njëpasnjëshme të një vargu numrash mund të jetë më e ndërlikuar dhe fundi i hapave të ciklit të lidhet me një kusht të caktuar. Një shembull për këtë jepet në paragrafin në vazhdim (paragrafi 5.3)
Në këtë problemë ekziston një lidhje e emëruesit të një elementi me emëruesin e elementit paraardhës: emëruesi = emëruesi i elementit paraardhës + 1 (ndërkohë numëruesi është gjithmonë 1) Përsëri do të kemi një cikël ku elementi në ҫdo hap krijohet nga një formulë, por cikli në këtë rast mbaron kur plotësohet kushti që elementi i radhës <= 1/1000.
___
>
1. Të shkruhet pseudokodi dhe bllokskema që llogarit shumën e 100 numrave të parë ҫift. 2. Të shkruhet pseudokodi dhe bllokskema që llogarit shumën numrave të parë ҫift, përderisa numrat të jenë më të vegjël se 100.
Programi më i thjeshtë në C++ afishon një mesazh në ekran dhe është programi që i përkon bllokskemës fare të thjeshtë të figurës së mëposhtme (fig.6.1).
Të krijohet një program, i tillë që, gjatë ekzekutimit, të afishojë në ekran shprehjen “Programi im i parë në C++”.
//program im i parë në C++ #include <iostream> using namespace std; int main () { cout<<"Programi im i parë në C++\n"; return 0; }
Programi im i parë në C++
Para se të analizojmë programin e mësipërm, duhet të kemi të qartë hapat që kalohen nga momenti kur e shkruajmë programin në një gjuhë të nivelit të lartë, e cila në rastin tonë është gjuha C++, deri në çastin kur ai ekzekutohet në kompjuter dhe jep rezultatin në pajisjet e tij dalëse. Një program kalon nëpër këta hapa: Hapi I: shkruhet programi-burim në një editor si një sekuencë statementesh dhe regjistrohet me një prapashtesë e cila njihet nga kompilatori që kemi, p.sh.: cpp ose .cc. Ky është skedari (file) i kodit-burim. Në këtë mënyrë do ta shkruanim programin e figurës së mësipërme (fig.6.1). Hapi II: shpesh një program-burim përmban të ashtuquajturat direktiva, të cilat janë pikërisht ato që paraprihen nga simboli . Rreshta të tillë përfaqësojnë pjesë kodi që, për lehtësi, ofrohen nga C++, duke shkruar nga ana jonë një rresht të vetëm. Në rastin e kodit-burim në figurën më lart një direktivë paraqitet nga rreshti: #include <iostream> Hapi III: ekzekutohet kompilatori (përkthyesi) për të konvertuar programin makinë në instruksione makine. Një statement zbërthehet në disa instruksione në gjuhën makinë. Kompilatori gjithashtu na vë në dukje gabimet që mund të bëjmë gjatë shkrimit të programit, gabime që nuk i respektojnë rregullat e shkrimit të një programi në C++. I korrigjojmë këto gabime dhe përsëri e përkthejmë programin me ndihmën e kompilatorit. Hapi IV: ekzekutohet programi linker për të lidhur së bashku pjesë të ndryshme të një programi, siҫ është kodi i mësiperm i shkruar nga ne, po ashtu edhe kodi që përfaqëson rreshti #include <iostream> duke prodhuar kështu një skedar të ekzekutueshëm. Hapi dytë dhe hapi i katërt shpesh realizohen me një komandë të vetme ose me një klikim butoni, kjo është gjithmonë në varësi të mjedisit të punës ku zhvillojmë një program. Gabimet që mund të dallohen në një hap të çfarëdoshëm, do ta pengonin ekzekutimin e hapave pasues. Diagrami në figurën e mëposhtme (fig.6.2) paraqet pikërisht këtë radhë hapash, që janë të nevojshme të ndiqen për analizimin e një programi.
Krijoni një mjedis pune për shkruar një program në C++. Mund të përdoren mjedise të ndryshme pune si: Code Block, Visual C++, NetBeans etj. Të gjitha këto mjedise pune na japin mundësi të shkruajmë në program dhe me një buton të përkthejmë (kompilatori), të lidhim (linkeri) dhe ta ekzekutojmë programin tonë. Kjo punë duhet të bëhet në bashkëpunim me mësuesin.
Në kreun 6 pamë se si paraqitet programi i parë në gjuhën C++, tani, duke u mbështetur te figura 6.1 (faqe 36), e analizojmë atë rresht për rresht.
//programi im i parë në C++ #include <iostream> using namespace std; int main () { cout<<"Programi im i parë në C++\n";
return 0; }
int main () Ky rresht i përkon fillimit të funksionit main(), i cili përfshin zakonisht një pjesë kodi që realizon diçka. Funksioni main() ka një sintaksë të përcaktuar dhe është pika e programit ku fillon ekzekutimi i tij, pavarësisht se ku ndodhet ai (funksioni) në kodin-burim. Pra, ky funksion është i domosdoshëm në çdo program të C. Formati i plotë i funksionit main() është: int main(){ return 0; } Fjala main ndiqet nga çifti i kllapave (()), i cili e dallon një funksion nga shprehje të tjera. Këto kllapa mund të përfshijnë një listë elementesh të quajtura “parametra brenda tyre”.
Mbas këtyre kllapave gjejmë trupin e funksionit të përfshirë në kllapat ({}). Ajo çka ndodhet në këto kllapa, është lloji i funksionit që jep ai kur ekzekutohet. cout<<"Programi im i parë në C++\n"; Ky rresht është një statement C++. Një statement është shprehje e thjeshtë ose e përbërë që ka një efekt. Në të vërtetë, ky statement realizon të vetmin veprim që është afishimi i mesazhit "Programi im i parë në C++\" në ekran, ndërsa "\n" siguron kalimin e kursorit në rreshtin i cili vijon në ekran, poshtë mesazhit që shfaqet në të. Kjo gjë sigurohet edhe në një mënyrë tjetër. Provoni statementin: cout<<"Programi im i parë në C++"<<endl; endl siguron të njëjtën gjë, pra, kalimin e kursorit në rreshtin që vijon. cout është formati që lejon afishimin në ekran të një vargu karakteresh (në këtë rast vargu i karaktereve Programi im i parë në C++). Përdorimi i cout bëhet i mundur duke shtuar në krye të kodit rreshtat: #include <iostream> using namespace std; Theksojmë se statementi mbaron gjithmonë me një pikëpresje (;). Ky karakter përdoret për të shënuar fundin e statementit në një program C++ (ndër gabimet sintaksore më të zakonshme që bëhen, është harrimi i pikëpresjes në fund të një statementi). return 0; këtu kemi kthimin e numrit 0 nga funksioni main(). Ajo që kthehet nga ky funksion, merret parasysh nga sistemi operativ, Windows; në këtë rast vlera zero tregon një mbarim normal të programit për këtë sistem. Programi strukturohet në rreshta të ndryshëm, që të jetë më i lexueshëm. Por mund të shkruhet dhe në një rresht. Kështu, kodi-burim i figurës së mëparshme (fig.7.1) është njëlloj siç paraqitet në figurën vijuese: //programi im i parë në C++ #include <iostream> using namespace std; int main (){ cout<<"Programi im i parë në C++\n"; return 0;}
1. Duke përdorur cout, shkruani një program në C++, i cili e printon emrin tuaj në një rresht; adresën tuaj në një rresht të dytë; qytetin, shtetin në një rresht të tretë. Ekzekutojeni programin.
2. (a) Tregoni sa statemente cout duhet të përdorni, për të afishuar tabelën vijuese:
(b) Cili është minimumi i numrit të statementeve cout që do të përdoreshin për të printuar tabelën në ushtrimin 2.a.? (c) Shkruani një program të plotë C++ për të nxjerrë daljen e ushtrimit 2.a. (d) Ekzekutojeni programin.
3. (a) A do të ecë programi? #include <iostream> using namespace std; int main(){cout<< "përshëndetje të gjithëve!"; return 0}
(b) Pse ky program nuk është program i mirë?
4. Rishkruajeni kodin e programit të mëposhtëm, duke respektuar një paraqitje të tij komode. (a) #include <iostream> using namespace std; int main( ){ cout << "Disa teste" ; return 0}
(b) #include <iostream> using namespace std; int main ( ){cout << "Durrësi është qytet"\n;cout << "në bregdet\n" ;cout << "pranë Tiranës\n" ; return 0;}
5. Gjeni gabimet në kodet e mëposhtme: (a) //programi im i parë në C++ #include <iostream> using namespace std; int main (){ cout<<"Programi im i parë në C++\n" return 0; }
(b) //programi im i parë në C++ #include <iostream> using namespace std; int main (){ cout<<"Programi im i parë në C++";<<endl; return 0; }
Në figurën 3.1 (Kreu 3, faqe 22) paraqitet një shembull i llogaritjes së sipërfaqes së një mjedisi në formë drejtkëndëshi. E rimarrim këtë shembull, por këtë herë vlerat e përmasave i japim me numra të plotë, siç i tregon edhe figura në vijim (fig.8.1).
Për ta paraqitur bllokskemën e mësipërme në një kod-burim të një programi në C++ na duhet të mësohemi me konceptet e variablave, si dhe me tipat e tyre në C++.
Në shembullin e llogaritjes së sipërfaqes siç paraqitet në figurën e mësipërme (fig.8.1), na duhet një vend në kujtesë, në të cilin të vendosim gjatësinë, si dhe një vend tjetër ku të vendosim gjerësinë. Gjithashtu na duhet edhe një vend tjetër për të vendosur rezultatin e llogaritjes së sipërfaqes. Kjo gjë bëhet e mundur në C++ (po ashtu edhe në gjuhët e tjera të
programimit), duke përdorur të ashtuquajturat variabla, të cilët emërtojnë pikërisht vende në kujtesë. Atëherë procesin e mësipërm do ta paraqisnim si më poshtë: gjerësia = 3 gjatësia = 5 sipërfaqja = gjerësia * gjatësia; Është e qartë se ky është një shembull shumë i thjeshtë, mbasi kemi vetëm dy vlera të plota të vogla, me të cilat mund të kishim vepruar drejtpërdrejt 3 * 5. Por sikur të përfytyrojmë që të kishim miliona numra të tillë dhe shumë veprime matematikore me ta, atëherë do të kishim veprime më të ndërlikuara. Për këtë arsye përcaktojmë një variabël si masë të kujtesës, në mënyrë që të rezervojmë një vlerë të përcaktuar. Çdo variabël kërkon një identifikues, i cili e dallon atë nga të tjerët. Për shembull, në kodin e mësipërm identifikuesit e variablave janë: gjerësia, gjatësia dhe sipërfaqja, por ne mund të përdornim gjithashtu edhe çdo lloj emri tjetër të pranueshëm.1
Një identifikues i pranueshëm është një sekuencë e një ose më shumë shkronjave, shifrave, ose karakterit (_). As hapësira dhe as shenjat e pikësimit nuk mund të jenë pjesë e një identifikuesi. Përveç kësaj, një identifikues nuk mund të fillojë me një shifër. Ai fillon me një shkronjë ose me (_). Në lidhje me identifikuesit duhet të kemi parasysh edhe një rregull tjetër: për ta nuk mund të përdorim fjalët e vetë gjuhës C++, që ne i quajmë “fjalë të rezervuara”. Fjalë të tilla të rezervuara në C++ janë: bool, case, char, class, const, const_cast, continue, default, delete, do, double, dynamic_cast, else, enum, explicit, export, extern, false, float, for, friend, goto, if, inline, int, long, mutable, namespace, new, operator, private, protected, public, register, reinterpret_cast, return, short, signed, sizeof, static, static_cast, struct, switch, template, this, throw, true, try, typedef, typeid, typename, union, unsigned, using, virtual, void, volatile, wchar_t, while 1
Në vijim shtjellohen disa rregulla për emrat e variablave.
VËREJTJE 1: Gjuha C++ është një gjuhë "case sensitive", pra, shkronjat e vogla konsiderohen ndryshe nga shkronjat e mëdha. Kjo do të thotë se një identifikues i shkruar me shkronja të mëdha konsiderohet ndryshe nga një tjetër i shkruar me shkronja të vogla. Kështu, për shembull: variabli Sipërfaqja nuk është i njëjtë më sipërfaqja. Në shembullin e mësipërm të figurës 8.1 kemi tre identifikues të ndryshëm variablash. VËREJTJE 2: Rekomandohet që si identifikues variablash të përdoren fjalë të cilat shprehin domethënien e këtyre variablave, pra, qëllimin për të cilin përdoren ata. Të tillë identifikues u përdorën në shembullin në fjalë: gjerësia, gjatësia, sipërfaqja.
Në shembullin e figurës 8.1 vlerat 3 dhe vlera 5 quhen konstante dhe, po ashtu si variablat, edhe ato zënë një vend në kujtesë. Dallojmë konstante të ndryshme të tipave të ndryshëm. 3 dhe 5 janë konstante numerike, kurse një shprehje e përbërë nga karaktere (shkronja, shifra, karaktere etj.) quhet konstante string. E tillë është për shembull shprehja "Programi im i parë në C++". Nuk duhet harruar se konstantet stringje vendosen në thonjëza dyfishe ( " ) gjatë përdorimit të tyre në një program.
Kur merremi me programimin, ne i vendosim ose, ndryshe, i ruajmë variablat në kujtesën e kompjuterit. Por kompjuteri duhet të dijë çfarë lloj të dhënash do të vendosim atje, mbasi nuk i jepet e njëjta hapësirë kujtese një numri të plotë ose një numri dhjetor, ose një karakteri. Kujtesa e kompjuterit organizohet në bite (byte). Një bit është minimumi i sasisë së kujtesës që mund të menaxhojë C++. Një bit lejon ruajtjen e një sasie të vogël të dhënash: një karakter të vetëm ose një numër të plotë të vogël (në përgjithësi një të plotë midis 0 - 255). Përveç kësaj, kompjuteri mund të përpunojë të dhëna më komplekse që kërkojnë disa bite për t’i ruajtur, të tilla si: numrat e gjatë apo numrat jo të plotë. Në shembullin e figurës 8.1 (Kreu 8, faqe 45) për llogaritjen e sipërfaqes s, ne do të mjaftoheshim me numrat e plotë dhe, në këtë rast, do të duhej që t’i deklaronim ata, para përdorimit të variablave, pra, të përcaktonim tipat e tyre si numra te plotë: int gjerësia; //deklarimi i variablit gjerësia int gjatësia; //deklarimi i variablit gjatësia int sipërfaqja; //deklarimi i variablit sipërfaqja gjerësia = 3; gjatësia = 5; sipërfaqja = gjerësia * gjatësia;
ose int gjerësia, gjatësia, sipërfaqja; //deklarimi i tre variablave gjerësia = 3; gjatësia = 5; sipërfaqja = gjerësia * gjatësia;
Atëherë kodi-burim që i përgjigjet bllokskemës në figurës 8.1 (kreu 8), ku vlerat e variablave jepen si të dhëna brenda programit, do të jetë:
//llogaritja e sipërfaqes
Sipërfaqja: 15
#include <iostream> using namespace std; int main () { int gjerësia, gjatësia, sipërfaqja; gjerësia = 3; gjatësia = 5; sipërfaqja = gjerësia * gjatësia; cout<<"Sipërfaqja:"<< sipërfaqja <<endl; return 0; }
Në qoftë se do të përdornim vlera dhjetore për: gjerësia, gjatësia, sipërfaqja, atëherë do të kishim kodin e mëposhtëm: //llogaritja e sipërfaqes #include <iostream> using namespace std; int main () { double gjerësia, gjatësia, sipërfaqja; gjerësia = 3.4; gjatësia = 5.2;
Sipërfaqja:17.28
sipërfaqja = gjerësia * gjatësia; cout<<"Sipërfaqja:"<<sipërfaqja <<endl; return 0; }
Në vijim është një përmbledhje e tipave të ndryshëm të të dhënave në C++, si dhe intervali i vlerave që mund të përdoret për secilën prej tyre. Këta tipa quhen dhe tipa primitivë:
Të shprehen bllokskemat e mëposhtme me kod në C++:
1.
2.
3.
Në kreun 8 u njohëm me nevojën e përdorimit të variablave dhe të konstanteve. Tani do të shohim se si veprohet me ta. Për këtë qëllim C++ përdor operatorët.
Operatori i dhënies së vlerës i jep një vlerë një variabli. a = 5; Rregulla më e rëndësishme kur japim një vlerë, është të veprohet nga e djathta më të majtë: Operatori i dhënies së vlerës ka vend nga e djathta më të majtë, por asnjëherë në drejtim të kundërt a = b; Ky statement i jep variablit a vlerën që ndodhet në variablin b. Vlera që ndodhej deri tani në a humbet. a merr vlerën e variablit b, por, nëse b ndryshon më vonë, kjo nuk do të sjellë një ndryshim te variabli a. Kështu, për shembull, le të marrim parasysh kodin që vijon. // operatori i dhënies së vlerës #include <iostream> using namespace std; int main ()
a:4 b:7
{ int a, b;
//a:?, b:?
a = 10;
//a:10, b:?
b = 4;
//a:10, b:4
a = b;
//a:4, b:4
b = 7;
//a:4, b:7
cout <<"a:"; cout <<a; cout <<" b:"; cout <<b; return 0; }
Ky kod tregon se vlera që përmbahet në a është 4 dhe ajo që përmbahet në b është 7. Shënojmë se a nuk preket nga modifikimi i fundit i variabëlit b, megjithëse më parë kemi shkruar: a = b (kjo është bërë për arsye të rregullës nga e djathta më të majtë). Shprehja e mëposhtme është gjithashtu e vlefshme në C++: a = b = c = 5; Këtu jepet vlera 5 te të tre variablat: a, b, c.
+, -, *, /, % Pesë veprimet aritmetike që mbështeten nga gjuha C++, janë:
Veprimet aritmetike si: mbledhja, zbritja, shumëzimi, pjesëtimi u përkojnë veprimeve përkatëse aritmetike. I vetmi që mund të mos jetë i njohur për nxënësin është veprimi modulo; operatori i tij jepet me shenjën e përqindjes (%) dhe ka të bëjë me mbetjen e pjesëtimit. Modulo është veprimi që jep mbetjen e pjesëtimit të dy vlerave të plota, pra, ky veprim përdoret vetëm kur veprojmë me dy numrave të plotë. Kështu, për shembull, kemi: a = 11 % 3; Në këtë rast variabli a do të mbajë vlerën 2, mbasi 2 është dhe mbetja e pjesëtimit midis numrit 11 dhe numrit 3.
(+=, -=, *=, /=, %=, >>=, <<=, &=, ^=, |=) Kur duam të modifikojmë vlerën e një variabli duke kryer një veprim në vlerën që kemi ruajtur në këtë variabël, mund të përdorim operatorët e përbërë të dhënies së vlerës:
E njëjta gjë kryhet edhe për gjithë operatorët e tjerë. Për shembull: // operatorët e përbërë të dhënies së vlerës
5
#include <iostream> using namespace std; int main () { int a, b=3; a = b; a += 2; //ekuivalent me a = a+2 cout <<a; return 0; }
Duke i shkurtuar më tepër disa shprehje, operatori i shtesës (++) dhe i zbritjes (--) e rrit ose e zvogëlon vlerën e ruajtur në një variabël me 1. Ata janë të barasvlershëm përkatësisht me +=1 dhe -=1. Kështu, kemi: c++; c+=1; c=c+1;
Të gjitha shprehjet janë të barasvlershme në funksionin e tyre: të tria e rritin vlerën e c me 1. Një karakteristikë e këtij operatori është se mund të përdoret para (++a) ose pas (a++) identifikuesit të variablit (pa hapësirë midis tyre). Megjithëse në shembujt e thjeshtë si: a++ ose ++a të dyja shprehjet kanë të njëjtin kuptim, në shprehje të tjera ato mund të kenë një ndryshim të rëndësishëm: në rastin e (++a) vlera rritet përpara se rezultati i shprehjes të vlerësohet dhe, për këtë arsye, është vlera e rritur që konsiderohet në vlerësimin e një shprehje të jashtme; në rastin e (a++) vlera e rezervuar në a rritet pas vlerësimit, prandaj është vlera e ruajtur fillimisht tek a, që merret parasysh në vlerësimin e një shprehje të jashtme. Vëmë re diferencën:
B=3;
B=3;
A=++B;
A=B++;
//A është 4, B është 4
//A është 3, B është 4
Në shembullin 1, variabli B rritet para se vlera e tij të kopjohet në A, ndërsa në shembullin 2, vlera e tij (B) kopjohet në variablin A dhe pastaj B rritet. Ndërmjet operatorëve aritmetikë ka një përparësi për sa i parket radhës së veprimeve. Kjo radhë shprehet si në tabelën më poshtë:
*
/ +
% -
Në qoftë se nuk kemi kllapa, veprimet e shumëzimit dhe të pjesëtimit bëhen para veprimeve të tjera (mbledhjes dhe zbritjes). Këtë radhë mund ta ndryshojë vetëm vënia e kllapave.
1. Gjeni rezultatin e shprehjes së mëposhtme: 6 + 5 * 4 % 3
2. Përcaktoni vlerën e shprehjeve të plota që jepen më poshtë. (a) 2*3/12*8/4 (b) 10*(1+7*3 (c) 20-2/6+3 (d) 20-2/(6+3)
3. Përcaktoni vlerën e shprehjeve të plota në vijim. (a) 2.0*3.0/12.0*8.0/4.0 (b) 10.0*(1.0+7.0*3.0) (c) 20.0-2.0/6.0+3.0 (d) 20.0-2.0/(6.0+3.0)
4. Vlerësoni çdo rezultat të shprehjeve të mëposhtme dhe tregoni tipin e të dhënave të rezultatit. Në vlerësimin e shprehjeve merrni parasysh tipat e vlerësimeve të ndërmjetme. (a) 10.0 + 15% 2 + 4.3 (b) 3.0*4/6+6 (c) 3*4.0/6+6
5. Përcaktoni rezultatin e programit që vijon: #include <iostream> using namespace std; int main() { cout <<"mbetja e pjesëtimit të 9 pjesëtuar me 4 është: " <<9%4 << "\n mbetja e pjesëtimit te 17 pjesëtuar me 3 është: " << 17%3 <<endl; return 0; }
6. Shkruani një program në C++, i cili të afishojë rezultatet e shprehjeve të mëposhtme: (a) 3.0*5.0 (b) 7.1*8.3-2.2 (c) 3.2/(6.1*5) (d) 15/4 (e) 15$4 (f) 5*3-(6*4) (g) Shkruani një statement deklarativ për variablat që vijojnë:
num1, num2, dhe num3 për të rezervuar numra të plotë. grade1, grade2, grade3 dhe grade4 për të rezervuar numra dhjetorë.
(h) Secilën nga statementet e mëposhtme rishkruajeni si deklarime individuale. int muaji, dita = 30, viti; double orët, norma, koha=15.62;
7. Përcaktoni çfarë shkakton çdo statement në programin e mëposhtëm. #include <iostream> using namespace std; int main() { int num1, num2, total; num1=25; num2=35; total=num1+num2; cout <<"Totali i "<<num1 <<" dhe " <<num2 <<"është" <<total <<endl; return 0; }
8. Përcaktoni çfarë shkakton çdo statement në programin e mëposhtëm. #include <iostream> using namespace std; int main() { int num1, num2; num1=25; num2=35; ++num1; nume2++; cout<<"num1 "<< num1 <<" dhe " << " num2 " <<num2 << endl; return 0; }
(==, !=, >, <, >=, <=) Për të bërë krahasimin midis dy shprehjeve, mund të përdorim operatorët relacionalë dhe operatori i barazisë. Rezultati i një operatori relacional është një vlerë boolean, e cila mund të jetë true ose false, gjithnjë në përputhje me rezultatin e vet boolean. Kështu, mund të duam të krahasojmë dy shprehje, për shembull, për të nxjerrë në pah nëse ato janë të barabarta apo njëra është më e madhe se tjetra. Tabela e mëposhtme paraqet një listë operatorësh relacionalë dhe të barazimit, që mund të përdoren në C++: == != > < >= <=
(7 == 5)
// vlerësohet si false.
(5 > 4)
// vlerësohet si true.
(3 != 2)
// vlerësohet si true.
(6 >= 6)
// vlerësohet si true.
(5 < 5)
// vlerësohet si false.
Natyrisht, në vend që të përdorim vetëm konstantet numerike, mund të përdorim një shprehje të çfarëdoshme, e cila të përfshijë variabla. Hamendësojmë që a=2, b=3, c=6. (a == 5)
// vlerësohet si false, pasi a nuk është i barabartë me 5.
(a*b >= c) // vlerësohet si true, pasi (2*3 >= 6) është true. (b+4 > a*c) // vlerësohet si false, pasi (3+4 > 2*6) është false. ((b=2) == a) // vlerësohet si true.
KUJDES! Operatori = (një shenjë =) nuk është i njëjti me operatorin == (dy shenja barazimi). (=) është operatori i dhënies së vlerës (jepet vlera nga e djathta më të majtë); (==) është operatori i barazisë, i cili bën krahasimin nëse dy shprehjet në dyja anët e tij janë të barabarta. Në këtë mënyrë, në shprehjen ((b=2) == a), së pari i japim vlerën 2 variablit b dhe pastaj e krahasojmë me a, që gjithashtu e ruan vlerën, kështu që rezultati i veprimit është true. Ndërmjet operatorëve të krahasimit ekziston një përparësi në radhën e veprimeve. Vetëm vendosja e kllapave mund ta ndryshojë këtë radhë. Radha e veprimit të tyre shprehet si në tabelën e mëposhtme:
< > <= >= == !=
Si është vlera e shprehjeve që vijojnë si të plotë dhe si vlerë booleane? a- 3 b- 5+7 c- 3+(3<4) d- (2>1)+(3<2)
(!, &&, ||) Operatori ! është operatori i C++ që realizon veprimin logjik JO dhe ka vetëm një operand boolean të vendosur më të djathtë, dhe ajo që bën, është gjetja e inversit të vlerës së tij, pra, false nëse operandi është true dhe true nëse operandi është false. Kështu, ai kthen vlerën e kundërt booleane të operandit të tij. Le të shohim një shembull. !(5 == 5)
// vlerësohet false, mbasi shprehja më të djathtë(5 == 5) // është true
!(6 <= 4) // vlerësohet true, mbasi (6 <= 4) do te ishte false !true
// vlerësohet false
!false
// vlerësohet true
Operatorët logjikë && dhe || përdoren kur shqyrtohen dy shprehje, për të marrë një rezultat të vetëm relacional. Operatori && përkon me veprimin logjik boolean DHE. Ky veprim është true nëse të dy operandet janë true; është false kur të dy operandet janë false. Operatori || përkon me veprimin logjik boolean OSE. Ky veprim del true nëse të paktën një nga operandet është true; del false kur të dy operandet janë false. Tabela në vijim paraqet rezultatin e operatorëve: && dhe ||, duke shqyrtuar shprehjet: a && b dhe a || b. Operatori &&
Operatori ||
A
B
a && b
a
B
a || b
True
True
true
true
True
True
True
False
false
true
false
True
False
True
false
false
True
True
False
False
false
False
false
false
SHEMBULL ( (5 == 5) && (3 > 6) ) // vlerësohet si false (true && false) ( (5 == 5) || (3 > 6) ) // vlerësohet true ( true || false)
Kur përdoren operatorët logjikë, C++ llogarit nga e majta më të djathtë gjithçka është e nevojshme, për të ardhur në rezultatin e kombinuar relacional, por duke mos e marrë parasysh pjesën që mbetet. Për këtë arsye, në shembullin e mësipërm ((5==5)||(3>6)), C++ do të përllogariste fillimisht nëse 5==5 është true dhe, në rast së kjo qëndronte, nuk do të vazhdonte të kontrollonte më tej, nëse 3>6 është e vërtetë ose jo. Ky veprim njihet si vlerësimi “qark i shkurtër” dhe paraqitet si në tabelën e mëposhtme (tab.1.12).
&& ||
false
false
true
true
Duhet theksuar se është e rëndësishme, kur shprehja në anën e djathtë ka efekte anësore, si ndryshim vlerash: if ((i < 10)&&(++i < n)) { /*...*/ } Kjo shprehje e kushtëzuar rrit i me 1, por vetëm nëse kushti më të majtë të && është i vërtetë, përndryshe shprehja më të djathtë të (++i < n) asnjëherë nuk vlerësohet. Ndërmjet operatorëve të krahasimit ekziston një përparësi në kryerjen e veprimeve. Radha e veprimit të tyre shprehet si në tabelën e mëposhtme. Këtë radhë mund ta ndryshojë vetëm vendosja e kllapave.
!
JO
&&
DHE
||
OSE
Thoni se cila është vlera e shprehjeve të mëposhtme booleane. (a) 1 && 0
(b) 1 !! 0 (c) ! 3 (d) ! 0 (e) 1 && 3
Tregoni se cila është vlera e shprehjeve që vijojnë. (a) 1 ^ 4 (b) 4 & 8 (c) 1 & 3 (d) 1 | 3 (e) 1 ^ 3
Pa e ekzekutuar programin e shkruar më poshtë, thoni se cilat janë rezultatet që afishohen në ekran. #include <iostream> using namespace std; int main() { int x = 3, y = 6, z = 10; cout << "3 * 6 is " << x * y << endl << "6 / 3 is " << y / x << endl << "10 % 3 is " << z % x << endl << "10 / 3 is " << (float) z / x << endl; }
Në kreun e mëparshme (kreu 12) u fol mbi përparësinë e veprimeve të operatorëve të ndryshëm brenda kategorisë së tyre përkatëse. Por, përveç kësaj, mund të kemi edhe shprehje komplekse, ku përfshihen veprime të ndryshme të të gjitha kategorive: veprime aritmetike, veprime krahasimi, veprime logjike. Duke u nisur nga vlera e përparësisë -nga më e madhe në atë më të ulët- për një pjesë të operatorëve do të kishim një renditje të përparësive si në tabelën e mëposhtme.
1
* / %
2
+ -
3
< > <= >=
4
== !=
5
!
6
&&
7
||
8
= *= /= %= += -= >>= <<=
1. Përcaktoni vlerat e shprehjeve të mëposhtme: Për ta realizuar këtë ushtrim, hamendësojmë këto vlera: a = 5, b = 2, c = 4, d = 6, e = 3. (a) a > b (b) a != b (c) d % b == c % b (d) a * c != d * b (e) d * b = c * e
2. Vendosni kllapa që tregojnë radhën e veprimeve në shprehjet e mëposhtme. Për ta realizuar këtë ushtrim, le të hamendësojmë këto vlera: a = 5, b = 2, c = 4 (a) a % b * c && c % b * a (b) a % b * c || c % b * a (c) b % c * a && a % c * b (d) b % c * a || a % c * b
cout Në programet e krerëve të mëparshëm u përdor formati i afishimit në ekran për një rezultat. Për këtë ishin të nevojshëm disa rreshta kodi, dhe veprohej si në vijim. Fillimisht përfshinim në program-direktivën: #include <iostream> të shoqëruar me specifikimin: using namespace std; Pra, #include <iostream> using namespace std; dhe më pas përdornim formatin: cout << variabël/konstante... ku << quhej operator i daljes dhe (cout) përfaqësonte formatin e daljes standarde në ekran në C++. cout << "një shprehje në ekran"; // printon një shprehje në ekran cout << 120; cout << x;
// printon numrin 120 në ekran // printon përmbajtjen e x në ekran
Operatori << shton të dhënat që vijojnë pas tij në një sekuencë karakteresh, e cila e paraprin atë. Në shembujt e mësipërm fillimisht vendosej konstantja string. një shprehje në ekran, më pas shtohej konstantja numerike 120 dhe ende më pas përmbajtja e variablit x në sekuencën e karaktereve që cout bën të mundur të afishohet. Kështu, do ta përfytyrojmë për momentin cout. Shënojmë që fjalia në statementin e parë përfshihet midis thonjëzave dyfishe ("), mbasi është një konstante string karakteresh. Gjithmonë kur duam të përdorim një konstante string karakteresh, duhet ta përfshijmë atë midis thonjëzave të dyfishta në mënyrë që ajo të dallohet nga një emër variabli. Për shembull, më poshtë jepen dy fjali që kanë rezultate shumë të ndryshme. cout << "Përshëndetje"; // printon përshëndetje cout << Përshëndetje; // printon përmbajtjen e variablit Përshëndetje
Operatori i daljes (<<) mund të përdoret më shumë se një herë në një statement të vetëm. cout << "Përshëndetje, " << "ky është " << "një statement C++";
Ky statementi i fundit do të shtypë në ekran mesazhin Përshëndetje, ky është një statement C++. Dobia e përsëritjes së operatorit të daljes (<<) duket kur kombinojmë shtypjen e variablave dhe të konstanteve ose kombinimin e më shumë se dy variablave: cout << "Përshëndetje, unë jam " << mosha << " vjeç dhe adresa ime është " << adresa;
Nëse hamendësojmë që variabli mosha ka vlerën 24 dhe adresa përmban fjalët: rruga “Dëshmorët e Kombit” nr. 20, rezultati i statementit të mësipërm do të ishte si në vijim: Përshëndetje, unë jam 24 vjeç dhe adresa ime është rruga Dëshmorët e Kombit, Nr 20
Duhet theksuar se, pas rezultatit, cout nuk kalon në rresht tjetër, po qe se nuk mendojmë ta bëjmë vetë këtë gjë.
Kështu, statementet e mëposhtme do t’i shfaqin rezultatet e tyre në një rresht, si në vijim: cout << "Ky është një pohim."; cout << " Ky është një pohim tjetër.";
Ky është një pohim. Ky është një pohim tjetër. Për të realizuar kalimin në një rresht tjetër pas shtypit të një mesazhi specifikohet karakteri special i rreshtit të ri \n (\,n) dhe kemi: cout << "Pohimi i parë.\n"; cout << " Pohimi i dytë.\n Pohimi i tretë.";
prej nga marrim këtë rezultat: Pohimi i parë. Pohimi i dytë. Pohimi i tretë. Për kalimin në një rresht të ri mund të përdorim dhe sintaksën endl, e cila quhet “manipulator”. Për shembull: cout << "Pohimi i parë." << endl; cout << "Pohimi i dytë." << endl;
që do të printonte: Pohimi i parë. Pohimi i dytë. Manipulatori endl jep një karakter të kalimit në rresht të ri, në mënyrë të saktë çfarë bën dhe '\n'. Mund të përdoren të dy formatet, pa ndonjë ndryshim në rezultat.
cin Pajisja standarde e hyrjes në kompjuter është tastiera. Përdorimi i hyrjes standarde në C++ realizohet nëpërmjet operatorit të hyrjes (>>), i përdorur së bashku me formatin cin, të cilin, për momentin, e përfytyrojmë si bartës të një sekuence karakteresh. Operatori duhet të ndiqet nga variabli që ruan të dhënat, të cilat futen si një sekuencë karakteresh. Për shembull: int mosha; cin >> mosha;
Statementi i parë deklaron një variabël të tipit int të quajtur mosha; statementi i dytë pret për një hyrje nga cin (tastiera) për ta ruajtur në këtë variabël të plotë. >> trajton hyrjen nga tastiera, kur ne shtypim tastin RETURN. Për këtë arsye, edhe nëse kërkojmë një karakter të vetëm, futja e tij nga cin nuk bëhet pa e shtypur tastin RETURN, pasi të jetë shtypur më parë karakteri. Gjithmonë duhet të kemi parasysh tipin e variablit që po përdorim si mbartës të asaj që futet me cin. Në qoftë se kërkojmë një të plotë, duhet të shtypim një të plotë; po qe se kërkojmë një karakter, duhet të shtypim një karakter; nëse kërkojmë një string karakteresh, duhet të shtypim një string karakteresh. // shembull hyrje/daljesh
Shtypni një vlerë të plotë: 702
#include <iostream> using namespace std;
Vlera e shtypur është 702
int main ()
dhe dyfishi i saj është 1404.
{ int i; cout << "shtypni një vlerë të plotë: "; cin >> i; cout << "Vlera e shtypur është " << i; cout << " dhe dyfishi është " << i*2 << ".\n"; return 0; }
Përdoruesi i programit mund të jetë një nga faktorët që shkakton gabime, qoftë edhe në programin më të thjeshtë që përdor cin (si në programin më sipër). Nëse kërkohet një vlerë e plotë dhe përdoruesi i programit fut një emër (një varg karakteresh), atëherë do të kemi një veprim të gabuar, mbasi nuk jepet ajo çka pritej. Kështu, kur përdoren të dhëna hyrëse të siguruara nga cin, duhet të jemi të sigurt që të futen të dhëna të rregullta.1 Mund të përdoret cin për të kërkuar më shumë se një të dhënë hyrëse nga përdoruesi: cin >> a >> b; gjë që është ekuivalente me cin >> a; cin >> b; Në të dy rastet përdoruesi duhet të japë dy të dhëna: një për variablin a dhe një tjetër për variablin b, të cilat që mund të ndahen me një ndarës: një hapësirë, një karakter tab ose me një karakter që përfton një rresht të ri.
cin Ne mund të përdorim cin për të futur stringje nëpërmjet variablave të tipit string me operatorin (>>) siç do të bënim me variablat e tipave të tjerë themelore. Variabla të tipit string do të ishin variablat që kanë si vlera të tyre stringje. cin >> një string; Megjithatë cin gjatë futjes së të dhënës ndalon së vepruari, sapo gjen një karakter hapësirë. Kështu, në këtë rast do të marrë fjalën e parë të një fjalie. Kjo sjellje mund të jetë ajo që duam, por edhe e kundërta, nuk mund të jetë. Për shembull: nëse duam të marrim një fjali nga përdoruesi, kjo procedurë hyrje nuk është e dobishme. Për të futur një rresht të plotë, mund të përdorim funksionin getline, i cili është më i rekomanduar për të marrë atë çka fut përdoruesi si të dhënë në cin: 1
Në vijim do të shohim se ka mënyra të ndryshme për të zgjidhur situatat e gabimeve që shkaktohen nga shtypja e të dhënave të përdoruesit.
// cin me stringje #include <iostream> #include <string> using namespace std; int main () { string njestr;
Emri juaj? Arjan Bregu Përshëndetje, Bregu.
Arjan
Dega juaj? Informatikë ekonomike
cout << "Emri juaj? "; getline (cin, njestr);
Më pëlqen informatikë ekonomike shumë!
cout << "Përshëndetje " << njestr << ".\n"; cout << "Dega juaj? "; getline (cin, njestr); cout << "Më pëlqen " << njestr << " shumë!\n"; return 0; }
1. Nga pseudokodi i mëposhtëm hartoni bllokskemen dhe kodin e programit në C++.
2. Shkruani kodin e programit në C++, duke u mbështetur në bllokskemën e mëposhtme.
3. Duke marrë në shqyrtim informacionin e mëposhtëm, shkruani kodin e programit në C++, që gjen diferencën dhe herësin e dy numrave, si dhe e afishon rezultatin.
N1: N2: D: V
4. Shkruani kodin e një programi në C++, i cili gjen sipërfaqen e rrethit dhe perimetrin e tij, kur jepet rrezja. Përllogariteni informacionin e mëposhtëm.
5. Realizoni kodin e një programin në C++ të tillë që, kur të ekzekutohet, të ketë këtë dalje: Cili është emri juaj? Sa vjeç jeni?
"Gjergji"
18
Gjergji është 18 vjeç. Ju mund t’i mbaroni studimet kur te jeni 23 vjeç.
Për ta pasur më të qartë se ç’janë strukturat e kontrollit, le të diskutojmë një problemë praktike, që do ta zgjidhim me një program. Do të përcaktohet nëse nxënësi është kalues në bazë të pikëve që ka marrë në provimet e maturës. Për këtë shërbejnë tri lëndë, pikët e të cilave mblidhen. Po qe se shuma e pikëve e kalon 50-n, nxënësi quhet kalues, nëse numri i pikëve është nën 50, nxënësi quhet jokalues. Bllokskema e algoritmit të kësaj probleme do të paraqitej në një nga bllokskemat e mëposhtme:
Nga bllokskemat e figurës së mësipërme, bllokskema 1 jep një përgjigje vetëm për nxënësit kalues, ndërsa bllokskema 2 jep përgjigje për të dy rastet, pra, për nxënës kalues dhe jokalues. Një program zakonisht nuk kufizohet me një sekuencë instruksionesh, që ekzekutohen njëri pas tjetrit. Gjatë ekzekutimit të programit mund të kemi degëzime, siç e tregon qartë edhe figura (fig. 15.1) ose marrje vendimesh. Për këtë arsye C++ siguron strukturat e kontrollit që
shërbejnë për të specifikuar se çfarë duhet bërë nga programi ynë, kur dhe në çfarë rrethanash. Me strukturat e kontrollit ne do të paraqesim një koncept të ri: statementin e përbërë ose bllokun. Një bllok është një grup satementesh që ndahen me pikëpresje (;) si të gjitha statementet e C++, por të grupuara së bashku në kllapa gjarpërushe{ }: { statement1; statement2; statement3; } Një statement mund të jetë i thjeshtë (një instruksion që mbaron me një pikëpresje) ose i përbërë (shumë instruksione të grupuara në një bllok), si statementi i mësipërm. Në rastin kur duam që statementi të jetë i thjeshtë, nuk është e nevojshme ta përfshijmë atë midis kllapave ({}). Por, kur duam që një statement të jetë i përbërë, atëherë duhet ta fusim ndërmjet kllapave ({}), duke formuar një bllok.
if
else
if është një nga strukturat e kontrollit. Nëse përdoret fjala-çelës if për të ekzekutuar një statement ose bllok, ai ekzekutohet vetëm në rast se plotësohet një kusht. Forma më e thjeshtë e kësaj strukture kontrolli është: if (kusht) statement ku kushti është një shprehje logjike, që do të shqyrtohet, pra, një shprehje e cila mund të ketë dy vlera: e vërtetë (true) ose jo e vërtetë (false). Nëse ky kusht është true, atëherë statementi ekzekutohet, por nëse ai kusht është false, statementi nuk merret parasysh (nuk ekzekutohet) dhe programi vazhdon menjëherë pas strukturës së kushtit. Në ato raste kur mund të specifikojmë se çfarë duam të ndodhë nëse nuk plotësohet kushti, atëherë përdorim fjalën-çelës else. Forma e saj (else) së bashku me if është: if (kusht) statement1 else statement2 Një strukture kontrolli do të paraqitej me një bllokskemë si në figurën më poshtë (fig.15.1).
if…else
Në rastin e problemës lidhur me vlerësimin e nxënësve, për bllokskemën 1 (fig.15.1) do të kishim kodin në vijim: // vlerësimi i nxënësve
Fusni pikët e tre testeve
#include <iostream> using namespace std;
15 16
int main ()
17
{ int test1, test2, test3, shuma = 0; cout << "Fusni pikët e tre testeve\n"; cin >> test1 >> test2 >> test3; shuma = test1 + test2 + test3; if(shuma > 50) cout << "nxënësi është kalues\n"; return 0; }
Nxënësi është kalues
Në përgjigje të bllokskemës 2 do të kishim kodin e mëposhtëm: // vlerësimi i nxënësve
Fusni pikët e tre testeve
#include <iostream> using namespace std;
5 10
int main ()
5
{ int test1, test2, test3, shuma = 0;
Nxënësi është jokalues
cout << "Fusni pikët e tre testeve\n"; cin >> test1 >> test2 >> test3; shuma = test1 + test2 + test3; if(shuma > 50) cout << "nxënësi është kalues\n"; else cout << "nxënësi është jokalues\n"; return 0; }
Në rastin kur ka më shumë statemente që kryen kur kushti plotësohet ose jo, atëherë përdoren kllapat gjarpëruese siç paraqiten në kodin e figurës së mëposhtme (fig.15.5). // vlerësimi i nxënësve
Fusni pikët e tre testeve
#include <iostream> using namespace std;
45 30
int main ()
20
{ int test1, test2, test3; int shuma = 0, diferenca = 0;
Nxënësi është kalues, për 5 pikë plotësohen 100
cout << "Fusni pikët e tre testeve\n"; cin >> test1 >> test2 >> test3; shuma = test1 + test2 + test3; if(shuma > 50){ diferenca = 100 - shuma; cout << "nxënësi është kalues,\n"; cout << " për " << diferenca << " pikë plotësohen 100\n"; } else{ diferenca = 51 - shuma; cout << "nxënësi është jokalues\n"; cout << "duhen dhe " << diferenca << " pikë për të kaluar\n"; } return 0; }
Strukturat if + else mund të bashkohen nëse duam të verifikojmë më shumë se dy alternativa. Le të shohim shembullin e mëposhtëm: // vlerësimi i nxënësve
Fusni pikët e tre testeve
#include <iostream> using namespace std;
0 0
int main () {
0
int test1, test2, test3, shuma = 0, diferenca = 0;
Nxënësi mungoi në provim
cout << "Fusni pikët e tre testeve\n"; cin >> test1 >> test2 >> test3; shuma = test1 + test2 + test3; if(shuma > 50) cout << "nxënësi është kalues\n"; else if(shuma > 0 && shuma <= 50) cout << "nxënësi është jokalues\n"; else cout << "nxënësi mungoi në provim\n"; return 0; }
Këtu vëmë re shprehjen logjike (shuma > 0 && shuma <= 50) Kuptimi i së cilës është shuma është > 0 dhe shuma është <= 50, që është një shprehje e kompozuar nga dy shprehje (shuma > 0) krahasimi dhe (shuma <= 50)
1. Tregoni rezultatin e ekzekutimit të programeve të mëposhtme: (a) #include <iostream> using namespace std; int main(){
int i = 3,j = 5; if(i < j){ cout << (i < j) << endl; } return 0; }
(b) #include <iostream> using namespace std; main() { int i=5, j =1; if (i > j){ i = i + 1; cout << "i = " << i << endl; } else{ j = j + 1; cout << "j = " << j << endl; } }
(c) Fusni vlera të ndryshme për variablin “i”. #include <iostream> using namespace std; int main(){ int i = 0;
cout << "fusni një vlerë për i\n"; cin >> i; if(i == 0){ cout << " i == 0. \n"; }else if(i == 1){ cout << " i == 1. \n"; }else if(i == 2){ cout << " i == 2. \n"; }else cout << " i < 0 ose i > 2. \n"; return 0; }
(d) #include <iostream> using namespace std; int main(){ int test = 0; if( test % 2 == 0) { cout << "Numri " << "është çift" <<endl; if ( (test/2) % 2 == 0) { cout << "\n Gjysma e " << test << " është gjithashtu çift\n"; cout << "a s’është kjo interesante?\n"; } } else cout << "Numri " << "është tek" <<endl; return 0; }
2. Bllokskemën që vijon, kthejeni në kod të një programi në C++.
3. Të shkruhet kodi i një programi në C++, i tillë që t’i përgjigjet bllokskemës së mëposhtme.
4. Programin në vijim kthejeni në bllokskemë. #include <iostream> using namespace std; int main () { int a = 100; if( a < 20 ) { cout << "a është më e vogël se 20;" << endl; } else { cout << " a nuk është më e vogël se 2020;" << endl; } cout << "vlera e a është : " << a << endl; return 0; }
5. Vizatoni një bllokskemë që tregon vijimin e trafikut me semafor, duke e shprehur në një mënyrë tjetër algoritmin e mëposhtëm. Algoritmi
STOP PRIT KALO.
6. Programin e mëposhtëm kthejeni në bllokskemë. #include <iostream> using namespace std; int main () { int a = 100; if( a == 10 ) { cout << "Vlera e a është 10" << endl; } else if( a == 20 ) { cout << " Vlera e a është 20" << endl; } else if( a == 30 ) { cout << " Vlera e a është 30" << endl; } else { cout << " Vlera e a nuk përputhet" << endl; } cout << " Vlera e saktë e a është : " << a << endl; return 0; }
Probleme të ndryshme praktike kërkojnë përsëritjen e një serie hapash dhe jo vetëm një herë, por disa herë. Le të marrim një shembull: Do të llogaritim shumën e 10 numrave të parë natyralë: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10. Mbledhja e 10 numrave realizohet duke përsëritur 10 herë shtimin e një numri në një vend në kujtesë. Në çdo hap pasardhës numri rritet me një derisa të arrijmë në numrin 10. Në këtë rast numri i herëve kur bëhen të njëjtat veprime (shtohet numri në vendin e kujtesës, rritet numri me një) përputhet me numrin më të madh, pra, realizohen 10 cikle me të njëjtat veprime. Duhet të kemi parasysh se fillimisht vendi në kujtesë duhet të ketë vlerën 0, mbasi duhet të sigurohemi që vlera fillestare në këtë vend të kujtesës nuk duhet të ketë efekt në rezultatin përfundimtar. Algoritmi i kësaj probleme do të paraqitej me bllokskemën e figurës së mëposhtme (fig.16.1).
Nga këndvështrimi i programit, ciklet kanë si qëllim përsëritjen e një ose disa statementeve një numër herësh, nëse një kusht plotësohet. Në C++ ka disa formate që realizojnë një cikël.
while Formati i këtij cikli është: while (shprehje) statement Funksionaliteti i tij është që të përsërisë statementin përderisa kushti (shprehje) mbetet i vërtetë. Për shembull, ne do të bëjmë një program për të numëruar në mënyrë zbritëse. Para se të shkruajmë kodin le ta paraqesim këtë rast me një bllokskemë e më pas shkruajmë kodin duke përdorur një cikël while:
n
n
// numërim zbritës duke përdorur while
Filloni me numrin > 8
#include <iostream>
8, 7, 6, 5, 4, 3, 2, 1, Nisu!
using namespace std;
int main () { int n; cout << "Filloni me numrin > "; cin >> n; while (n>0) { cout << n << ", "; --n; } cout << "Nisu!\n"; return 0; } while
Kur fillon programi, përdoruesit i kërkohet të fusë një numër fillestar për numërimin zbritës. Atëherë nis cikli; nëse vlera e futur e plotëson kushtin n > 0 (n të jetë më e madhe se zero), blloku që vijon kushtin, do të ekzekutohet dhe do të përsëritet përderisa kushti (n > 0) mbetet i vërtetë. I gjithë procesi i programit të mëparshëm mund të interpretohet në përputhje me skriptin që vijon (i cili fillon në main): (1) Përdoruesi i jep një vlerë n-së (2) Kontrollohet kushti while(n > 0). Në këtë pikë ka dy mundësi:
* kushti është i vërtetë: statementi ekzekutohet (hapi 3) * kushti nuk është i vërtetë: injorohet statementi dhe vazhdohet pas tij (hapi 5) (3) Ekzekutohet statementi:
cout << n << ", "; --n; (afishohet vlera n në ekran dhe zvogëlohet n me 1) (4) Fundi i bllokut. Kthimi automatik në hapin 2
(5) Vazhdon programi menjëherë pas bllokut: afishohet Nisu! dhe programi mbaron.
Kur krijojmë një cikël while, duhet gjithmonë të kemi parasysh se ai duhet të mbarojë në një moment, prandaj duhet të sigurojmë në bllok mënyrën që ta detyrojnë kushtin të bëhet false, përndryshe cikli do të vazhdojë pafundësisht. Në rastin tonë ne kemi veprimin –n, i cili pakëson vlerën e variablit që vlerësohet në kushtin (n) me një –. Kjo gjë do ta bëjë kushtin (n > 0) false pas një numri hapash të ciklit; më konkretisht: kur n bëhet 0, d.m.th. kur cikli while i numërimit zbritës mbaron.
do-while Formati i ciklit do-while është: do statement while (kushti); Funksionaliteti i tij është i njëjtë si cikli while, më përjashtimin e vetëm që kushti në ciklin do-while vlerësohet pas ekzekutimit të statementit në vend të vlerësimit para tij, duke garantuar kështu të paktën një ekzekutim edhe në rastin kur kushti nuk plotësohet asnjëherë. Për shembull, duam të realizojmë një program që kërkon një numër nga ne, dhe ky proces vazhdon përderisa nuk kemi futur numrin zero. Ky është një rast që justifikon përdorimin e një sintakse do ...while të ciklit, gjë që shihet dhe nga bllokskema dhe programi i figurës në vijim (fig.16.4).
n
n!=0?
// kërkimi i një numri
Futni 12345
#include <iostream>
Ju futët numrin: 12345
using namespace std;
Futni një 160277
int main ()
Ju futët numrin: 160277
{
Futni një numër(0-fund): 0
unsigned long n;
një
numër(0-fund):
numër
(0-fund:
Ju futët numrin: 0
do { cout << "Futni një numër(0-fund): "; cin >> n; cout << "Ju futët numrin: " << n << "\n"; } while (n != 0); return 0; } do..while
Cikli do-while zakonisht përdoret kur variablat që përbëjnë kushtin, përcaktohen fillimisht në trupin e ciklit, si në rastin e mëparshëm, ku n e merr vlerën brenda në bllok dhe përcakton fundin e ciklit. Po qe se nuk fusim vlerën 0, shohim që cikli përsëritet më shumë herë.
for Formati i ciklit for është: for (inicializimi; kushti; modifikim) statement; dhe funksioni i tij kryesor është të përsërisë statement derisa kushti të mbetet i vërtetë, si dhe në ciklin while. Por përveç kësaj, cikli for siguron një vend për statemente inicializimi dhe një për statement modifikimi. Kështu, ky cikël është i disenjuar për të realizuar veprime përsëritëse me një numërator, i cili fillon dhe rritet në çdo hap të ciklit (hap). Cikli for punon në këtë mënyrë:
Hapi 1. Inicializimi ekzekutohet: në përgjithësi variablit numërator i jepet një vlerë fillestare. Kjo pjesë ekzekutohet vetëm një herë. Hapi 2. Kontrollohet kushti: nëse kushti është i vërtetë, cikli vazhdon, përndryshe, cikli mbaron dhe statementi kapërcehet (nuk ekzekutohet). Hapi 3. Statementi ekzekutohet: si zakonisht statementi mund të jetë ose një statement i vetëm, ose një bllok statemetesh të përfshira në kllapat { }. Hapi 4. Çfarëdo që të jetë specifikuar në fushën e shtimit, ajo ekzekutohet dhe cikli kthehet prapa në hapin 2. Në vijim paraqitet një shembull i numërimit zbritës, që fillon nga numri 10, duke përdorur ciklin for:
// numërimit zbritës duke përdorur ciklin 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, Nisu! for #include <iostream> using namespace std; int main () { for (int n=10; n>0; n--) { cout << n << ", "; } cout << "Nisu!\n"; return 0; } for
Pjesët e fillimit dhe të shtimit në formatin for (inicializimi, modifikim, kushti) statement... nuk janë të detyrueshme. Ato mund të mbeten bosh, por në çdo rast duhet të vihet shenja e pikëpresjes midis tyre. Kështu, për shembull, mund të shkruajmë: for (;n < 10;), nëse do të donim të mos bënim inicializim dhe modifikim; for (;n < 10;n++), po qe se do të donim të përfshinim një fushë modifikimi, por jo inicializim (ndoshta sepse variabli është inicializuar përpara).
break Duke përdorur statementin break, mund ta ndërpresim ciklin edhe nëse kushti për mbarimin e tij nuk plotësohet. Ky statement mund të përdoret për të ndërprerë një cikël të pafundmë ose për ta ndërprerë forcërisht para mbylljes së tij natyrale. Për shembull, duam ta ndërpresim numërimin zbritës para mbylljes së tij natyrale (fig.16.8).
n=10
n>0?
n=n-1
n==3?
n
// shembull i break në një cikël #include <iostream> using namespace std; int main ()
10, 9, 8, 7, 6, 5, 4, 3, numërimi përfundon!
{ int n; for (n=10; n>0; n--) { cout << n << ", "; if (n==3) { cout << "numërimi përfundon!"; break; } } return 0; } break
continue Statementi continue shkakton kapërcimin e mbetjes së ciklit në hapin vijues, duke shkuar në fund të bllokut të statementeve, duke shkaktuar kapërcimin në hapin e ciklit që vijon. Për shembull, e kapërcejmë numrin 5 në këtë numërim zbritës (fig.16.10).
n=10
n>0?
n==5?
n=n-1
n
n
// shembull i continue në një cikël #include <iostream>
10, 9, 8, 7, 6, 4, 3, 2, 1, Nisu!
using namespace std; int main () { for (int n=10; n>0; n--) { if (n==5) continue; cout << n << ", "; } cout << "Nisu!\n"; return 0; } continue
1. Të ndërtohet një bllokskemë dhe kodi i një programi në C++, i cili kërkon një numër të plotë nga përdoruesi. Ai do të vazhdojë derisa të futet një numër jozero.
2. Bllokskema e mëposhtme, e cila paraqet shumën e 10 numrave të parë natyrale: 1,2,3,4…, të jepet me një kod siç tregohet në figurën 16.1 (faqe 86).
3. Paraqiteni me një bllokskemë këtë pjesë kodi:
. . . while (x < 10) { ++x; if (x % 2 == 0) { continue; } cout << x << "është një numër çift" << endl; } . . .
4. Pseudokodin e mëposhtëm interpretojeni dhe kthejeni në bllokskemë, më pas kthejeni në një kod C++. Hapi 1:
baza 2
Hapi 2:
fuqia 4
Hapi 3:
produkt baza
Hapi 4:
numërator 1
Hapi 5:
Përderisa numërator < fuqia Përsërit Hapi 5 deri Hapi 7
Hapi 6:
produkt produkt * baza
Hapi 7:
numërator numërator +1
Hapi 8:
Afisho produkt
5. Kodin në C++ të bllokskemës së mëposhtme shkruajeni duke përdorur ciklin for…
6. Kodin në C++ të bllokskemës së mëposhtme shkruajeni duke përdorur ciklin for….
7. Vizatoni një algoritëm me një bllokskemë, që gjen shumën e n numrave çift, n të lexohet nga tastiera. Udhëzim: Që një numër të jetë çift, duhet të plotpjesëtohet me 2, pra: (numri / 2 == 0)
8. Përcaktoni bllokskemën dhe kodin në C++ që i përgjigjet algoritmit të mëposhtëm:
9. Nga pseudokodi vizatoni bllokskemën dhe kodin përkatës të pseudokodit të programit që llogarit produktin e 5 numrave të parë natyralë(5!).
produkt numërator
numërator <5 numërator
1
produkt = produkt * numërator numërator > 0 produkt
Përdorimi i funksioneve mundëson strukturimin e programeve tona në një formë modulare, duke bërë të mundur atë çka quhet programimin i strukturuar, i cili na ofrohet në C++. Le të shohim shembullin e një programi në C++, që llogarit shumën e dy numrave të plotë:
//ky program gjen shumën e dy numrave
shuma e a, b: 3
#include <iostream> using namespace std; int main () { int a=1, b=2, rezultat; rezultat = a+b; cout<< "shuma e a, b: " << rezultat << endl; return 0; }
Të njëjtën gjë mund ta realizojmë ndryshe në C++, duke përdorur një funksion, funksionin shuma në shembullin e mëposhtëm.
//ky program gjen shumën e dy numrave //duke përdorur një thirrje funksioni, //shih përcaktimin e funksionit shuma
shuma e a, b: 3
#include <iostream> using namespace std; //përcaktimi i funksionit shuma() int shuma(int a, int b) { int s; s=a+b; return (s); } int main () { int a=1, b=2, rezultat; rezultat= shuma(a,b); cout<< "shuma e a, b: " << rezultat << endl; return 0; }
Një formë tjetër e pranueshme nga C++ për të llogaritur shumën e dy numrave të plotë, do të ishte siç paraqitet në figurën që vijon (fig. 17.3).
//ky program thirrur një //funksion, funksionit
gjen
shih
shumën
deklarimin
e
dy dhe
numrave
përcaktimin
#include <iostream> using namespace std; //deklarimi i funksionit prototip shuma() int shuma(int, int); int main () { int a=1, b=2,rezultat;
duke shuma e a, b: 3 e
rezultat= shuma(a,b); cout<< "shuma e a, b: " << rezultat << endl; return 0; } //përcaktimi i funksionit shuma() int shuma(int a, int b) { int s; s=a+b; return (s); }
Në shembujt e mësipërm realizohet e njëjta gjë, por fillimisht gjithçka realizohet në funksionin main të programit (fig.17.1), ndërsa në dy raste e tjera (fig.17.2 dhe fig.17.3) veprimi që do të kryhet, pra llogaritjen e shumës së dy numrave, realizohet në funksionin shumë. Brenda këtij funksioni kryhet prodhimi i dy numrave dhe rezultati kthehet nga funksioni me statmentin return. Ky funksion thirret në main dhe, meqë ai kthen një vlerë, kjo e fundit vendoset në një statement afishimi, i cili është cout. Siç e shohim nga shembujt e mësipërm, funksioni mund të përcaktohet para se të thirret, si në rastin e dytë, ku është përcaktuar mbi main (fig 17.2) ose vetëm deklarohet para se të thirret dhe përcaktohet poshtë funksionit main (fig 17.3). Pra, një funksion është një grup statementesh, që ekzekutohet kur thirret në një pikë të programit. Formati i një funksioni është si më poshtë. tipi emri( parametër1, parametër2, ...) { statemente } ku:
tipi është specifikuesi i tipit të asaj çka kthen funksioni. Në shembujt e mësipërm është int.
emri është identifikuesi me të cilin thirret një funksion. Në shembujt e mësipërm është shuma.
parametrat (aq sa nevojiten): çdo parametër shoqërohet me tipin e vet, i ndjekur nga një identifikues, si në një deklarim të thjeshtë variabli (për shembull: int x) dhe që vepron në një funksion si një variabël i rregullt lokal.
Nëpërmjet parametrave kalohen vlerat e argumenteve. Pra, termi argument përdoret në thirrjen e funksionit dhe termi parametër në përcaktimin e funksionit. Parametrat ndahen me presje. Kështu, në shembujt e mësipërm kemi argumentet: a dhe b në thirrjen shuma (a, b) të funksionit shuma() në rreshtin cout<< "shuma e a, b: " << rezultat << endl; dhe kemi parametrat o dhe po në përcaktimin e tij: int shuma(int a, int b) { int s; s = a + b; return s; } Pra, kemi një përkim të tillë ndërmjet argumenteve dhe parametrave: shuma (a, b) shuma (int a, int b) Në funksionin main, ne thirrëm funksionin shuma, duke kaluar në të dy vlera: a dhe b, që përkojnë me parametrat int a dhe int b të deklaruar në funksionin shuma. Parametrat mund të shënohen me çfarëdo lloj emrash, ndaj dhe quhen shpesh parametra formalë. Për shembull mund të shkruanim: int shuma(int x, int y) { int s; s = x + y; return s; }
në vend të int shuma(int a, int b) { int s; s = a + b; return s; } Do të ishte e njëjta gjë dhe do të kishim përkimin: shuma (a, b) shuma (int x, int y)
statementet përbëjnë trupin e funksionit. Trupi i funksionit është një bllok statementesh të futur në kllapat { }. Në shembullin e mësipërm ky bllok statementesh është: { int s; s = a + b; return s; } Tani mund ta kuptojmë më mirë strukturën main, të përmendur dhe më parë. Vetë main nuk është gjë tjetër, veçse një funksion që kthen një vlerë int. Duhet të kujtojmë se një program në C++ fillon gjithmonë me ekzekutimin e funksionit main. Në pikën ku funksioni shuma thirret në main, kontrolli kalon nga main në funksionin shuma. Vlerat e dy argumenteve që kalojnë në thirrjen e funksionit si (a dhe b) kopjohen në variablat a dhe b, që kuptohen si variabla lokalë për funksionin shuma. Rreshti cout<< "shuma e a, b: " << rezultat << endl; afishon rezultatin e veprimit.
Shembullin e mësipërm mund ta trajtojmë edhe me një funksion pa parametra, si në vijim.
//ky program gjen shumën e dy numrave //duke përdorur një thirrje funksioni, //shih përcaktimin e funksionit shuma #include <iostream> using namespace std; //percaktimi i funksionit shuma() int shuma() { int a, b, s; cout << "Futni vlerat e a, b \n"; cin >> a >> b; s=a+b; return (s); } int main () { int rezultat; rezultat= shuma(); cout<< "shuma e a, b: " << rezultat << endl; return 0; }
1. Përdorini funksionet e mëposhtme në një program:
Futni vlerat e a, b 1 2 shuma e a, b: 3
(a) Funksion me vlerë kthimi, por pa parametra. int pjesëtim(){ int përgjigje = 35 \ 7; return përgjigje; } (b) Funksion me vlerë kthimi dhe me parametra double mezatarja(double num1, double num2, double num3){ double mes; mes = (num1 + num2 + num3) / 3; return mes; }
2. (a) Me një funksion llogarisni vlerën e një produkti, duke përdorur si parametra sasinë dhe çmimin e tij. (c) Përdorni për të njëjtin qëllim një funksion pa parametra.
Fusha e veprimit të variablave të deklaruar në funksion, ashtu si dhe në një bllok tjetër të brendshëm {}, është vetë ky funksion ose bllok dhe ato nuk mund të përdoren jashtë tyre. Në shembullin e mësipërm (fig 17.4) do të ishte i pamundur përdorimi i variablave a, b në funksionin main, mbasi ata janë variabla lokalë për funksionin shuma dhe nuk ekzistojnë jashtë tij. Fusha e veprimit të variablave lokalë kufizohet brenda bllokut ku ata deklarohen, megjithatë ne kemi mundësinë e deklarimit të variablave globalë: ata janë të aksesueshëm nga çdo pikë e kodit brenda dhe jashtë funksioneve. Që të përdorim një variabël global, duhet ta deklarojmë atë jashtë çdo funksioni ose blloku, siç paraqitet në figurën më poshtë (fig 17.5), në të cilën
jepen disa shembuj për fushën e veprimit të variablave në raste të ndryshme, në varësi të faktit se ku deklarohen ata në një program.
# #include <iostream>
2
using namespace std;
2
int ShtoDhePrinto() { int vlera = 1; // variabël lokal ++vlera; return vlera; } // vlera nuk ekziston me int main() { int rezultat; rezultat = ShtoDhePrinto(); cout << "vlera= " << rezultat << endl; rezultat = ShtoDhePrinto(); cout << "vlera= " << rezultat << endl; return 0; }
#include <iostream>
2
using namespace std;
3
int vlera = 1; // variabel global int ShtoDhePrinto() { ++vlera; return vlera; } // vlera nuk ekziston me
int main() { int rezultat; rezultat = ShtoDhePrinto(); cout << "vlera= " << rezultat << endl; rezultat = ShtoDhePrinto(); cout << "vlera= " << rezultat << endl; return 0; }
Shembullin e figurës 17.4 e bëjmë edhe një herë, duke shtuar një variabël global, që përdoret sa herë llogaritet shuma e dy numrave. Kështu, do të kemi.
//ky program gjen shumën e dy numrave
Futni vlerat e a, b
//duke përdorur një thirrje funksioni,
1
//ky veprim përsëritet 5 herë #include <iostream> using namespace std;
2 shuma e a, b: 3 Futni vlerat e a, b 10
int numërator = 0; //përcaktimi i funksionit shuma() int shuma()
25 shuma e a, b: 35 Futni vlerat e a, b 15
{ int a, b, s;
17 shuma e a, b: 32
cout << "Futni vlerat e a, b \n"; cin >> a >> b; s=a+b;
Futni vlerat e a, b 11 22
numërator++; //shtohet me një numëratori
shuma e a, b: 33 Futni vlerat e a, b
return (s);
32
} int main ()
43
{
shuma e a, b: 75 int rezultat; while(numërator < 5){ rezultat= shuma(); cout<< "shuma e a, b:" << rezultat << endl; } return 0;
}
Në figurën e mësipërme (fig.17.6) shohim përdorimin e variablit global numërator, i cili është deklaruar jashtë çdo funksioni dhe është filluar me vlerën 0. Vëmë re se ky variabël njihet nga të dy funksionet, që janë në këtë program: funksioni main dhe shuma.
Realizoni një program që afishon vlerën e produkteve të një magazine, sipas modelit të shembullit të mësipërm. Përdorni një variabël global, që tregon numrin e produktit të afishuar.
void Siç dhe e pamë më sipër, sintaksa e deklarimit të një funksioni tipi emri( parametër1, parametër2, ...) { statemente } fillon me një tip, i cili është tipi i vetë funksionit (d.m.th tipi i të dhënës që kthehet nga funksioni me statementin return). -Çfarë ndodh kur nuk duam të kthejmë një vlerë?
Së pari, kur mund të paraqitet një rast i tillë, pra, kur duam një funksion i cili të mos na kthejë asnjë vlerë. Një rast i tillë do të ishte kur ne i japim funksionit si detyrë, për shembull, të bëjë afishime. Së dyti, Kur funksioni nuk kthen vlerë, tipi i kthimit për funksionin duhet të jetë void.
// shembull i një funksioni void
Një funksion void!
#include <iostream> using namespace std; void printim_mesazhi () { cout << "Një funksion void!"; } int main () { printim_mesazhi(); return 0; } void
Shembullin e figurës më përpara (fig.17.6) e ribëjmë duke synuar që, për afishimin e rezultatit, të përdorim një tjetër funksion, të cilin po e quajmë afishim.
//ky program gjen shumën e dy numrave
Futni vlerat e a, b
//duke përdorur një thirrje funksioni,
1
//ky veprim përsëritet 5 herë
2 shuma e a, b: 3
#include <iostream>
Futni vlerat e a, b
using namespace std;
10
int numërator = 0; //përcaktimi i funksionit shuma() int shuma()
25 shuma e a, b: 35 Futni vlerat e a, b 15
17
{ int a, b, s;
shuma e a, b: 32 Futni vlerat e a, b
cout << "Futni vlerat e a, b \n";
11
cin >> a >> b;
22 shuma e a, b: 33
s=a+b;
Futni vlerat e a, b
numërator++; //shtohet me një numëratori 32 43 return (s);
shuma e a, b: 75
} void afishim (int r){ cout<< "shuma e a, b: " << r << endl; } int main () { int rezultat; while(numërator < 5){ rezultat= shuma(); afishim(rezultat); } return 0; } void
Në figurën më lart (fig.17.8) afishimi i rezultatit të programit të figurës më përpara (fig.17.6) është vendosur në funksionin afishim me tip kthimi void. void afishim (int r){ cout<< "shuma e a, b: " << r << endl; }
Vëmë re se një funksion me tip kthimi void nuk mund të kombinohet me statementin cout, mbasi një funksion i tillë nuk kthen vlerë; si rrjedhim, ai thjesht thirret si në figurën 17.8. Nuk duhet harruar se formati i thirrjes së një funksioni përfshin emrin e tij dhe parametrat brenda kllapave. Kur nuk kemi parametra, kllapat do të shkruhen, porse në këtë rast, pa parametra brenda tyre. Kështu, për shembull: shuma(a,b) // kodi në Fig.17.3 afishim(); // kodi në Fig.17.8 Kllapat tregojnë që kemi të bëjmë me një thirrje funksioni dhe jo me emrin e një variabli në C++ ose me statemente të tjera.
1. Përdorini funksionet e mëposhtme në një program: (a) Funksion pa vlerë kthimi dhe pa argumente / parametra: void funksion1(){ cout << "Përshëndetje"; } (b) Funksion pa vlerë kthimi, por me argumente / parametra: void funksion2(string emri){ cout << " Përshëndetje, " << emri; }
Rekursiviteti është një mënyrë zgjidhje e një probleme që e kalon atë në një version më të thjeshtë të problemës origjinale, dhe kjo gjë vazhdon në disa hapa. Kur themi version më të
thjeshtë, kuptojmë një vlerë më të vogël parametri deri në një vlerë që sjell edhe fundin e këtij procesi rekursiv. Marrim si shembull llogaritjen e faktorialit të një numri (n!). Formula matematike është: n! = n * (n-1) * (n-2) * (n-3) ... * 1 Më konkretisht, 5! (faktoriali i 5) do të ishte: 5! = 5 * 4 * 3 * 2 * 1 = 120 Shohim se mund të shkruajmë: n! = n * (n – 1)! , duke e shënuar n! me f(n), mund të shkruajmë: f(n) = n * f(n-1) Pra, f(n-1) nuk është gjë tjetër, veçse një version më i thjeshtuar i f(n), nga pikëpamja e vlerës së parametrit të tij. Kjo është dhe esenca e mënyrës rekursive të një probleme. Në vijim jepet kodi i dy mënyrave të ndryshme që mund të përdorim për zgjidhjen e n!. Një mënyrë është ajo që kemi përdorur deri tani për zgjidhjen e një probleme të tillë, të cilën e quajmë iterative; një mënyrë është mënyra rekursive.
// Programi llogarit n!
// Programi llogarit n!
#include <iostream>
#include <iostream>
using namespace std;
using namespace std;
long faktorial(int n)
long faktorial(int n)
{
{ if (n==1)
int k;
return 1;
long rezultat = 1;
else for (k = 2; k <= n; k++) rezultat = rezultat * k; return rezultat;
return n * faktorial(n-1); }
}
int main () int main ()
{
{
int n;
int n; cout << "fusni një vlerë:\n"; cout << "fusni një vlerë\n";
cin >> n;
cin >> n; cout << " n!: " cout << " n!: " << faktorial(n)
<<faktorial(n) <<endl;
<<endl;
return 0; }
return 0; } fusni një vlerë: 5 n!: 120
fusni një vlerë: 5 n!: 120
Vëmë re se në funksionin faktorial (në rastin rekursiv) përfshihet një thirrje e atij vetë, por vetëm nëse argumenti që kalon, është më i madh se 1, përndryshe, funksioni ndalon. Përcaktimi i një alternative ndalimi të vlerës së cout << factorial argumentit është thelbësor për rekusivitetin, (5) përndryshe, do të krijonim një proces pa fund. return 5 * factorial (4) return 4 * factorial (3) return 3 * factorial (2)
Ky funksion ka një kufizim për arsye të tipit të të dhënave të përdorura në disenjimin e tij (long) për më tepër thjeshtësi. Rezultati i marrë nuk do të jetë i vlefshëm për vlerat shumë më të mëdha se 10! ose 15!, në varësi të sistemit ku e përpilojmë atë. Skema e figurës më të majtë (fig.17.10) paraqet një skemë se si realizohet procesi i rekursivitetit.
return 2 * factorial (1)
5! return 1
Më poshtë është dhënë një shembull që kthen një varg numrash në reversin e tij. Për këtë qëllim përdoret një funksion rekursiv në C++, si për shembull vargu: 1 2 3 4 5 6 7 8 9 10 të afishohet në formën: 10 9 8 7 6 5 4 3 2 1 void afishim (int n) { if ( n <= 0 ) return; //kondita mbyllëse cout << n << " "; //afishohet numri n afishim(n-1); //funksioni thërret veten me argument (n-1) return; //kthim nga funksioni } Ky funksion mund të përdoret në kodin e mëposhtëm
//renditet një varg numrash natyralë //në renditje të kundërt #include <iostream> using namespace std; void afishim(int n) { if ( n <= 0 ) return; //kondita mbyllëse cout << n << " "; //afishohet numri n afishim(n-1); //funksioni thërret veten me
10 9 8 7 6 5 4 3 2 1
argument (n-1) return; //kthim nga funksioni } int main() { afishim(10); return 0; }
#include <iostream>
#include <iostream>
using namespace std;
using namespace std;
int shuma(int nr){
int shuma(int nr){
int total = 0;
if (nr==0) return 0;
for ( int i = 1; i <= 50; i++ ) {
else
total = total + i;
return nr + shuma (nr-1);
}
}
return total;
int main()
}
{
int main()
cout << " shuma e 50
{
numrave të parë natyralë\n" cout << " shuma e 50
<< shuma(50) << endl;
numrave natyralë\n" return 0;
<< shuma(50) << endl; } return 0; }
Të zgjidhet në mënyrë rekursive problema e gjetjes së shumës së n numrave të parë natyralë çift.
Deri tani kemi parë raste kur përcaktimi i funksionit bëhet para funksionit main ose para funksionit ku ai thirret, ose funksioni mund të deklarohet si prototip para funksionit ku ai thirret dhe përcaktohet pas funksionit main, duke e lënë këtë të fundit si funksion të parë në kodin-burim. Të dy variantet janë të mundshme. Por duhet të kemi parasysh se një funksion nuk mund të thirret, nëse nuk është përcaktuar ose deklaruar më parë. Më shpesh përdorim mënyrën e dytë, d.m.th. deklarohet prototipi i funksionit para thirrjes së tij dhe poshtë funksionit ku ai thirret, bëhet përcaktimi i tij. Forma e deklarimit të një funksioni është: tipi emri ( tipi_argumentit1, tipi_argumentit2, ...); Ai është i njëjtë me përcaktimin e funksionit, me përjashtim të faktit që nuk e përfshin vetë trupin e funksionit, d.m.th., statementet e funksionit që, në një përcaktim të zakonshëm, përfshihen në kllapat { } dhe, në vend të kësaj pjese, kemi pikëpresjen (;). Nuk është e detyrueshme përfshirja e një emri për çdo parametër që bëhet në përcaktimin e funksionit, në prototip. Për shembull, ne mund të deklarojmë një funksion të cilin po e quajmë “funksion me dy parametra të tipit int” në një nga mënyrat e mëposhtme: int një funksion (int i pari, int i dyti); int një funksion (int, int); Megjithatë vendosja e emrave për çdo argument e bën kodin më të lexueshëm.
1. Të shkruhet një program ku të përdoret një funksion i cili llogarit sipërfaqen e një mjedisi në formë drejtkëndëshi, ku gjerësia dhe gjatësia futen nga tastiera. Funksioni kthen sipërfaqen e llogaritur.
2. Të zhvillohet i njëjti ushtrim si më sipër, por që funksioni nuk kthen gjë, pra tipi i tij është void.
3. Të shkruhet një program që, me një funksion, realizon futjen e çmimeve të produktit, sasinë e tij dhe kthen vlerën e produktit.
4. Të shkruhet një program që realizon disa veprime në lidhje me numrat. Ekzekutimi i programit afishon në main një menu si më poshtë: ********************************************* ** 1. Llogaritje e shumës së dy numrave
**
** 2. Llogaritje e prodhimit të dy numrave
**
** 3. Llogaritja e herësit të dy numrave
**
** Cilin veprim doni të kryeni? ___
**
-Secili nga veprimet të kryhet me një funksion. Përdorni dy variante. -Funksionet e kthejnë rezultatin; funksionet nuk kthejnë gjë.
5. Të shkruhet një program që i printon në mënyrë rekursive numrat nga 0 në n. 6. Të shkruhet një program që gjen totalin e orëve të punës (numër i plotë) dhe totalin e prodhimit të shprehur me një vlerë dhjetore për një numër n punëtorësh, duke përdorur funksione të ndryshme, por me të njëjtin emër totali. -Të gjendet një mesatare e prodhimit për orë.