Ezt hogy lehet lekódolni? Vagy valami trükközéssel, de van általános szabály is. Nézzük a trükközést:

Hasonló dokumentumok
Java programozási nyelv

A C# programozási nyelv alapjai

Webprogramozás szakkör

Vezérlési szerkezetek

6. fejezet: Ciklusok

Bevezetés a programozásba I.

ALGORITMIKUS SZERKEZETEK ELÁGAZÁSOK, CIKLUSOK, FÜGGVÉNYEK

Óbudai Egyetem. C programozási nyelv

5. előadás. Programozás-elmélet. Programozás-elmélet 5. előadás

Nézzük tovább a lexikai egységeket!

Programozás BMEKOKAA146. Dr. Bécsi Tamás 3. előadás

Szelekció. Döntéshozatal

Internet programozása. 3. előadás

Programozási segédlet

AWK programozás, minták, vezérlési szerkezetek

Programozás I. Matematikai lehetőségek Műveletek tömbökkel Egyszerű programozási tételek & gyakorlás V 1.0 OE-NIK,

Bevezetés a programozásba I 4. gyakorlat. PLanG: Szekvenciális fájlkezelés. Szekvenciális fájlkezelés Fájlok használata

Bevezetés a programozásba I 4. gyakorlat. PLanG: Szekvenciális fájlkezelés

Készítette: Nagy Tibor István Felhasznált irodalom: Kotsis Domokos: OOP diasor Zsakó L., Szlávi P.: Mikrológia 19.

Számítástechnika I. BMEKOKAA152 BMEKOKAA119 Infokommunikáció I. BMEKOKAA606. Dr. Bécsi Tamás 3. előadás

AWK programozás, minták, vezérlési szerkezetek

Java II. I A Java programozási nyelv alapelemei

Occam 1. Készítette: Szabó Éva

1. Jelölje meg az összes igaz állítást a következők közül!

Változók. Mennyiség, érték (v. objektum) szimbolikus jelölése, jelentése Tulajdonságai (attribútumai):

PHP. Telepítése: Indítás/újraindítás/leállítás: Beállítások: A PHP nyelv

BASH script programozás II. Vezérlési szerkezetek

Vezérlési szerkezetek

I. ALAPALGORITMUSOK. I. Pszeudokódban beolvas n prim igaz minden i 2,gyök(n) végezd el ha n % i = 0 akkor prim hamis

Szoftvertervezés és -fejlesztés I.

Programozás alapjai gyakorlat. 4. gyakorlat Konstansok, tömbök, stringek

Változók. Mennyiség, érték (v. objektum) szimbolikus jelölése, jelentése Tulajdonságai (attribútumai):

Programozás I. 1. előadás: Algoritmusok alapjai. Sergyán Szabolcs

Java II. I A Java programozási nyelv alapelemei

1. Alapok. #!/bin/bash

HORVÁTH ZSÓFIA 1. Beadandó feladat (HOZSAAI.ELTE) ápr 7. 8-as csoport

Bevezetés a programozásba I.

Adminisztrációs feladatok Strukturált programok A C programnyelv elemei

7. fejezet: Mutatók és tömbök

Programozás. (GKxB_INTM021) Dr. Hatwágner F. Miklós február 18. Széchenyi István Egyetem, Gy r

A programozás alapjai

Gyakorló feladatok Gyakorló feladatok

Informatika terméktervezőknek

A C# PROGRAMOZÁSI NYELV

Szkriptnyelvek. 1. UNIX shell

Programozás alapjai C nyelv 4. gyakorlat. Mit tudunk már? Feltételes operátor (?:) Típus fogalma char, int, float, double

Vezérlési szerkezetek. Szelekció Ciklusok

Apple Swift kurzus 3. gyakorlat

Bevezetés az informatikába

Objektumorientált Programozás III.

2018, Diszkrét matematika

1. Egyszerű (primitív) típusok. 2. Referencia típusok

Mit tudunk már? Programozás alapjai C nyelv 4. gyakorlat. Legnagyobb elem keresése. Feltételes operátor (?:) Legnagyobb elem keresése (3)

A függvény kód szekvenciáját kapcsos zárójelek közt definiáljuk, a { } -ek közti részt a Bash héj kód blokknak (code block) nevezi.

S z á m í t ó g é p e s a l a p i s m e r e t e k

Programozási nyelvek I. 5. előadás (Gregorics Tibor anyagának felhasználásával)

Komputeralgebra Rendszerek

Oktatási segédlet 2014

Kezdő programozók hibái

A fordítóprogramok szerkezete. Kódoptimalizálás. A kódoptimalizálás célja. A szintézis menete valójában. Kódoptimalizálási lépések osztályozása

Kifejezések. Kozsik Tamás. December 11, 2016

Rekurzió. Dr. Iványi Péter

Járműfedélzeti rendszerek II. 2. előadás Dr. Bécsi Tamás

file./script.sh > Bourne-Again shell script text executable << tartalmat néz >>

Algoritmizálás + kódolás C++ nyelven és Pascalban

AWK programozás Bevezetés

Bevezetés a programozásba. 5. Előadás: Tömbök

NEM-DETERMINISZTIKUS PROGRAMOK HELYESSÉGE. Szekvenciális programok kategóriái. Hoare-Dijkstra-Gries módszere

Bevezetés a programozásba I.

OOP I. Egyszerő algoritmusok és leírásuk. Készítette: Dr. Kotsis Domokos

Java programozási nyelv 9. rész Kivételkezelés

Programozás I. Metódusok C#-ban Egyszerű programozási tételek. Sergyán Szabolcs

Programozási nyelvek JAVA EA+GY 1. gyakolat

BATCH Programozás. Tartalomjegyzék

Pásztor Attila. Algoritmizálás és programozás tankönyv az emeltszintű érettségihez

A programozás alapjai előadás. Amiről szólesz: A tárgy címe: A programozás alapjai

C# nyelv alapjai. Krizsán Zoltán 1. Objektumorientált programozás C# alapokon tananyag. Általános Informatikai Tanszék Miskolci Egyetem

Pénzügyi algoritmusok

Programozás II. 2. gyakorlat Áttérés C-ről C++-ra

Maximum kiválasztás tömbben

Python tanfolyam Python bevezető I. rész

Algoritmus fogalma. Mi az algoritmus? HF: Al Khwarizmi. Egy adott probléma megoldásának leírása elemi lépések sorozatával

Műveletek mátrixokkal. Kalkulus. 2018/2019 ősz

C programozás. 1 óra Bevezetés

Bevezetés a programozásba I 3. gyakorlat. PLanG: Programozási tételek. Programozási tételek Algoritmusok

Programkonstrukciók A programkonstrukciók programfüggvényei Levezetési szabályok. 6. előadás. Programozás-elmélet. Programozás-elmélet 6.

3. Osztályok II. Programozás II

sallang avagy Fordítótervezés dióhéjban Sallai Gyula

Matlab alapok. Baran Ágnes. Baran Ágnes Matlab alapok Elágazások, függvények 1 / 15

A kódgenerálás helye a fordítási folyamatban. Kódgenerálás I. (kifejezések és vezérlési szerkezetek) A kódgenerálás feladata. Ebben az előadásban...

Adattípusok, vezérlési szerkezetek. Informatika Szabó Adrienn szeptember 14.

Aritmetikai kifejezések lengyelformára hozása

Forráskód formázási szabályok

Java és web programozás

Bevezetés a Programozásba II 2. előadás. Adattípusok megvalósítása egységbe zárással. Adattípusok megvalósítása egységbe zárással

Szövegek C++ -ban, a string osztály

3 A C programozási nyelv szintaktikai egységei

Bevezetés a programozásba

A JavaScript főbb tulajdonságai

Kezdő programozók hibái Azok a buktatók, amikről ha nem tudsz, napokat töprenghetsz hiába programozás-tanulás közben

Átírás:

A struktogramok és átírásuk C++ kóddá A szekvenciális 1 programok (vagy legalábbis az a részük, amit struktogrammal megadunk) alapvetően 5 félék lehetnek: üres utasítás értékadás szekvencia elágazás ciklus Ezek kombinálásából épül fel még a legbonyolultabb program lényegi algoritmusa is. Ebből az következik, ha ezeket az építőköveket tudjuk értelmezni és ezekből kódolni, akkor közvetetten bármilyen összetett programmal is el tudunk bánni, ugyanazzal a megközelítéssel, technikával, a struktúrája mentén. Lássuk az öt féle programot egyesével! Üres utasítás Ez a legegyszerűbb eset, a struktogramban egy kötőjel (esetleg egy SKIP felirat) felel meg neki, kódolása annyi, hogy nem írunk semmit 2 Felmerülhet a kérdés, hogy hol használunk ilyet. Ebben a dokumentumban, később, az elágazásról szóló részben van példa arra, hogy a struktogram szintjén üres utasítást kelljen írnunk. A kód szintjén pedig gyakran előfordul az ún. kivételkezelés során a catch blokkban. De ez nem ennek a félévnek a témája. Értékadás Egy olyan egyszerű utasítás, amely egy vagy több változónak értéket ad. Struktogramban a legyen egyenlő jel baloldalán felsoroljuk a változókat, a jobb oldalán pedig sorrendhelyesen azokat az értékeket vagy kifejezéseket, amelyeket ezeknek a változóknak értékül adunk. Ezt a struktogramban úgy kell érteni, hogy több változónak egyszerre, egy időben adunk értéket (szimultán értékadás), de a C++ kódban ez a fajta párhuzamosság nem megvalósítható. Ha a változóinknak nincs sok köze egymáshoz, akkor felcseréljük a szimultán értékadást egyszerű értékadások szekvenciájára (a sorrend mindegy): a=a+1; b=b+1; vagy b=b+1; a=a+1; 1 a programsorok, mint utasítások egymás utáni végrehajtásán alapuló modell 2 esetleg, írhatnánk csak úgy magában egy darab pontosvesszőt mivel minden utasítást pontosvessző zár le, így az üreset is.

Ha viszont egy változót bal és jobb oldalon is felsorolunk, akkor baj van:??? Itt ezt úgy értjük, hogy az értékadás végrehajtása után a növekedjen meg eggyel és b értéke legyen a régi értéke+1, azaz (itt, ebben a példában legalábbis) pontosan az, ami a végrehajtás utáni értéke lesz Ezt hogy lehet lekódolni? Vagy valami trükközéssel, de van általános szabály is. Nézzük a trükközést: a=a+1; b=a; Nyilván ez nem valami általános megoldás, erre a feladatra speciel használható. Mivel a-nak is és b-nek is a régi értéke +1 kell, hogy legyen az új értéke, ezért előbb a-t megnöveljük, majd ezt b-nek értékül adjuk. Nagyon vigyázni kell ezzel, ismernünk kell a műveleteket, amiket használunk. Most képzeljük el mert miért ne hogy a hozzáadás műveletünk úgy működik, hogy minden meghívásakor kiír egy üzentet. Amikor én a stukiba két helyre írok összeadást, akkor számítok erre, hogy ez két üzenetet meg fog jelenni, de a mellékelt kódban csak egy fog megjelenni Tehát, ez a fajta módszer gondokat okozhat az ún. mellékhatásos függvények hívása esetén. Viszont a szimultán értékadásnál nincs sorrendiség a felsorolt változók között (hisz eredetileg mind egyszerre kap értéket), tehát a fentit így is át lehet írni C++-kódra: b=a+1; a=a+1; és így máris két összeadás szerepel a kódban, ugyanúgy mint a struktogramban. Az a=a+1; b=a+1; sorrend már nem lenne helyes, hiszen itt b végül a eredeti értékénél kettővel nagyobb lenne. Amúgy két szám, és a rajtuk elvégzett sima mezei összeadás esetében az első megoldás a javasolt átírás, hiszen hatékonyabb (=kevesebb műveletet kell elvégeznie a processzornak gyorsabb a program), mint a második verzió. Általánosabb megoldás, ha kimentünk minden problémás változót egy-egy segédváltozóba, majd ezen segédváltozók értékét használjuk az értékadásokban: int c=a; a=c+1; b=c+1;

Ez a logika van a swap-művelet (azaz a két változó megcserélése) átírása mögött is: int c=a; a=b; b=c; Szekvencia Két vagy több (akár bonyolultabb) utasítás egymás utáni végrehajtását jelenti. Ennek megfelelően a kódja is mindössze annyi, hogy egymás után sorban leírjuk a szekvenciában részt vevő programrészekhez tartozó kódokat Itt persze számít a sorrend, ami a struktogramban felül van, az kerül a kódban is felülre : a=4; b=a+1; Elágazás Ennek többféle fajtája is van. A struktogram szintjén megkülönböztetjük a két- vagy többágú elágazást, a C++ pedig az egyágú, kétágú, többágú és switch/case eseteket. Nézzük elsőnek a kétágú elágazást: if(a>0) b = a; b = -a; A kétágú elágazás struktogramja mindig egy feltétel vizsgálattal indul. A két átlós pöcök közé egy logikai kifejezést kell írni, pl, hogy a változó pozitív-e Ha ez igaz, akkor a bal oldali (igaz-ág) kódja fut le (itt persze egész nagy, összetett program is lehet), ha nem, akkor pedig a jobb (hamis-ág). Kódban az if kulcsszót a feltétel követi kerek zárójelek között, majd kapcsos zárójelek között 3 az igaz-ág kódja, majd egy (különben) kulcsszót követően kapcsos zárójelek között a hamis-ág kódja. 3 Általános C++-os szabály: ha a kapcsos zárójel közti utasításblokk (if, for, while magjában) csak egy utasításból áll, akkor elhagyható a kapcsos zárójel. Illetve a kapcsos zárójelekbe írt programblokkok után (tehát maga a kapcsos zárójel után) nem kell pontosvesszőt írni, annak ellenére sem, hogy amúgy minden utasítást azzal kellene zárni. Ezeket maga a kapcsos zárójel lezárja.

Nézzünk egy ilyen kétágú elágazásos struktogramot: if(a>0) b = a; Ez elég gyakran előforduló helyzet, hogy az egyik ág üres. Ekkor (bár a fenti átírás is működik) használjuk az ilyen csonka kétágú elágazások átírására a C++ egyágú elágazását, azaz az ágat egyszerűen hagyjuk el, ugyanis ha egy C++-os if szerkezetben nem fedünk le minden esetet, akkor a C++-fordító automatikusan hozzágondol egy ilyen üres törzsű ágat. if(a>0) b = a; Persze elvileg a baloldali ág is lehet üres: if(a>0) b = a; Ez bár helyes és működik is, de azért elég ocsmány. Alakítsuk át tagadjuk le a feltételt és cseréljük meg az ágakat, és máris szebb alakú elágazást kapunk. if(a<=0) b = a;

Mi a helyzet akkor, ha nem csak két eset van? Ezeket hívjuk többágú elágazásnak. if(a>0) b = 1; if(a==0) b = 0; if(a<0) b = -1; A struktogramot úgy kell érteni, hogy ha a fent felsorolt feltételek valamelyike igazra értékelődik ki, akkor az ő hozzá tartozó ág fut le. Tehát ha a pozitív, akkor b értéke 1 lesz stb. A kétágú elágazás struktogramjánál nem fordulhatott elő, de itt igen, mi van, ha az ágak átfednek, illetve mi van, ha nem fednek le minden esetet? A struktogramban ha az ágak átfednek (pl. van egy és egy feltételű ág is), akkor amikor a változó értéke pozitív, akkor az átfedő ágak valamelyike fog végrehajtódni. Nem tudjuk melyik, de azt tudjuk, hogy csak az egyik. Ha a programot többször is futtatom, nincs rá garancia, hogy mindig ugyanaz az ág fog lefutni. Ezt hívják nemdeterminisztikus működésnek, a C++ viszont ebben a kérdésben determinisztikusan viselkedik. Ha az ágak nem fednek le mindent, tehát pl. a fenti elágazásból kimaradt volna az eset és ha a épp egyenlő 0-val, akkor a struktogram szerint ilyenkor a program elszáll. C++-ban ez se fordulhat elő, hiszen mint már korábban említettem, a C++ mindig hozzáír az elágazásokhoz egy üres ágat, tehát ha egyik ág se teljesül, akkor ez az üres blokk fog lefutni, a program továbblép, nem fagy be. A C++ elágazásában tehát nincs nemdeterminisztikusság, ezt fejezik ki a többágú szerkezet során használt kulcsszavak is. A fenti kód így működik: Megvizsgálja, a pozitív-e. Ha igen, lefut az első ág, és vége az elágazásnak. Ha nem, megvizsgálja 0-e. Ha igen, lefut a 2. ág és vége az elágazásnak. Ha nem, megvizsgálja a 3. feltételt, és ha az igaznak bizonyul, lefut a 3. ág, különben az odaképzelt üres törzsű ág. Tehát a C++-ban leírási sorrendben értékelődnek ki az ágak és kizárják egymást. Tekintsük ezt a példát: if(a>0) b=1; if(a>=0) b=2; Itt b, ha a pozitív, biztosan 1 lesz. Pedig az ezzel közel ekvivalens struktorgram szerint akár 2 is lehetne. Mindez azért, mert az különben pedig nem történik semmi. feltételvizsgálat van előbb. Ha a nulla, akkor b 2 lesz,

Mi van, ha kihagyjuk az szócskát? A kód akkor is értelmes, de elképzelhető, hogy nem azt csinálja, amit várunk: if(a==0) a=1; if(a==1) a=2; Azt várjuk, hogy ha a értéke 0, akkor legyen 1, ha 1, akkor meg legyen 2. Ehelyett mit kapunk? Ha a értéke 0, akkor bizony 2 lesz. Miért? Mert ez nem egy többágú elágazás, hanem két szimpla elágazás egymás után írva (azaz szekvencia). Megnézzük a értéke 0-e. Ha igen, akkor 1-re állítjuk, és elágazás vége. Jön a következő elágazás, a értéke vajon 1-e. Persze, hogy az, mert most állítottuk arra. OK, akkor legyen 2. versus if(a==0) a = 1; if(a==1) a = 2; if(a==0) a = 1; if(a==1) a = 2; (bár ez se teljesen korrekt az automatikusan hozzáíródó üres ág miatt) Többágú elágazást lehet egymásba ágyazott kétágú elágazásokkal helyettesíteni. if(a==0) b = 1; if(a==1) b=2; if(a==2) b=3; ekvivalens ezzel: if(a==0) b = 1; if(a==1) b=2; if(a==2) b=3; De azért az első csak szebb. De azt fontos látni, hogy az első se teljesen azt a nemdeterminisztikus algoritmust valósítja meg, amit egy többágú elágazós struktogram sugall, hanem pontosan azt, amit a jobb oldalon álló egymásba ágyazott kétágú elágazásokból felépülő algoritmus struktogramja lenne.

Még egy tipp elágazásokra. Ha adott egy többágú elágazás, ami minden esetet lefed, akkor az utolsó ág feltétele végül is elhagyható: if(a>0) b = 1; if(a==0) b = 0; b = -1; Az elágazások utolsó fajtája a switch/case. Ennek nincs struktogrambeli megfelelője, amúgy is ami switch/case-zel megadható, az iffel is, tehát nem túl fontos téma, lehet nélküle is boldog életet élni, de a teljesség igénye miatt megmutatom. A switch/case arra a helyzetre van kitalálva, amikor arra vagyunk kíváncsiak, hogy egy bizonyos változó értéke egy konkrét konstanst vesz-e fel. Ilyen konstrukciót például menük kódolásakor érdemes használni, ahol a felhasználónak például számokat kell beírnia, és attól függően melyik számot írta be történik más és más. Nézzük meg ezt egy iffel: if(menupont == 1) >>egyes szamu funkcio vegrehajtasa<< if(menupont == 2) >>kettes szamu funkcio vegrehajtasa<< cout<< HIBA! Nem letezo menupont <<endl; Ehelyett alkalmazhatjuk ezt: switch(menupont) case 1: >>egyes szamu funkcio vegrehajtasa<< break; case 2: >>kettes szamu funkcio vegrehajtasa<< break; default: cout<< HIBA! Nem letezo menupont <<endl; break;

Kinek a pap, kinek a papné, valakinek ez a forma jobban tetszik. Szerintem nem sok értelme van, hiszen az iffel hasonló méretű erőfeszítéssel lehet kifejezni ugyanazt. Szeretném felhívni a figyelmet a break utasításokra. Ez egy régről örökölt, ún. nemstrukturált elem (az ilyenek használata kerülendő és kiveszőfélben is van). Jelentése az, hogy a legbelső blokkból ahol épp a vezérlés van, lépjünk ki és folytassuk a végrehajtást a blokk után. A blokk az, ami a kapcsos zárójelek között van, tehát a break utasítás hatására történik (ebben a szerkezetben) az, hogy NEM ugrik tovább a következő ágra a vezérlés és hajtódik végre az is, mert hogy a switch/case alapértelmezett működése ez lenne. Egy példa: switch(menupont) case 1: >>egyes szamu funkcio vegrehajtasa<< case 2: >>kettes szamu funkcio vegrehajtasa<< break; default: cout<< HIBA! Nem letezo menupont <<endl; break; Itt, ha a felhasználó az egyes menüpontot választja, akkor végrehajtódik a kettes ág is. A default azért nem, mert a kettes végén break van. Amúgy a default a hagyományos elágazás -ének felel meg. A break mellett még két további nemstrukturált elemet ismerünk, a continue-t és a gotot. Használatuk mellőzendő, mert olvashatatlanná és nehezen követhetővé teszik a kódot. A continue ciklusokban használatos és olyasmit jelent mint a break, azaz szakítsuk meg a blokk (ciklusmag) végrehajtását, de ne a ciklus után folytassuk, hanem lépjünk egy iterációt és futtassuk le újra a ciklusmagot. A program soraihoz lehet ún. címkéket rendelni. A goto paranccsal ilyen címkéhez lehet a vezérlést küldeni. De ennek sűrű használata igen átláthatatlanná és követhetetlenné teszi a kódot, ezért ilyet végképp csak nagyon indokolt esetben használhatunk (azaz soha). Ciklusok Ebből meg 4 féle van: elöltesztelős, hátultesztelős, számlálós és foreach. Foreach ciklus a C++-ban nincs 4. Amúgy az arra való, hogy ha van egy tömbünk 5 és amúgy az indexek nem különösebben érdekelnek, akkor ne az indextartományon menjünk végig, hanem eleve a tömb elemeken. C#, Ada, Java nyelvekben van ilyen szerkezet többek között. Az elöltesztelős (while) ciklus úgy működik, hogy előbb letesztelem az ún. ciklusfeltételt, aztán ha az igaz, végrehajtom a ciklusmagot. Ezután letesztelem a ciklusfeltételt, ha igazat 4 na jó, van, de csak az újabb szabványban amikor én tanultam, még nem volt :P 5 nem csak tömb van ám a világon vannak olyan adatszerkezetek is, amik nem indexelhetők, na ahhoz meg főleg kényelmes ezt használni, mert nem is tudnánk olyan ciklust írni, ami az indextartományán megy végig, ha egyszer nincs olyan neki

ad akkor lefuttatom a ciklusmagot, stb. Ha egyszer hamis lesz a feltétel, akkor a ciklus utáni részre lép a végrehajtás, ha sose lesz hamis, akkor a program sose áll le (végtelen ciklus). Simán előfordulhat az is, hogy a ciklusmag egyszer se fut le, ha már eleve hamis a feltétel. Ez nem feltétlenül baj, sőt általában összhangban van a programozó szándékával. while(a>0) --a; Ez a ciklus voltaképpen 0-ra állítja a-t. Ha a eleve 0, vagy annál kisebb, akkor viszont úgy hagyja ahogy van. A ciklushoz nagyon gyakran tartozik valami inicializáló lépés. Pl. itt van egy tömbbejárás: i=0; while(i<n) ( [ ]) valami(t[i]); ++i; Viszont ez nem a ciklus szerves része, hanem egy szekvenciával a ciklus elé ragasztott (többnyire) értékadás csupán. Hátultesztelős ciklus Az elöltesztelőshöz nagyon hasonló, viszont itt a ciklusfeltételt mindig a ciklusmag futtatása után ellenőrizzük, szóval egyszer biztosan lefut. Adatbekérésekkor szoktuk leginkább használni, de akkor se mindig. ( ) do bekeres(a); while(a<0); Tehát itt a változóba addig kérek be egy számot, amíg a bekért szám negatív. Így lehet mondjuk azt biztosítani, hogy a egy természetes szám legyen. Számlálós ciklus Ezt a ciklusfajtát akkor használjuk, ha előre tudjuk azt, hogy a ciklusmagot hányszor kell lefuttatni. Az előző két esetben mindig valami feltétel került a ciklus fejébe, most pedig egy számlálóval fogunk végigjárni egy intervallumot, és minden egyes intervallumbeli értékre le fog futni egyszer a ciklusmag. A C++ szintjén a for és a while ciklus ekvivalens, mindkettő helyettesíthető a másikkal a megfelelő paraméterezéssel.

for(int i=1;i<=n;++i) a+=i; Tehát itt egy csak a for ciklusban élő segédváltozóval bejárjuk az [1..n] intervallumot, és például megnöveljük a-t a segédváltozó aktuális értékével. A segédváltozó (általában i-vel jelöljük) csak ebben a ciklusban használható, épp ezért ha sok for ciklust írunk egymás után, akkor nyilván az ő i-jeiknek semmi közük nem lesz egymáshoz. Viszont ha egymásba ágyazunk ciklusokat, akkor nyilván a belső ciklus változóját illik máshogy hívni, mint a külső ciklusét. Azonban ez a C++-ban nem kötelező! Ez egy érdekes sajátossága a nyelvnek, a jelenséget elfedésnek (shadowing) hívják és nagyon meglepő következményei lehetnek: for(int i=0;i<3;++i) for(int j=0;j<2;++j) cout<<j<<" "; cout<<endl; Ez a kód 3 sort fog kiírni (mert a külső for ciklus három kört megy), mindannyiszor két számot (mert a belső for ciklus kétszer fut le), 0-t és 1-et, mert ezeket az értékeket veszi fel j minden körben. for(int i=0;i<3;++i) for(int i=0;i<2;++i) cout<<i<<" "; cout<<endl; Most semmi se változott, csak az, hogy j helyet i-nek hívom a belső változót. És ezt szabad vajon? Már deklaráltam egy i nevű változót kívül, ami ugyan csak a külső for cikluson belül él, na de hát a másik for ciklus a külső for cikluson belül van, tehát ez legalább gyanús. Szabad ilyet csinálni, igen. Nem szabad csak úgy újradeklarálni egy változót, de egy beágyazott blokkon belül (pont ilyen a belső for ciklus) igen. Ez jelenti az elfedést, mert így a külső i változóhoz (ami ugyanúgy létezik és semmi köze a belső i-hez) már belül nem férek hozzá. Ha a cout<<endl; sornál ahol a belső for ciklus már nem él, de a külső igen íratnám ki i-t, akkor a külső for szerinti értéke íródna ki, hiszen a belső i-je ott nem is létezik. Tehát ez a megoldás, ha a külső i-re nincs belül szükségünk, csak azt szeretnénk, hogy 3-szor fusson le, akkor végül is teljesen rendben van, bár általában nem tudatosan szoktak ilyet írni. Ezért kicsit sajnálatos, hogy a C++ nem jelez hibát, mert ez tipikusan olyan hibákat tud eredményezni, ami hosszas, eredménytelen hibakeresésbe torkollhat.

Még ennél is sokkal rosszabb ez a megoldás, ami szintén lefordul és lefut: for(int i=0;i<3;++i) for(i=0;i<2;++i) cout<<i<<" "; cout<<endl; Itt az a különbség van a fentivel szemben, hogy a belső for ciklusban nem deklaráltam i-t. Ezért itt nincs elfedés, itt bizony a belső for ciklus ciklusváltozója megegyezik a külsőével. Ez a kód egészen váratlan módon csak annyit fog kiírni: 0 1 Ez azért van így, mert amikor a külső for ciklus elindul, i értéke 0. Majd a belső ezt ismét 0-ra állítja, majd kiírja. Ezért látjuk kiíva, hogy 0. Ez után a belső továbblép, kiírja, hogy 1, i értéke ekkor 1. Majd a belső továbblép, i értéke 2, és a belső kilép, hiszen i már nem kisebb 2-nél. A külső kiírja az endl-t, majd továbblép, de mivel i értéke legutóbb még 2 volt, ezért most 3 lesz. És mivel 3 nem kisebb, mint 3 ezért ezzel be is fejeződött a külső ciklus is. Ha a külső ciklus fejében a 3-as felső határt 4-re írjuk, akkor hasonló okokra visszavezethető módon a program folyamatosan, vég nélkül a 0 1 sort fogja kiírni. Hát persze, amikor véget ér a belső ciklus, akkor i értéke most is 3 lesz. De 3<4, ezért a külső ciklus folytatja működését, a belső ciklus megint 3-ra állítja i-t, és így megy ez a végtelenségig. Tanulság: ha egymásba ágyazunk for ciklusokat, mindegyiknek legyen külön, a for fejében deklarált ciklusváltozója; illetve akármilyen for ciklus esetében a ciklusváltozót a for törzsében ne módosítsuk, mert meglepő dolgok történhetnek, és nagyon nehezen fogjuk tudni megfejteni a furcsaságok okát. A legfontosabb alapelv amikor programozunk, hogy a kód olvasható legyen, logikus legyen, ne tartogasson meglepetéseket. A ciklusváltozó értékét kiolvasni természetesen szabad. A for ciklus első paramétere 6 adja meg a segédváltozót kezdőértékestül, a második azt a feltételt, ameddig a fornak mennie kell, ez nyilván valami olyasmi, hogy i elért egy bizonyos felső határt, a harmadik paraméter pedig i növeléséről gondoskodik. Ez az utasítás mindig a ciklusmag aktuális lefutása után fut le. Persze lehet visszafelé, vagy többesével is lépkedni: for(int i=n;i>=1;--i) a+=i; 6 Igazából az első és a 3. paraméterhez tetszőleges utasítást, a 2-hoz tetszőleges feltételvizsgálatot írhatunk. Csak így szokás. Írhatunk üres utasításokat is: például a for(;i<n;++i) nem inicializálja i-t semmire mert mondjuk korábban megtettük.

Egyéb különbségek for(int i=1;i<=10;i+=2) a+=i; Egyenlőségvizsgálat, relációs jelek, értékadás szintaktikája: Struktogramban: Kódban: a==b //vizsgalat a>b a<b a>=b a<=b a = b //ertekadas Tömbindexelés: Ha a specifikációban és algoritmusban adott egy [ ] indexelésű tömb, azt a C++-ban [ ] indextartományúként fogjuk kezelni. Ezen kívül az is fontos, hogy általában ez az n egy bemenő adat, tehát a tömb mérete a felhasználó akaratától függ. Egyelőre ezt C++-ban nem engedjük, ezért mindig megadunk egy konstans maximum értéket n-re, a tömb a valóságban akkora, mint ez a maximum, de csak az első n darab értékét használjuk. ( [ ]) i=0; while(i<n) valami(t[i]); ++i; ( [ ]) for(int i=0;i<n;++i) valami(t[i]); Nyilván az i<n úgy is írható lenne, hogy i<=n-1. De így rövidebb.

Matematikai dolgok: Struktogramban: Kódban: i=i+1; i+=1; Igazából bármelyik használható, bár árnyalatnyi különbség van köztük: A + két tetszőleges kifejezést ad össze és ezt egy változónak értékül adhatjuk (a változónak nem kell hogy bármi köze legyen a két kifejezéshez), a += egy változót megnöveli egy kifejezés értékével, a ++ egy változót megnövel eggyel. Ha előre írom a ++-t, akkor megnöveli, és maga a ++i kifejezés felveszi i új értékét, ha hátulra, akkor is megnöveli de a kifejezés értéke még i régi értéke marad. Mivel ez utóbbi megvalósítása eggyel több műveletet tartalmaz, mint a prefixes ++-é (hiszen ki kell mentenie i eredeti értékét egy segédváltozóba), ezért általában i++ ++i illik a ++-t a változó elé írni, mert az a megoldás hatékonyabb. Logikai műveletek: Struktogramban: Kódban: a&&b a b Egy feltételvizsgálatban, ha a vizsgálandó feltétel egy logikai változó igazságértéke, akkor fölösleges 7 == true-t vagy == false-t írni, még akkor se, ha a struktogram ezt sugallja, hanem ezt sokkal egyszerűbb szintaktikával is meg lehet oldani:!a while(a) if(!b) c = 1; c = 2; Láthatjuk, ha arra vagyunk kíváncsiak, vajon egy változó igaz-e, akkor csak odaírjuk a nevét, ha a hamisságot szeretnénk vizsgálni, akkor pedig egy felkiáltójellel (tagadás jele) lehet jelölni szándékunkat. 7 de szabadni szabad

Egy komplex példa: int i = 0; while(i<n) for(int j=1;j<=10;++j) [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] if(t[i]<=j) t[i] = 0; if(t[i]>j && t[i]<2*j) t[i] = i+1; (értelmet ne nagyon keressetek ebben a stukiban :D) if(t[i]>2*j) t[i] = j; i += 1; i végig a 0..n-1 vonalon mozog, mivel tömbindex, j viszont a kódban is annyi, amennyi a struktogramban, mert őneki tényleg az értékét használjuk, nem pedig indexelésre, mint i-t. t tömbben számértékek vannak, és amikor az alg. szerint i-t kellett beírni, i+1-et írtam be, ugyanis itt i nem egy index, hanem egy szám (de ez már nagyon elfajult dolog, ilyen nem lesz zh-ban). Az elágazás üres programos ágát elhagytam, hiszen így is-úgy is üres programot (=semmit) fog végrehajtani.