ÓBUDAI EGYETEM
Programozás I-II Kidolgozott példák és példatár
Dávid András ÓE-AREK-8004 Budapest, 2013
Tartalom jegyzék 1.
Kidolgozott példák C++ programozásra ...................................................................................... ..................................................................................... 5
1.1.
Vezérlési szerkezetek és egyszerű adattípusok ............................................... .......................................................................... ........................... 5
1.1.1.
Szekvencia és elágazás ............................................................. ............................................................................................................... .................................................. 5
1.1.2.
Ismétlés, ciklus ............................................................................................................... ........................................................................................................................... ............. 7
1.1.3.
Egy különleges adattípus, a pointer vagy v agy mutató .................................................................... 11
1.2.
Összetett adattípusok ............................................................................................................... .............................................................................................................. 11
1.2.1.
Egydimenziós tömbök, vektorok .............................................................................................. 11
1.2.2.
Gyakorisági tömbök .................................................................................................................. ................................................................................................................. 17
1.2.3.
Karaktertömbök ............................................................................................................. ....................................................................................................................... ........... 18
1.2.4.
Kétdimenziós tömbök, mátrixok .......................................................... .............................................................................................. .................................... 20
1.3.
Függvények, paraméterátadás ................................................................................... ................................................................................................. .............. 24
1.3.1.
Érték szerinti paraméterátadás ..................................................................................... ................................................................................................ ........... 24
1.3.2.
Cím szerinti paraméterátadás .................................................................................................. 25
1.3.3.
Érték szerint pointerváltozó (memória cím) átadás ................................................... ................................................................. .............. 25
1.3.4.
A tömb, mint paraméter: ........................................................... .......................................................................................................... ............................................... 26
1.4.
Önállóan kidolgozandó feladatok C .......................................................................................... ......................................................................................... 33
1.4.1.
Kis programrészletek visszafejtése ....................................................... ........................................................................................... .................................... 33
1.4.2.
Egyszerű programok (egyszerű adattípusok) ........................................................................... 34
1.4.3.
Egydimenziós tömbök (vektorok), karaktertömbök ................................................................. ................................................................ 36
1.4.4.
Gyakorisági tömbök .................................................................................................................. ................................................................................................................. 37
1.4.5.
Kétdimenziós tömbök, mátrixok .......................................................... .............................................................................................. .................................... 38
1.4.6.
Függvények, paraméterátadás ................................................................................... ................................................................................................. .............. 38
2.
Kidolgozott feladatok ASM programozásra .............................................................................. ............................................................................. 41
2.1.
Adatmozgató, aritmetikai és vezérlésátadó utasítások ........................................................... 41
2.2.
Bitműveletek, logikai utasítások ............................................................................................... .............................................................................................. 46
2.3.
Léptető (shift) és forgató (rotate) műveletek m űveletek .......................................................................... 48
2.4.
Input/output műveletek ........................................................................................................... .......................................................................................................... 49
2.5.
Konverziók ..................................................................................................................... ................................................................................................................................ ........... 53
2.6.
Sztringműveletek ...................................................................................................................... ..................................................................................................................... 57
2.7.
Procedúrák, makrók használata ............................................................................................... 58
2.7.1.
Procedúrák ..................................................................... ............................................................................................................................... .......................................................... 58
2.7.2.
Makrók ............................................................................................................. ..................................................................................................................................... ......................... 62
2.8.
Gépi kódos példák .................................................................................................................... 63
2.9.
Önállóan kidolgozandó feladatok ASM .................................................................................... 71
2.9.1.
Címzési módok, aritmetikai utasítások, ciklusok ............................................. ...................................................................... ......................... 71
2.9.2.
Klaviatúra - képernyő I/O, összehasonlítás, vezérlés átadás .................................................... ................................................... 72
2.9.3.
Bitműveletek - logikai utasítások .............................................................................................. ............................................................................................. 72
2.9.4.
Alprogramok ................................................................... ............................................................................................................................. .......................................................... 74
Bevezetés Nagyon sok programozási nyelv (pl. C#, php) C alapú, ezért ebben a jegyzetben nagy hangsúlyt fektetek arra, hogy C nyelv alapjait minél jobban megismerjék kidolgozott feladatokon keresztül. Bevezetésképpen szeretnék a kedves Olvasónak, programozást tanuló kollégának néhány gondolatot, tanácsot leírni. Az első fontos kérdés, hogy hogyan lehet, szabad, érdemes programozást tanulni. Véleményem szerint „programozást tanulni” nem lehet (csak) könyvből. A legtöbb könyv egy adott programozási nyelv részletes taglalásával, utasításainak ismertetésével foglalkozik. Nem azt állítom, hogy lehetetlen így megtanulni bizonyos dolgokat, fogásokat, de véleményem szerint így „csőlátású” lesz az Illető. Ha „megtanul” C - ben fogásokat, kínkeservvel vált majd Pascalra, vagy bármely más programozási nyelvre. Mivel Önök talán most tanulnak először programozást, szeretném, ha a programozás lényegét megízlelnék, problémacentrikus szemléletmódra tennének szert. Ehhez szeretnék segítséget adni ezzel a kis példatárral . Mivel Önök az Egyetemünkön C alapú és Intel Assembly alapú programozási nyelveket tanulnak, ezért ez a segédlet C++ és I8086 assembly nyelvű kidolgozott feladatokat tartalmaz. A példatár végén találhatók önállóan kidolgozandó példák mindkét programozási nyelvre. A magas szintű nyelvek összetett utasításokkal, az alacsonyszintű nyelvek egyszerű utasításokkal operálnak, így a példatár végén az önállóan kidolgozandó feladatok is programozási nyelv szerint elkülönítve találhatók. Továbbá figyelmükbe ajánlom a Bevezetés az algoritmustanba és programozási tételek című segédletemet, amelyben röviden ismertetem az algoritmustan alapfogalmait, az algoritmus-leíró módszereket, eszközöket, a strukturált programozás alapelveit, illetve a tanulmányaik során gyakran használt programozási tételeket. A jegyzet felépítése példatár szerkezetű, vagyis az elméleti ismeretek rövid közlése után kidolgozott példák, és Önök által önállóan kidolgozandó feladatok találhatók. A C nyelv alapjai nak megismeréséhez Benkő Tiborné, Benkő László, Tóth Bertalan: Programozzunk C nyelven 1 című könyvét, az Intel assembly programozás alapjai nak
megismeréséhez pedig Pethő Ádám: Assembly alapismeretek 2 című könyvét ajánlom a figyelmükbe. A jegyzet végén található irodalomjegyzékben további segédleteket és ajánlott könyveket találnak.
1
Benkő Tiborné, Benkő László, Tóth Bertalan: Programozzunk C nyelven, ComputerBooks, 2003
2
Pethő Ádám: Assembly alapismeretek 1. kötet, Számalk, 1992
1. Kidolgozott példák C++ programozásra 1.1. Vezérlési szerkezet ek és egyszerű adattípusok 1.1.1.
Szekvencia és elágazás
A programkészítés során
törekednünk kell arra, hogy a „strukturált programozás” alapelveit betartsuk. A strukturált programozás 3 vezérlési szerkezetet enged meg: Szekvencia: A programutasítások egymás után (a leírás sorrendjében) hajtódnak végre. Elágazás: Egy vagy több feltételtől függően a program végrehajtása két vagy több ágon folytatódhat az elágazás végéig, és aztán újra egy ágon történik az utasítás végrehajtás. Ismétlés, ciklus: Egy vagy több programutasítást ismételten többször kell végrehajtani. programkészítés során elemi vagy egyszerű, illetve összetett adattípusokkal fogunk dolgozni. Az elemi adattípusok azok az adattípusok, amelyek nem bonthatók kisebb egységekre. Pl. egész, valós, karakter, pointer típus. Az összetett adattípus az az adattípu s, amely több elemi (vagy összetett) adattípusból épül fel. Pl. a tömb olyan összetett adattípus, amely azonos típusú adatokból épül fel. Az összetett adattípus felbontható kisebb egységekre. Az egyszerű adattípusokról részletesen olvashat Benkő Tiborné, Benkő László, Tóth Bertalan: Programozzunk C nyelven című könyvében 3. A
Első lépésként nézzünk olyan feladatokat, ahol elágazást tartalmaz a program. A szekvenciára nem oldunk meg külön feladatot, mivel szekvenciát minden egyes programunk tartalmazni fog. 1.1.1.1.
Készítsen programot, amely meghatározza egy egész számot reciprokát!
A matematikai modell: a reciproka: 1 / a , ahol „a” beolvasott egész szám. Beolvasunk egy számot (pl. a), kiszámol juk és kiírat juk a reciprokát. Ha a beolvasott szám 0, akkor számolhatunk reciprokot ? Nem. Egy elágazás feltétele lesz az a =0. Ha a feltétel hamis, ak kor számolunk reciprokot, ha igaz, akkor kiírunk egy üzenetet (0 -val való osztás nem értelmezett). A C programkódban találhatjuk a következő sort: „ r=1/(float)a”. A programban az „a” változó egész típusú, az „r” változó valós típusú. Az „r=1/a” értékadó ut asítás során a jobb oldal kiértékelődik, és az eredmény az „r” változóban megjelenik. Mivel az „a” egész típusú (az 1 pedig konstans) , ezért a „/” egész osztást jelent. Ha pl. a=2, akkor az eredmény 0 lesz, az „r” változó a 0 értéket veszi fel. Ez hiba természetesen, mert a 2 reciproka 0.5. Az „ r=1/(float)a”
utasítássor esetén típuskényszerítés történik. Az „a” változót valósként kezeli a compiler, vagyis értéke 2.0. Az osztás valós osztás lesz, így az eredmény 0.5 lesz.
3
Benkő Tiborné, Benkő László, Tóth Bertalan: Programozzunk C nyelven 38 -55. oldal 5
Reciprok(a,r) 1. read a 2. if a=0 3. then 4. write „Hibás adat,0 -val való osztás” 5. else
6.
r
Start
Be:
1/a : write r
a
a=0
int _tmain(int argc, _TCHAR* argv[]) {int a; float r; // a szám beolvasása printf("\n a= "); scanf("%d",&a); // reciprok képzés if (a==0) {printf("\n Hibás adat"};} else {r=1/(float)a; printf("\nA %d reciproka %5.4f",a,r);}}
Igaz
Ki:
"Hiba!"
Hamis
r:=1/a
Ki:
r
Stop
1. ábra. Az 1.1.1.1 . feladat folyamatábrával, peszeudokóddal és a programlista
Készítsen programot , amely kiszámítja egy háromszög kerületét és területét a HERON képlet segítségével ! 1.1.1.2.
A matematikai modell: K a b c; s K / 2; T s * ( s a) * ( s b) * ( s c) , ahol az „a”, „ b”, „c” a háromszög három oldala, „ K ” a kerülete, „ T” a területe. Be kell olvasnunk a háromszög oldaladatait (a, b, c), meg kell határoznunk, hogy szerkeszthető-e háromszög. Ha igen, akkor ki kell számolni a kerületét és a területét a matematikai modellben megadott képlet segítségével . A háromszög megszerkeszthető,
ha igaz az a feltétel, hogy bármely két oldal összege nagyobb, mint harmadik oldal. Az előző példában az elágazás feltétele egy egyszerű feltétel volt (a=0). Ebben a példában az elágazás feltétele egy összetett feltétel (a+b>c és a+c>b és b+c>a). A feltételek között „és” kapcsolat van, vagyis akkor igaz az összetett feltétel, ha minden részfeltétel igaz. A tesztelés során próbáljuk ki a programot különböző adatokkal! Pl. ha a=2, b=3, c=5 , akkor nem szerkeszthető háromszög. Önálló feladatként módosítsa a programot úgy, hogy írjon ki egy üzenetet a program, ha a háromszög derékszögű. 6
Start Elágazás Be:
a, b, c
(a+b>c) és (a+c>b) és (b+c>a)
Hamis
Ki:
"Nem szerkeszthetõ háromszög"
Igaz
k:=a+b+c
s:=k/2
t:=gyök((s*(s-a)*(s-b)*(s-c))
Ki:
k, t
Stop
2. ábra. Az 1.1.1.2. feladat folyamatábrája
Háromszög() 1. read a,b,c 2. if (a+b>c) and (a+c>b) and (b+c>a) then 3. 4. k a+b+c 5. s k/2 6. t gyök((s*(s -a) *(s-b)*(s-c)) 7. write k,t else 8. write „Nem szer9. keszthető háromszög”
int _tmain(int argc, _TCHAR* argv[]) {float a, b, c, s, k, t; printf("\nKerem a haromszög harom oldaladatat!"); printf("\na="); scanf("%f",&a); printf("\nb="); scanf("%f",&b); printf("\nc="); scanf("%f",&c); if ((a+b>c)&&(a+c>b)&&(b+c>a)) //igaz, szerkeszthető háromszög { k=a+b+c;s=k/2; t=sqrt(s*(s-a)*(s-b)*(s-c)); printf("\nK=%6.2f,T=%6.2f",k,t); } else printf("\n Nem szerkesztheto haromszog.");}return 0;}
3. ábra. Az 1.1.1.2. feladat
1.1.2.
pszeudokódja és programlistája
Ismétlés, ciklus
A következő néhány feladat a ciklusműveletekre mutat be példákat. Egy gyerek a szüleitől P Ft zsebpénzt kapott. Az első napon 10 Ft - ot költött, majd ezután mi nden n ap 5 Ft - tal többet. Készítsen programot, amely meghatározza, hogy hány napig tudta ezt a költekezést folytatni, és mennyi „töredék” pénze Start maradt? A Zsebpénzt olvassa be, az eredményt írja ki! 1.1.2.1.
Próbáljuk a gyerek helyébe képzelni magunkat. Kapunk „zseb pénz” Ft-t, elköltünk belőle az első napon 10 Ft-ot. A következő nap már 15 Ft -ot fogunk elkölteni. Hány napig tudunk így a büfében étkezni? Addig, amíg a maradék pénzünk több vagy éppen egyenlő a következő nap elköltendő pénzzel. A megoldás egy ismétlődő műveletsor , ciklus lesz. A ciklus elöltesztelő ciklus, mivel először megvizsgáljuk, hogy van -e elegendő pénzünk, ha igen, akkor végrehajtjuk a ciklusmagot.
zsebpenz Be:
zsebpenz koltopenz >=0
ő l e t s z u l s k e i t l c ö l E
s i m a H
Igaz
nap:=nap+1 zsebpenz:= zsebpenzkoltopenz
Költekezés() 1. read zsebpenz 2. nap 0 : koltopenz 10 3. while zsebpenz-koltopenz >= 0 do 4. 5. nap nap+1 : zsebpenz 6. koltopenz koltopenz+5 7. write nap, zsebpenz
koltopenz:=10 nap:=0
koltopenz:= koltopenz+5
zsebpenz-koltopenz Stop
int _tmain(int argc, _TCHAR* argv[]) {int zsebpenz, koltopenz=10, nap=0; printf("\nZsebpenz=");scanf("%i",&zsebpenz); while(zsebpenz-koltopenz>=0) {nap++; zsebpenz=zsebpenz-koltopenz;koltopenz=koltopenz+5;} printf("\n%inapig tud vasarolni,%iFt-ja marad",nap,zsebpenz);} 4. ábra. Az 1.1.2.1. feladat folyamatábrája, pszeudokódja és programlistája
7
Készítsen programot, amely meghatározza két természetes szám legnagyobb közös osztóját az Euklideszi algoritmus segítségével! 1.1.2.2.
Az Euklideszi algoritmus a következő: Megvizsgáljuk, hogy a két szám közül melyik a nagyobb. A nagyobból kivonjuk a kisebbet, ez lesz a Start szám új értéke. A vizsgálatot és a kivonást addig a, b ismételjük, amíg a két szám értéke egyenlő nem lesz. Be: Ekkor a két szám értéke a legnagyobb közös osztó. A megoldás lépései: Be kell olvasnunk két számot (a, b), a nem meg kell határoznunk a legnagyobb közös osztót a fent a egyenlõ b Ki: ismertetett algoritmus segítségével. Ismételt, ciklikus műveletet kell ehhez végeznünk , de nem használhatunk Stop növekményes ciklust (bár a C ++ - ban ezt megtehetnénk), a>b mivel nem tudjuk, hogy hányszor kell az ismétlést végrehajtanunk. A ciklus végrehajtását egy feltétel vezérli (a b), így tesztelő ciklust fogunk használni. A a:=a-b b:=b-a feladat megoldását elől-tesztelő ciklussal mutatjuk be. Hamis
Igaz
Hamis
Igaz
LNKO() 1. read a, b
2. while a b 3. do 4. if a>b then a 5. else b 6. 7. write a
a-b b-a
int _tmain(int argc, _TCHAR* argv[]) { int a,b; printf("a="); scanf("%i",&a); printf("b="); scanf("%i",&b); while(a!=b) { if(a>b) a=a-b; else b=b-a;} printf("\n A legnagyobb kozos oszto= %i",a);}
5. ábra. Az 1.1.2.2. feladat folyamatábrája, pszeudokódja és programlistája
Átlag() 1. összeg 0 : db 0 2. repeat 3. read szám : összeg összeg+szám : db 4. until szám 0 5. átlag összeg/db : write átlag
db+1
ő l e t z s s u l e t k - i l c u t á H
Start
összeg:=0 db:=0
Be:
int _tmain(int argc, _TCHAR* argv[]) { int szam,osszeg=0,db=0; float atlag; do {printf("\nSzám= ");scanf("%i",&szam); osszeg=osszeg+szam; db++; }while(szam!=0); db--; atlag=(float)osszeg/(float)db; 6. ábra. Az 1.1.2.3. feladat
Kérjünk be a billentyűzetről egész számokat 0 végjelig, határozzuk meg az átlagukat!
Számokat kell beolvasnunk 0 végjelig. (a legutolsó szám a 0, ez jelzi az input végét). 8
összeg:= összeg+szám db:=db+1
szám nem 0
Igaz
folyamatábrája, pszeudokódja és programlistája
1.1.2.3.
szám
Hamis
db:=db-1 átlag:=összeg/db
Ki:
átlag
Stop
Ismételt, ciklikus műveletet kell végeznünk , de nem használhatunk növekményes ciklust, mivel nem tudjuk, hogy hányszor kell az ismétlést végrehajtanunk. A ciklus végrehajtását egy feltétel vezérli (szám 0), így tesztelő ciklust fogunk használni. Megoldjuk a feladatot hátul tesztelő ciklussal, az olvasóra bízom, hogy oldja meg elől -tesztelő ciklussal is , ekkor előolvasást is kell végezni. Ez a feladat tipikus „hátul -tesztelős feladat” . Az átlagképzéshez szükség van a beolvasott számok összegére és darabszámára. Készít sen pr ogramot, amely megh atározza a páratlan számok összegét a- tól b-ig! (a és b bármelyike lehet páros illetve páratlan is) 1.1.2.4.
A feladat szerint k ét
érték (a, mint alsó érték és b, mint felső érték ) közötti páratlan számok összegét kell képeznünk. b A matematikai modell:
Be : a, b; Ki :
intervallumhatár.
( páratlan i ) , ahol „a” és „ b” a két i a
kell olvasnunk két számot (a, b), meg kell határoznunk a és b közötti páratlan számok összegét. Célszerűen egy ciklussal (méghozzá növekményes ciklussal) állítjuk elő az összeadandó számokat. Az összegképzést halmozott összegképzéssel, az összegzés tételét felhasználva valósítjuk meg. A program megírásánál kérdés lehet még, hogy mikor páros illetve páratlan egy szám. Páros a szám, ha 2 -vel elosztva az osztási maradéka 0. A C ++-ban az egész számok körében a „ /” az egész osztást, a „ %” (moduló), a maradékos osztást jelenti. A „ %” osztás az osztási maradékot adja eredményül. a, b A C++ nyelvben a for (növekményes) ciklus sok feladatban felhasználható. Szintaktikája: for(inicializáló kifejezés; összeg:=0 feltételes kifejezés; léptető kifejezés). Ezt kihasználva megoldhatjuk úgy is feladatot, hogy biztosítjuk azt, hogy az i:=a-tól b-ig 1-sével „a” változó páratlan értékről induljon, majd a ciklusban kettesével léptetjük az összeadandó számokat. Ekkor a i páratlan ciklusmagban a feltételvizsgálat elmaradhat. Ez lényeges időmegtakarítással jár, hatékonyabb algoritmust kapunk. Be
Start
s e y n é s u l m k i k e c v ö N
Be:
Hamis
Igaz
Páratlanösszeg() 1. read a, b 2. osszeg 0 3. for i a to b 4. do 5. if i páratlan then osszeg 6. write összeg
összeg:=összeg+i
osszeg+i
Ki:
összeg
Stop
int _tmain(int argc, _TCHAR* argv[]) { int a,b,i,osszeg=0; printf("\na=");scanf("%i",&a);printf("\nb=");scanf("%i",&b); for(i=a;i<=b;i++) { if(i%2!=0){ osszeg=osszeg+i; } } printf("\n Az osszeg= %i",osszeg); return 0;} 7. ábra. Az 1.1.2.4. feladat folyamatábrája, pszeudokódja és programlistája
9
Erre a feladatra létezik egy zárt matematikai formula , amely alul látható. Az „a1” a sorozat első tagja, az „an” a sorozat n. tagja, „n” a sorozat tagjainak a száma. „ Sn” a sorozat n tagjának az össze ge. Önálló feladatként készítse el azt a programot, amely kiszámolja az adott formula (a1 an ) * n szerint a számtani sorozat n elemének az összegét. S n
1.1.2.5.
2
Készítsen programot, amely meghatározza egy egész szám számjegyeinek összegét!
A feladat során egy egész típusú számot számjegyeire bontunk, és meghatároz zuk a számjegyeinek az összegét. Ha egy egész számot maradékosan elosztunk 10 -el, akkor megkapjuk az utolsó számjegyét. A megoldás során ciklikusan osztjuk a számot maradékosan 10-el (a maradékot, mint számjegyet hozzáadjuk egy összeg változóhoz), majd a számot elosztjuk egész osztással 10 -el. A ciklus egészen addig fog futni, amíg a szám 0 -vá nem válik. Számjegyösszeg() 1. szjossz 0 2. read szam 3. while szam 0 4. do 5. szjossz szjossz+szam%10 6. szam szam/10 7. write szjossz
int _tmain(int argc, _TCHAR* argv[]) { int szam, szjossz=0; printf("\nSzam= ");scanf("%i",&szam); while(szam!=0) {szjossz=szjossz+szam%10; szam=szam/10;} printf("\nSzamjegyek osszege= %i", szjossz);}
8. ábra. Az 1.1.2.5. feladat pszeudokódja és programlistája
Készítsen programot, amely kiszámítja PI /2 értékét az alábbi végtelen sorozat első n tényezőjének figyelembevételével! PI /2=2/1* 2/3* 4/3* 4/5* 6/5* 6/7* 8/7* 8/9* .... A tényezők számát (n) a felhasználó adja meg! 1.1.2.6.
Matematikai modell: n
Pi / 2 i 2
számláló
nevez ő
páratlan i esetén: számláló számláló 2 egyébként : nevez ő nevez ő 2
A számláló kezdőértéke=2, a nevező kezdőértéke=1. A megoldás során egy növekményes ciklussal dolgozunk, mivel tudjuk, hogy n tényezőt kell majd figyelembe vennünk. Törtek szorzatát kell előállítanunk. A számláló 2 -ről indul, és minden páratlan tagnál 2 -vel kell növelni a számlálót. A nevező 1 -ről indul, és minden páros tagnál kell a nevezőt növelni 2 -vel. Önálló feladatként a lakítsa át úgy az algoritmust, hogy a felhasználó által megadott közelítési pontosságig fusson a program! int _tmain(int argc, _TCHAR* argv[]) { float szamlalo = 2.0, nevezo = 1.0; float pi2=szamlalo/nevezo; int i,n; printf("\ntenyezok szama="); scanf("%i",&n);} for(i=2;i<=n;i++) {if(i%2!=0) {szamlalo=szamlalo+2;} else {nevezo=nevezo+2;} pi2=pi2*(szamlalo/nevezo);} printf("\nPi/2 erteke=%6.2f",pi2);} 9. ábra. Az 1.1.2.6. feladat
10
programlistája
1.1.3. Egy különleges adattípus, a pointer vagy mutató
A C nyelvben kiemelt szereppel rendelkezik egy olyan speciális változó, amely más objektumok címét tárolja. Ez a típus a mutató, vagy pointer. A pointer változónak van típusa, amely megegyezik annak a változónak a típusával, amely nek a címét tartalmazza. Pointerváltozó definiálásakor meg kell határoznunk, hogy milyen típusú adat (objektum) címét fogja tartalmazni (pl. int *p). A pointerváltozónak értéket kell adnunk mielőtt, használjuk, mivel deklarációkor NULL értéket kap (nem mutat sehova). Értéket értékadó utasítással és a címe operátorral (&) tudunk adni (pl. p=&a). A pointerváltozó által mutatott változóra (objektumra) a *pointerváltozó kifejezéssel tudunk hivatkozni (pl. x=*p). A pointerekről bővebb információ a Benkő Tiborné, Benkő László, Tóth Bertalan: Programozzunk C nyelven című könyvben található 4. 1.1.3.1.
Készítsünk egy rövid példát a pointerek bemutatására!
int _tmain(int argc, _TCHAR* argv[]) {int x=7,y=3; int *px,*py; //ket int tipusu pointer valtozo px=&x; py=&y; //a px pointervaltozo az x valtozo cimet, //a py az y valtozo cimet kapja ertekul //(*px)kiirjuk a px pointervaltozo altal mutatott memoriahely printf("\nx valtozo erteke= %i, pointerrel= %i",x,*px); //(*py)kiirjuk a py pointervaltozo altal mutatott memoriahely printf("\ny valtozo erteke= %i, pointerrel= %i",y,*py); printf("\nx valtozo cime= %i",py); *px=*px+x+y; //ertekadas: a px pointer valtozo altal mutatott //tartalma = a px pointer valtozo altal mutatott //tartalma + x + y *py=*py+x+y; printf("\nx valtozo erteke= %i, pointerrel= %i",x,*px); printf("\ny valtozo erteke= %i, pointerrel= %i",y,*py);}
tartalmat tartalmat
memoriahely memoriahely
10. ábra. Az 1.1.3.1. feladat programlistája
1.2.
Összetett adattípusok
1.2.1.
Egydimenziós tömbök , vektorok
A következőkben az egyik leggyakrabban használt összetett adatszerkezet, az egydimenziós tömb (vektor) kezelésére nézünk meg néhány példát. Az egydimenziós tömbök részletes ismertetését megtalálja Benkő Tiborné, Benkő László, Tóth Bertalan: Programozzunk C nyelven című könyvében 5. 1.2.1.1.
Kérjük be egy 10 elemű vektor elemeit , és írjuk ki az értékeket !
Egy tömböt kell beolvasnunk. A tömb olyan összetett adatszerkezet, mely több azonos típusú elemet tartalmaz. Az elemeket csak egyesével tudjuk kezelni, jelen esetben beolvasni, illetve kiírni, vagyis egy ciklussal tudjuk beolvasni a tömb összes elemét. Mivel tudjuk a beolvasandó elemek számát, ezért dolgozhatunk növekményes ciklussal. A ciklusváltozó a tömbindex. 4 5
Benkő Tiborné, Benkő László, Tóth Bertalan: Programozzunk C nyelven 49-55. oldal Benkő Tiborné, Benkő László, Tóth Bertalan: Programozzunk C nyelven 120 -139. oldal 11
Vektor1()
1. for i 0 to hossz[t] do read 2. t[i] 3. for i 0 to hossz[t] 4. do write t[i]
int _tmain(int argc, _TCHAR* argv[]) { int t[10],i; for(i=0;i<10;i++) //Beolvasás {printf("\n%i.elem= ",i); scanf("%i",&t[i]);} for(i=0;i<10;i++) {printf("%i\t",t[i]);}}
11. ábra. Az 1. 2.1.1. feladat programlistája
Olvassunk be egész számokat egy vektorba 0 végjelig, majd írjuk ki az elemeket a képernyőre! 1.2.1.2.
Egy tömböt kell beolvasnunk „0 végjelig”, majd ki kell írnunk a tömbelemeket. A „0 végjelig” való beolvasás azt jelenti, hogy elemeket olvasunk be egészen addig, amíg „ 0”-át nem olvastunk. A „0” jelzi a beolvasás végét. A feladatok megoldása során a „ 0”-át már nem tekintjük érvényes tömbelemnek. Mivel statikus tömbökkel foglalkozunk, egy újabb tömbelem beolvasása előtt vizsgálnunk kell azt is, hogy van -e még hely a tömbben (i
1. i 0 2. repeat 3. read t[i] : i 4. until t[i-1] 0 and 5. if i=hossz[t] then n 6. i else 7. for i 0 to n do
i+1 i
i-1 write t i
int _tmain(int argc, _TCHAR* argv[]) {int t[100], i=0,n; do {printf("%i.elem= ",i); scanf("%i",&t[i]); i++; }while(t[i-1]!=0 && i<100); if(i==100) {n=i;} else {n=i-1;} for(i=0;i
12. ábra. Az 1.2.1.2. feladat pszeudokódja és programlistája
juk meg az előző (1.2.1.2.) feladatot pointerváltozók segítségével! 1.2.1.3. Ol
A C nyelvben a tömb neve egy pointerváltozó, vagyis a tömb neve a tömb memóriabeli kezdőcíme. A megoldás során a tömb nevét, mint pointerváltozót fogjuk felhasználni. A beolvasó és kiíró ciklusban nem indexelni fogjuk a tömböt, hanem a pointervált ozót, mint címet fogjuk inkrementálni (vagy dekrementálni). Ebből is látszik, hogy a pointerváltozónak van típusa. Ha pl . egész típusú tömbünk van, és egy -egy egész típusú elemet 4 bájton tárol a rendszer, akkor a pointerváltozó értékének az inkrementálása automati kusan 4-el való növelést fog jelenteni. int _tmain(int argc, _TCHAR* argv[]) {int t[100],i=0,n=-1; int *tp=t; //a tomb neve egy pointervaltozo, tomb 0. elemenek a cime tp--; do{tp++;n++; //a tombre mutato pointervaltozot inkrementaljuk, //n a beolvasott elemek szama printf("%i.elem= ",n);scanf("%i",tp); }while(*tp!=0 && n<100); //kilepes, ha 0 vegjelet olvastunk be, tp=t; //vagy betelt a tomb for(;*tp!=0;tp++) //kiiras addig, amig a tombelem nem a 0 vegjel {printf("%i\t",(*tp));}} 12
13. ábra. Az 1.2.1.3. feladat programlistája
1.2.1.4. Olvassunk
be egész számokat egy vektorba 0 végjelig, majd oldjuk meg a következő
feladatokat!
meg a tömb elemeinek átlagát! e páros elem a tömb elemei között! b) Döntsük el, hogy van- c) Adjuk meg az első páros elem indexét! d) Adjuk meg a páros elemek darabszámát! e) Adjuk meg a legkisebb és a legnagyobb elemet! a) Adjuk
Ezt a feladatot részenként (külön az a), b) … e)) oldjuk meg. Ezek a feladatok a jól ismert programozási tételekre épülnek . a) feladat: A megoldás során az összegzés tételét alkalmaz zuk. Egy „összeg” változóhoz (melynek a kezdőértéke 0) ciklikusan hozzáadjuk a tömb elemeit. b) feladat: A megoldás során az eldöntés tételét alkalmaz zuk. Nem szükséges a tömb összes elemét megvizsgálnunk (hogy páros -e vagy sem), hiszen, ha megtaláljuk az első páros elemet, akkor már tudunk válaszolni a kérdésre. c) feladat: A megoldás során a lineáris keresés tételét alkalmaz zuk. A b) feladat megoldásához hasonlóan járunk el. A vizsgálóciklusból való kilépéskor, ha találtunk páros elemet a tömbben, akkor ennek az elemnek a tömbindexe adja a megoldást. d) feladat: A megoldás során a megszámolás tételét alkalmaz zuk. Ciklikusan végigvizsgáljuk a tömb elemeit, a páros elemeknél egy változó értékét (pl. db) megnöveljük 1 -el. A db változó kezdőértéke 0. e) feladat: A megoldás során a minimum, illetve a maximum kiválasztás tételét alkalmaz zuk. Kezdetben feltételezzük, hogy a legkisebb illetve a legnagyobb elem értéke egyenlő a tömb 0. elemével („min” és „max” változó). Ciklikusan végigvizsgáljuk a tömb elemeit, és ha az addig feltételezett legkisebb elemnél kisebb, illetve az addig feltételezett legnagyobb elemnél nagyobb elemet találunk, akkor a min illetve a max változóban megjegyezzük a tömbelem értékét. int _tmain(int argc, _TCHAR* argv[]) { int t[100], i = 0, n; do {printf("\n%i.elem= ",i); scanf("%i",&t[i]); i++; }while(t[i-1]!=0 && i<100); if(i==100){n=i;} else {n=i-1;} int osszeg=0; float atlag; //a) feladat, összegzés for(i=0;i
13
//e) feladat, minimum és maximum kiválasztás int min=t[0], max=t[0]; for (i=1;imax) { max=t[i]; } } printf("\nA tomb legkisebb eleme= %i, legnagyobb eleme= %i",min, max); return 0; } 14. ábra. Az 1.2.1.4. feladat programlistája
Töltsön fel egy 10 elemű egész típusú tömböt „véletlenszámokkal”, úgy, hogy ne legyen két azonos értékű elem. Ezután írja ki az elemeket a képernyőre. A „véletlenszámokkal” való feltöltés azt jelenti, hogy a fejlesztői rendszerünk (jelen esetben a C++) un. véletlenszám generátorával választunk számokat, és ezek a számok lesznek a tömb elemei. Ebben a feladatban kikötés, hogy nem lehet két egyforma szám a tömbben. Amikor generálunk egy számot, megnézzük, hogy szerepel -e már a tömbben (lineáris keresés tétele) . Ha nem, akkor betesszük a tömbbe, ha igen, akkor új számot generálunk. Használat előtt a véletlenszám generátort inicializálnunk kell. 1.2.1.5.
int _tmain(int argc, _TCHAR* argv[]) { int t[10],i=0,j,szam; int nincs; srand (time(NULL)); //veletlenszam generator inicializalasa while(i<10) //feltöltés {szam=rand()%10; j=0; //keresés while(t[j]!=szam && j
Készítsen programot, mely egy 10 elemű vektor elemeit 1 hellyel előre mozgatja, és az első elem az utolsó helyre kerül. A feltöltést véletlenszám generátorral oldja meg, majd írja ki az eredeti és az új vektort! 1.2.1.6.
A megoldás során a tömb 0. elemét elmentjük egy segédváltozóba, majd ciklikusan a tömb i-1. elemét felülírjuk az i. elemmel. A ciklus lefutása után a legutolsó elembe betöltjük a segédváltozóba elmentett 0. elemet. int _tmain(int argc, _TCHAR* argv[]) {int t[10]; int i, seg; srand (time(NULL)); //veletlenszam generator inicializalasa for(i=0;i<10;i++) {t[i]=rand()%10;} //feltöltés printf("\nA tomb elemei:"); //kiírás for(i=0;i<10;i++) {printf("\t%i",t[i]);} //mozgatás seg=t[0]; for(i=1;i<10;i++) {t[i-1]=t[i];} t[9]=seg; printf("\nA tomb elemei mozgatas utan:"); for(i=0;i<10;i++) {printf("\t%i",t[i]);} return 0; } 16. ábra. Az 1.2.1.6. feladat
14
ro ramlistá a
Írjon programot, amely egy 10 elemű egész típusú tömb elemeiről eldönti, hogy számtani sorozatot alkotnak - e! A tömböt a klaviatúráról történő beolvasással töltse fel, majd a megfelelő szöveges üzenetet írja ki a képernyőre! 1.2.1.7.
Egy sorozat akkor számtani sorozat, ha a szomszédos elemek különbsége állandó. A megoldás során az eldöntés tételét alkalmazzuk. A tömb 0. és 1. eleméből meghatározzuk a „d”-t (differenciát), majd ciklikus művelettel megvizsgáljuk, hogy a tömb összes szomszédos elemének a különbsége egyenlő -e a „d”-vel. Önálló feladatként módosítsa úgy az algoritmust, hogy eldöntse, hogy a vektor elemei mértani sorozatot alkotnak-e? int _tmain(int argc, _TCHAR* argv[]) { int t[10];int i=0,n; printf("\nKerem a tomb elemeit!"); do{printf("\n%i.elem= ", i);scanf("%i",&t[i]);i++; }while(t[i-1]!=0 && i<10); if(i==10) n=i; else n=i-1; int d=t[1]-t[0]; i=2; //számtani sorozat? while(t[i]-t[i-1]==d && i
feladat programlistája
z előző (1.2.1.7.) f eladatot pointer 1.2.1.8. Oldj uk meg a
változók segítségével! A tömb neve egy pointer változó. A részletes magyarázatot lásd az 1.2.1.3. példánál. int _tmain(int argc, _TCHAR* argv[]) { int t[10];int i=0,n=-1; int *tp=t;tp--; printf("\nKerem a tomb elemeit!"); do{tp++;n++; printf("\n%i.elem= ", n);scanf("%i",tp); }while(*tp!=0 && n<10); tp=t; int d=*(tp+1)-*tp; //differencia tp++; while(*tp!=0 && (*tp-*(tp-1)==d)) {tp++;} if(*tp==0) printf("\nSzamtani sorozat"); else printf("\nNem szamtani sorozat");} 18. ábra. Az 1.2.1.8.feladat programlistája
Adott egy N elemű sorozat, amely egész számokat tartalmaz. Adjuk meg a sorozatban található legkisebb pozitív számot! A minimum kiválasztás tételét kell alkalmaznunk, meg kell határoznunk a sorozat legkisebb pozitív elemét. A kérdés az, hogy mi legyen a „min” változó kezdőértéke . Egyik megoldás az, hogy megkeressük az első pozitív számot, ez lesz a kezdőérték, és ezt fogjuk majd összehasonlítani a sorozat következő pozitív elemével. A másik lehetőség, hogy a kezdőérték a változó értékkészlete által megengedett legnagyobb értékű elem lesz, és ezt hasonlítjuk a sorozat pozitív elemeivel. Ha nincs a sorozatnak pozitív eleme, az is kiderül, mert a kezdőérték nem fog megváltozni . 1.2.1.9.
15
a)
megoldás: Megkeressük az első pozitív elemet.
int _tmain(int argc, _TCHAR* argv[]) {int t[10],i=0,n; do{printf("\n%i. elem= ",i);scanf("%i",&t[i]);i++; }while(t[i-1]!=0 && i<10); if(i==10) n=i; else n=i-1; for(i=0;i0) {if(t[i]
b)
megoldás: A min változónak a + értéket adjuk kezdőértékként.
int _tmain(int argc, _TCHAR* argv[]) { int t[10],i=0,n; do {printf("\n%i. elem= ",i); scanf("%i",&t[i]);i++; }while(t[i-1]!=0 && i<10); if(i==10) n=i; else n=i-1; for(i=0;i0) {if(t[i]
1.2.1.10. Adott
egy N elemű sorozat (A), és egy M elemű sorozat (B). Adjuk meg a két sorozat közös elemeit !
A megoldás során két vektort fogunk beolvasni 0 végjelig majd meghatározzuk azokat az elemeket, amelyek mindkét sorozatnak az elemei. A metszetképzés tételét alkalmazzuk. Mivel a metszetképzés tétele során két halmaz metszetét képezzük, ezért feltételezzük, hogy a vektorokban minden elem csak egyszer fordul elő (egy vektort akkor tekinthetünk halmaznak, ha minden elem csak egyszer fordul elő). Az „A” vektor elemeiről (egyesével) eldöntjük, hogy benne vannak-e a „B” vektorban. Ha igen, akkor beletesszük a közös elemeket tartalmazó Metszet nevű vektorba. int _tmain(int argc, _TCHAR* argv[]) {int a[100], b[100], metszet[100]; int i=0,j=0,k=0,n,m; printf("\nKerem az A vektor elemeit!\n"); do{printf("\n%i.elem= ",i);scanf("%i",&a[i]);i++; }while(a[i-1]!=0 && i<100); if(i==100) n=i; else n=i-1;
16
printf("\nKerem a B vektor elemeit!\n"); do{printf("\n%i.elem= ",j);scanf("%i",&b[j]);j++; }while(b[j-1]!=0 && j<100); if(j==100) m=j; else m=j-1; for(i=0;i
1.2.2.
Gyakorisági tömbök
A gyakorlati életben sok olyan feladattal találkozunk, amikor valamilyen esemény ek gyakoriságát (előfordulási számát) kell meghatároznunk. Készítsen statisztikát a kocka dobálás eredményeiről! A lehetséges dobás értékek: 1, 2, 3, 4, 5, 6. Minden kockadobást véletlenszám - generátorral oldjon meg! A számlálást gyakoriság i tömb alkalmazásával végezze el, majd az eredményt áttekinthető formában írja ki a képernyőre! Gyakoriság() 1.2.2.1.
A megoldás során egy 6 elemű tömböt, mint gyakorisági tömböt fogunk használni. A tömb 0. eleme az 1-es dobások, az 1. eleme a 2 -es dobások… darabszámát fogja megadni. Minden egyes kockadobás után a tömb dobás -1. elemét megnöveljük 1-el (a C++-ban 0-tól indexeljük a tömböket).
1. for i 0 to hossz[dobások] 2. do dobasok[i] 0 3. read dobasok_szama 4. for i 0 to dobasok_szama 5. do 6. szam véletlenszám(1,6) 7. dobasok[szam-1] dobasok[szam-1]+1 8. for i 0 to hossz[dobasok] 9. do write dobasok[i]
int _tmain(int argc, _TCHAR* argv[]) {int i,szam,dobszam; int dobasok[6]; printf("\nDobasok szama= "); scanf("%i",&dobszam); for(i=0;i<6;i++) {dobasok[i]=0;} for(i=0;i
Készítsen olyan programot, amely megszámolja egy egész számban előforduló számjegyek számát ! A számjegyek számlálását gyakoriságtömb segítségével fogjuk megoldani. A gyakoriságtömb 10 elemű lesz, mivel 10 db számjegyünk van. Az egyes számjegyeket maradékos (moduló) osztással fogjuk előállítani, majd a gyakoriságtömb számjegynek megfelelő elemét megnöveljük 1-el. 1.2.2.2.
17
Számjegyekszáma() 1. for i 0 to hossz[szamjegyek] do szamjegyek[i] 0 2. read szam 3. while szam 0 4. do szamjegy szam%10 : szam szam/10 : szamjegyek[szamjegy] szamjegyek[szamjegy]+1 5. for i 0 to hossz[szamjegyek] do write szamjegyek[i] int _tmain(int argc, _TCHAR* argv[]) {int szamjegyek[10]; int i,szam,szamjegy; for(i=0;i<10;i++) {szamjegyek[i]=0;} printf("\nSzam= ");scanf("%i",&szam); if(szam==0) {szamjegy[szam]++;} while(szam!=0) {szamjegy=szam%10;szamjegyek[szamjegy]++;szam=szam/10;} printf("\nAz elofordulo szamjegyek: \n"); for(i=0;i<10;i++){printf("\n%i:\t%i",i,szamjegyek[i]);return 23. ábra. Az 1.2.2.2. feladat
0;}
pszeudokódja és programlistája
Határozzuk meg, hogy egy osztály tanulói közül hány 150 cm alatti, hány 150-160 cm közötti, hány 160- 170 cm közötti, hány 170- 180 cm közötti, hány 180- 190 cm közötti és hány 190 cm feletti tanulója van. Készítsen olyan programot, amely előállítja ezen togram adatsorát ! hisz 1.2.2.3.
Az adatok beolvasása után gyakorisági tömb segítségével meghatározzuk az adott magassági határok közé eső tanulók számát. A gyakorisági tömb 0. eleme a 150 cm alatti tanulók számát fogja számolni, az 1. eleme a 150 -160 cm között tanulók számát, … az 5. eleme a 190 cm feletti tanulók számát. int _tmain(int argc, _TCHAR* argv[]) {int magassagok[30];int gyakorisag[6];int i,n; for(i=0;i<6;i++) gyakorisag[i]=0; i=0; do{printf("\n%i.elem= ",i);scanf("%i",&magassagok[i]);i++; }while(magassagok[i-1]!=0 && i<30); if(i==30) n=i; else n=i-1; for(i=0;i=150 && magassagok[i]<159) gyakorisag[1]++; else if(magassagok[i]>=160 && magassagok[i]<169) gyakorisag[2]++; else if(magassagok[i]>=170 && magassagok[i]<179) gyakorisag[3]++; else if(magassagok[i]>=180 && magassagok[i]<189) gyakorisag[4]++; else if(magassagok[i]>=190) gyakorisag[5]++;} for(i=0;i<6;i++) {printf("%8i",gyakorisag[i]);}} 24. ábra. Az 1.2.2.3. feladat programlistája
1.2.3. K araktertömbök A következőkben megnézünk néhány példát karaktertömbökre! A karaktertömbök egydimenziós tömbök (vektorok), melyek minden eleme karakter. A C nyelv nem rendelkezik önálló sztringtípussal, ezért a karaktertömböket használja a sztringek tárolására. A sztring tehát olyan karaktertömb (char[]), melyben a karaktersorozat végét nulla értékű bájt (’ \0’) jelzi. A Windows és a Unix operációs rendszerben is un. 0-végű sztringeket használnak, így a mintapéldáinkban mi ilyen adatszerkezettel oldjuk meg a feladatainkat. 18
A 0 végű sztringek egyik előnye például az, hogy nem kell megjegyeznünk a sztring elemeinek a számát, mivel a sztring záró karakter egyértelműen meghatározza a sztring végét. A példákban szándékosan nem fogunk magas szintű sztring kezelő függvényeket használni, hanem a sztringeket tömbként kezeljük. Cél, hogy tovább gyakoroljuk a tömbökkel való műveletvégzést. Léteznek előre megírt sztring kezelő függvények (C++ string.h fájlban definiálva). Ezekről részletesen olvashat Benkő Tiborné, Benkő László, Tóth Bertalan: Programozzunk C nyelven c ímű könyvében 6. Olvassunk be „enter”( \n) végjelig egy maximum 20 elemű karaktertömböt ! Adjuk meg, hogy hány db számjegy karaktert tartalmaz a karaktertömb ! Egy karaktertömböt kell beolvasnunk enter végjelig, majd meg kell határoznunk a számjegy karakterek darabszámát. A megoldáshoz felhasználjuk a megszámolás tételét! Karakterek esetén a karakterek ASCII kódját String1() hasonlítjuk össze egymással. Az 1. repeat read s[i]: i i+1 „if(s[i]>=’0’ && s[i]<=’9’” sor jelentése: 2. until s[i-1] Enter and i=’0’ and s[i]<=’9’ then db 6. db+1 és kisebb vagy egyenlő a „ 9”-es karakter 7. i i+1 8. write db ASCII kódjánál. 1.2.3.1.
int _tmain(int argc, _TCHAR* argv[]) {char s[20]; int i=0,db=0; printf("\nString= "); do{scanf("%c",&s[i]);i++; }while(s[i-1]!='\n' && i<20); s[i-1]='\0'; for(i=0;s[i]!='\0';i++) if(s[i]>='0' && s[i]<='9') db++; printf("\nA szamjegy karakterek szama= %i",db);} 25. ábra. Az 1.2.3.1. feladat pszeudokódja és programlistája
Oldjuk meg az előző példát (1.2.3.1.) pointer változókkal! A tömb neve egy pointerváltozó. A részletes magyarázatot lásd az 1.2.1.3. példánál. 1.2.3.2.
int _tmain(int argc, _TCHAR* argv[]) {char s[20];int n=0;int db=0; char *ps=s; ps--; printf("\nString= "); do{ps++;n++; scanf("%c",ps); }while(*ps!='\n' && n<20); *ps='\0'; ps=s; for(;*ps!='\0';ps++) if(*ps>='0' && *ps<='9') db++; printf("\nA szamjegy karakterek szama= %i",db);} 26. ábra. Az 1.2.3.2. feladat programlistája
6
Benkő Tiborné, Benkő László, Tóth Bertalan: Programozzunk C nyelven 127 -130. oldal 19
Olvassunk be „enter”( \ n) végjelig egy maximum 20 elemű karaktertömböt ! Döntsük el, hogy a karaktertömb tükörszó-e! 1.2.3.3.
Egy karaktertömböt kell beolvasnunk enter végjelig, majd el kell döntenünk, hogy tükörszó -e. A megoldáshoz az eldöntés tételét fogjuk felhasználni. Meg kell vizsgálnunk, hogy a karaktertömb 0. karaktere egyenlő -e a ’ \0’ sztring záró karakter előtti utolsó karakterrel, az 1. karaktere egyenlő -e az utolsó előtti karakterrel, és így tovább. A vizsgálatot addig végezzük, amíg nem találunk két nem egyenlő karaktert, vagy felcserélődik a két tömbindex . int _tmain(int argc, _TCHAR* argv[]) {char s[20]; int i=0,db=0; printf("\nString= "); do{scanf("%c",&s[i]);i++; }while(s[i-1]!='\n' && i<20); s[i-1]='\0'; int j=0; while(s[j]!='\0') { j++; } j--; i=0; int palindrom; while(s[i]==s[j] && i=j); if(palindrom){printf("\nTukorszo");}else{printf("\nNem tukorszo");}} 27. ábra. Az 1.2.3.3. feladat programlistája
1.2.4.
Kétdimenziós tömbök, mátrixok
A következőkben megnézünk néhány példát a kétdimenziós tömbök (mátrix) kezelésére. A mátrixok esetében két indexre lesz szükségünk, lesz egy sorindex (általában i -vel jelölik) és lesz egy oszlopindex (általában j-vel jelöljük). Írjon olyan programot, amely véletlen számokkal feltölt egy N * M - es mátrixot, és mátrix alakban kiírja a képernyőre! A mátrixokat feltölthetjük (illetve kiírhatjuk) sorfolytonosan vagy oszlop folytonosan. A sorfolytonos feltöltés azt jelenti, hogy először feltöltjük a 0. sor elemeit egy belső ciklussal a vektoroknál megismert módszerrel, majd az 1. sor Mátrix() 1. for i 0 to n elemeit és így tovább. Két ciklus lesz a feltöltéskor, 2. do a külső ciklus változója a sorindex, a belső ciklus for j 3. 0 to m változója az oszlopindex lesz. Az oszlop -folytonos 4. do t[i] véletlenszám feltöltés esetén fordított sorrendben járunk el. Az 5. 6. for i 0 to n „n” és az „m” értékét a program a billentyűzetről 1.2.4.1.
7. do for j 0 to m do write t[i] 8.
olvassa be.
int _tmain(int argc, _TCHAR* argv[]) {int matrix[10][5]; int i,j; printf("\N= „);scanf("%i",&n); printf("\M= „);scanf( "%i",&m); for(i=0;i
20
pszeudokódja és programlistája
Készítsen programot, amely egy 10 fős tanulócsoport 6 tantárgyból szerzett osztályzatait dolgozza fel. Az osztályzatokat véletlenszám generátorral hozzuk létre, mátrix alakban jelenítsük meg, úgy, hogy egy sorban egy tanuló osztályzatai legyenek, a sor végén a tanuló tanulmányi átlagával. Utolsó sorként írjuk ki a tantárgyak átlagát a tanulócsoportban! A feladatot kétdimenziós tömb alkalmazásával oldjuk meg . Ellenőrzött adat bevitellel vagy véletlenszám generátorral feltöltünk egy 10*6-os mátrixot úgy, hogy minden tanuló esetében a tantárgyak sorrendje ugyanaz. Az osztályzatokat tanulónként hozzuk létre. A tanulókat és a tantárgyakat is sorszámmal azonosítjuk. A tanulók tanulmányi átlagát a mátrix sorainak átlaga fogja adni, a tantárgyankénti átlagot pedig a mátrix oszlop átlagai fogják megadni. 1.2.4.2.
int _tmain(int argc, _TCHAR* argv[]) {int tanulok[10][6]; int i,j; float tanatl[10],tantargyatl[6]; srand (time(NULL)); //veletlenszam generator inicializalasa for(i=0;i<10;i++) //feltöltés for(j=0;j<6;j++) {tanulok[i][j]=rand()%5+1;} for(i=0;i<10;i++) //tanulóátlag -> sorátlag {tanatl[i]=0; for(j=0;j<6;j++) {tanatl[i]=tanatl[i]+tanulok[i][j];} tanatl[i]=tanatl[i]/6;} for(j=0;j<6;j++) //tantárgyátlag -> oszlopátlag {tantargyatl[j]=0; for(i=0;i<10;i++) {tantargyatl[j]=tantargyatl[j]+tanulok[i][j];} tantargyatl[j]=tantargyatl[j]/10;} printf("\nA tomb elemei:\n"); //kiírás mátrix alakban for (i=0;i<10;i++) {for(j=0;j<6;j++) {printf("%6i",tanulok[i][j]);} printf("%6.2f",tanatl[i]); printf("\n");} for(j=0;j<6;j++) {printf("%6.2f",tantargyatl[j]);} return 0; } 29. ábra. Az 1.2.4.2. feladat programlistája
1.2.4.3.
Egy hónapon keresztül minden nap megmértük a hőmérsékletet r eggel és este.
a) Adj uk meg azt a napot, amik or r eggel a legmelegebb volt ! b) Adjuk meg mikor volt a legkisebb különbség a reggeli és az esti hőmérséklet között! c) Adj uk meg azokat a napokat, amikor r eggel melegebb volt, mi nt este! d) Hány nap volt 10 fok fölött a különbség a reggeli és az esti hőmérséklet között? e) Hány olyan nap volt, amikor az előző esti hőmérséklet megegyezett az aznap reggeli
hőmérséklettel? Az adatokat egy 30*2- es mátrixban fogjuk tárolni. Tételezzük fel, hogy 30 napos a hónap. A mátrix sorai a napok sorszámai, az első oszlop a reggel, a második oszlop az este mért hőmérsékletet tartalmazza. a) megoldása: A mátrix nulladik (0-tól indexelünk) oszlopára egy maximum -kiválasztást alkalmazzuk. b) megoldása: figyelve arra,
Először meghatároz zuk a reggeli és esti hőmérsékletek közötti különbséget, hogy mindig pozitív eredményt kapjunk, és ezek alapján egy minimumkiválasztást végzünk . 21
c) megoldása: A kiválogatás tételét alkalmaz zuk , és azon napok sorszámát adjuk meg, amikor
az első oszlopban lévő érték (reggeli hőmérséklet) nagyobb, mint a második oszlopban lévő (esti hőmérséklet ) d) megoldása: A megszámolás tételét alkalmazzuk. Meghatározzuk a reggeli és esti hőmérsékletek közti különbséget (abszolút értékben), és ha ez 10 foknál nagyobb, növeljük a darabszámot, ami azon napok számát jelöli, ahol több 10 foknál a hőmérséklet különbség a reggel és este mért érték között. e) megoldása: A megszámolás tételét alkalmazzuk. A második naptól kezdve, megnézzük, hogy az előző nap (előző sorban, a második oszlopban lévő érték) este mért érték megegyezik-e a vizsgált nap reggelén mért értékkel (aktuális sor első oszlopa), ha igen növeljük a feltételnek eleget tévő napok számát. int _tmain(int argc, _TCHAR* argv[]) {float hom[30][2]; int i=0,j=0,n=30; for(i=0;ihom[maxi][0]) {maxi=i;}} printf("\nA %i. napon volt a legmelegebb a reggel",maxi); //b) megoldása minimum kiválasztás a hőm. különbségekre //abs(esti-reggeli hőm.) float kul=abs(hom[0][1]-hom[0][0]); int mini=0; for(i=1; ihom[i][1]) {printf("%4i",i);}} //d) megoldása megszámolás, amikor a hőm. különbségekre //abs(esti-reggeli hőm.)>10 int db=0; for(i=0; i10) {db++;}} printf("\nAzok a napok szama, amikor a reggeli és esti homerseklet kulonbseg nagyobb mint 10 fok: %i",db); //e) megoldása megszámolás, amikor az előző esti hőm. = az //aznap reggeli homerseklettel db=0; for(i=1; i
22
Készítsen programot, amely egy N*N - es mátrixot feltölt véletlen számokkal, majd es - elkészíti a transzponált mátrixot transzponált mátrixot ! A transzponált mátrixot úgy kapjuk, hogy a sorokat és az oszlopokat felcseréljük. 1.2.4.4.
int _tmain(int argc, _TCHAR* argv[]) {int matrix[5][5], matrixtransz[5][5]; int i,j; for(i=0;i<5;i++) //sorfolytonos feltöltés {for(j=0;j<5;j++){matrix[i][j]=rand()%100;}} printf("\nA feltoltott matrix:\n"); for(i=0;i<5;i++) {for(j=0;j<5;j++) {printf("%6i",matrix[i][j]);} printf("\n");} for(i=0; i<5; i++) //transzponált mátrix előállítása {for(j=0;j<5;j++) {matrixtransz[j][i]=matrix[i][j];}} printf("\nA transzponalt matrix:\n"); for(i=0;i<5;i++) {for(j=0;j<5;j++) {printf("%6i",matrixtransz[i][j]);} printf("\n");} return 0;} 31. ábra. Az 1.2.4.4. feladat programlistája
Készítsen programot, amely egy N*N - es mátrixot feltölt a billentyűzetről, és es - eldönti, hogy a mátrix szimmetrikus-e! Egy négyzetes mátrix akkor szimmetrikus mátrix, ha az eredeti mátrix megegyezik a transzponáltjával. Vagyis: a ij = a ji minden i,j=1,…n indexre. A megoldás során az eldöntés tételét fogjuk alkalmazni. A vizsgálóciklus addig fog futni, amíg nem találunk olyan ol yan elemet, amelyre aij ≠ a ji vagy i eléri az n-et, vagyis megvizsgáltunk minden elemet. Ha úgy lépünk ki, hogy i=n, akkor szimmetrikus a mátrix. 1.2.4.5.
int _tmain(int argc, _TCHAR* argv[]) {int matrix[10][10]; int i,j,n; do {printf("\nMatrix sor es oszlopszama= ");scanf("%i",&n); }while(n<1 || n>10); for(i=0;i
23
1.3.
Függvények, paraméterátadás
A következőkben megoldunk néhány feladatot az alprogramok témakörében. 1.3.1.
Érték szerinti paraméterátadás
Készítsünk olyan maximum nevű függvényt, aminek az a feladata, hogy a kapott két paramétere közül a nagyobb értékűt adja vissz vissza! A megoldás során két egész típusú változó értékét átad unk a függvénynek, amely meghatározza, hogy a két érték közül melyik a nagyobb. A nagyobb értéket a függvény nevével, mint „változóval” adjuk vissza a hívó programnak.
1.3.1.1.
int maximum(int a, int b) {if(a>b) return a; else return b;} int _tmain(int argc, _TCHAR* argv[]) {int x,y,nagyobb; printf("\nx=");scanf("%i",&x);printf("\ny=");scanf("%i",&y); nagyobb=maximum(x,y); printf("\nA két szám közül a(z) %i a nagyobb!",nagyobb);} 33. ábra. Az 1.3.1.1. feladat programlistája
A maximum függvény két (a és b) paramétere értékként a híváskor megadott két paraméter (x és y) paraméter értékét kapja. A verem memóriában (stack) létrejön egy „a” és egy „b” nevű változó, amelyekbe bemásolódik az a x és y értéke! Érték kerül átadásra! A return utasítás hatására visszatérünk a függvényből (a visszatérési cím a verem memóriából kivételre kerül), ekkor az a és a b változó megsemmisül, így értéke is elvész. A verem memória LIFO (Last In First Out) szervezésű, így a visszatérési címhez csak úgy jutunk hozzá, hogy a felette levő változókat „kidobáljuk” a veremből. Egy ellenőrzéssel beolvasott pozitív egész számról döntse el, hogy prímszám-e! -e! A vizsgálatot függvénnyel végeztesse el, amely az eredményt „logikai érték” visszaadásával jelzi a főprogramnak! A szöveges szöv eges üzenetet a főprogram írja ki a képernyőre! 1.3.1.2.
A feladat megoldása során függvény segítségével döntjük el egy számról, hogy prímszám -e. A függvénynek a főprogramban beolvasott számot értékszerinti paraméterátadással adjuk át, mivel a függvény a szám értékét nem fogja megváltoztatni. A függvény neve, mint logikai típusú változó fogja az eredményt (igaz, vagy hamis) visszaadni. Egy szám akkor prímszám, ha csak 2 osztója van, az 1 és önmaga. int primszam(int a) {int prim=true; int oszto=2; if(a!=1) {while(a%oszto!=0) {while(a%oszto!=0) {oszto++;} prim=(oszto==a);} return prim;} int _tmain(int argc, _TCHAR* argv[]) {int szam;printf("\nSzam= ");scanf("%i",&szam); if(primszam(szam)) {printf("\nA(z) %i primszam", szam);} else {printf("\nA(z) %i nem primszam", szam);}return 0;} 34. ábra. Az 1.3.1.2. feladat programlistája
24
1.3.2.
Cím szerinti paraméterátadás
Írjon olyan függvényt, amely a memóriában felcseréli két egész típusú változó tartalmát! A feladat megoldása során látni fogjuk, hogy itt már nem fog helyesen működni az algoritmusunk, ha érték szerinti paraméterátadást paraméterátadást használunk. 1.3.2.1.
void csere(int &x, int &y) {int cs; cs=x; x=y; y=cs;} int _tmain(int argc, _TCHAR* argv[]) {int a,b; printf("\na=");scanf("%d",&a);printf("\nb=");scanf("%d",&b); printf("\nA két változó a csere elött:a= %d,b=%d",a,b); csere(a,b);printf("\ nA két változó a csere után: a=%d, b=%d",a,b);} 35. ábra. Az 1.3.2.1. feladat programlistája
A paraméterátadás folyamatát az alábbi ábra szemlélteti:
void csere(int &x, int &y) { int cs; cs=x; x=y; y=cs; return; } void main() { int a,b;
adat memória verem (stack) memória
b a
y = b változó címe x = a változó címe
csere(a,b); printf("\nA két változó a csere után : ...); ...); }
36. ábra. A cím szerinti
cs
Visszatérési cím
paraméterátadás
A csere függvény két (x és y) paramétere értékként a híváskor megadott két paraméter (a és b) változó címét kapja. A veremmemóriában (stack) létrejön egy „x” és egy „y” nevű változó, amelyekbe bemásolódik az „a” és „b” változó címe! Memória cím kerül átadásra! Ha visszatérünk a függvényből, akkor az x és az y változó megsemmisül, így értéke is elvész, de ez nem okoz gondot, mert a változás (csere) az „a” és „b” változót tároló memória rekeszekben rekeszekben történt. Az x=y utasítás értelmezése: Az x változó által mutatott memóriacímen levő adat (a) legyen egyenlő az y változó által mutatott memóriacímen levő adattal (b). 1.3.3.
Érték szerint pointerváltozó (memória cím) átadás
1.3.3.1. Oldjuk
meg az előbbi csere programunkat úgy (1.3.2.1.) , hogy pointer változókkal
dolgozunk!
Látni fogjuk, hogy működés szempontjából hasonló a helyzet, mint a címszerinti paraméterátadásnál. paraméterátadásnál. A híváskor az x mint pointer típusú változó az a változó memóriacímét, az y mint pointer típusú változó a b változó memóriacímét kapja értékül.
25
void csere(int *x, int *y) {int cs; cs=*x; *x=*y; *y=cs;} int _tmain(int argc, _TCHAR* argv[]) {int a,b; printf("\na=");scanf("%d",&a);printf("\nb=");scanf("%d",&b); printf("\nA két változó a csere elött: a=%d, b=%d",a,b); csere(&a,&b);printf("\ nA két változó a csere után: a=%d, b=%d",a,b);} 37. ábra. Az 1.3.3.1 feladat programlistája
Mi történik pl. a *x = *y utasítás hatására. Az „x” változó, mint pointerváltozó által mutatott memória hely tartalma legyen egyenlő az „y”, mint pointerváltozó által mutatott memóriahely tartalmával. Mivel az „x” az „a” változó címét, az „y” a „b” változó címét tartalmazza, gyakorlatilag az a=b; utasítás kerül végrehajtásra. Tehát a működés hasonló a címszerinti paraméterátadáshoz. Memóriacímet adunk át érték szerint. 1.3.4.
A tömb, mint paraméter:
A C nyelvben a tömb neve egy pointerváltozó, vagyis a tömb neve a tömb memóriabeli kezdőcíme. Így, ha tömböt kell átadnunk egy függvénynek, akkor egyszerűen a tömb nevét, mint pointerváltozót adjuk át. A függvényen belül ugyanúgy hivatkozhatunk a tömbre, mint a main() függvényben. Írjon olyan függvényt, amely meghatározza egy adott elemszámú vektor legnagyobb elemének indexét! A vektor elemeinek a beolvasását, és a legnagyobb elem indexének és értékének kiírását a főprogram végezze el. A megoldás során a függvénynek a tömb nevét, mint memóriacímet adjuk át. A függvény meghatározza a legnagyobb elem indexét. Az indexet a hívó programnak a függvény nevével, mint „változóval” adjuk vissza. 1.3.4.1.
int maxkiv(int *v, int n) {int i; int max=v[0]; for(i=1; imax) {max=v[i];}} return max;} int _tmain(int argc, _TCHAR* argv[]) {int t[100]; int i=0, n, maxelem; do{printf("\n%i.elem= ",i);scanf("%i",&t[i]);i++; }while(t[i-1]!=0 && i<100); if(i==100) n=i; else n=i-1; maxelem=maxkiv(t,n); printf("\nA tomb legnagyobb eleme= %i",maxelem);return 0;} 38. ábra. Az 1.3.4.1. feladat programlistája
Készítsen olyan programot, amely beolvas egy maximum 100 elemű egész típusú vektor t 0 végjelig , majd meghatározza azoknak az elemeknek a számát, amelyek tartalmaznak számjegy azonosságot. A feladatot függvényekkel oldja meg! 1.3.4.2.
A megoldás során a „ beolvas” függvény segítségével 0 végjelig beolvasunk egy vektort. A főprogram fogja megszámolni azokat az elemeket, amelyek tartalmaznak számjegy azonosságot (a „szamjegyazonossag” nevű függvény által visszaadott érték alapján) . 26
A „szamjegyazonossag” nevű függvény egy gyakoriságtömb segítségével megszámol ja, hogy egy adott tömbelem (átadott szám) hány darab 0, 1, 2, … 9 -es számjegyet tartalmaz. A függvény az eldöntés tétele segítségével eldönti, hogy a gyakoriságtömbnek van -e olyan eleme, amely nagyobb, mint 1, vagyis van- e olyan számjegy, amely 1 -nél többször fordul elő az adott számban. Ha van, akkor igaz, ha nincs akkor hamis értékkel tér vissza. int beolvas(int *v) {int i=0,n; do{printf("\n%i. elem= ",i);scanf("%i",&v[i]); i++; }while(v[i-1]!=0 && i<100); if(i==100) {n=i;} else {n=i-1;} return;} int szamjegyazonossag(int szam) {int szjegyekdb[10],i,szjegy,van; for(i=0;i<10;i++) {szjegyekdb[i]=0;} while(szam!=0) {szjegy=szam%10;szjegyekdb[szjegy]++;szam=szam/10;} //eldöntés van-e olyan szamjegy, van-e olyan eleme az szjegyekdb tombnek, //amely nagyobb, mint 1 i=0; while(i<10 && szjegyekdb[i]<2) {i++;} van=(i<10); return van;} int _tmain(int argc, _TCHAR* argv[]) {int t[100],i,db=0; int n=beolvas(t); for(i=0; i
Készítsen olyan programot, amely beolvas egy maximum 100 elemű egész típusú vektort 0 végjelig, majd kiválasztja azt az elemet, amelyben a számjegyek összege a legnagyobb. A feladatot függvényekkel oldja meg! 1.3.4.3.
A megoldás során a „beolvas” függvény segítségével 0 végjelig beolvasunk egy vektort , majd a maximum kiválasztás tételét alkalmazva meghatározzuk a legnagyobb számjegyösszegű elem sorszámát. Készítünk egy függvényt, amely meghatározza egy egész szám számjegyeinek összegét. A maximum kiválasztás során ezt a függvényt fogjuk hívni, hogy az aktuális tömbelem, mint szám számjegyinek az összegét meghatározza. int beolvas(int *t) {int i=0,n; do{printf("\n%i.elem= ",i);scanf("%i",&t[i]);i++; }while(t[i-1]!=0 && i<100); if(i==100) n=i; else n=i-1; return n;} int szjosszeg(int szam) {int szjossz=0; while(szam!=0) {szjossz=szjossz+szam%10;szam=szam/10;} return szjossz;} int _tmain(int argc, _TCHAR* argv[]) {int t[100],n,i; n=beolvas(t); int maxi=0,szjossz; int maxszjossz=szjosszeg(t[0]); 27
for(i=1;imaxszjossz) {maxi=i;maxszjossz=szjossz;}} printf("\nA legnagyobb szamjegyosszegu tombelem sorszama=%i, szjosszeg=%i", maxi,maxszjossz); return 0; } 40. ábra. Az 1.3.4.3. feladat programlistája
Készítsen olyan programot, amely beolvas Enter karakterig egy karaktertömböt , majd függvény segítségével meghatározza azon rész kezdő - és végindexét, amelyben azonos karakterek vannak! Több ilyen esetén válassza ki azt, amelyben a karakterek száma maximáli s! 1.3.4.4.
A megoldás során a „beolvas” függvény segítségével Enter végjelig beolvasunk egy karaktertömböt. Az „azonosresz” nevű függvény meghatározza annak a rész -karaktertömbnek a kezdő és végindexét, amely a leghosszabb azonos karakterekből álló intervallumot jelöli ki. A megoldás során vizsgáljuk a
karaktertömbü nk szomszédos karaktereit. Ha a két szomszédos karakter nem egyenlő, akkor egy új azonos karaktereket tartalmazó részi ntervallum kezdődhet, vagyis a végindexet egyenlővé tesszük a kezdő indexel. Ha a két szomszédos karakter megegyezik, akkor azonos karaktereket tartalmazó részintervallumban vagyunk, ekkor az a teendőnk, hogy megvizsgáljuk, hogy a mostani részintervallum h ossza nagyobb-e, mint az eddig megtalált , leghosszabb azonos karaktereket tartalmazó részintervallum. void beolvas(char *s) {int i=0; printf("\nString= "); do {scanf("%c",&s[i]);i++; }while(s[i-1]!='\n' && i<20); s[i-1]='\0';} void azonosresz(char *s,int *kezdo,int *veg) {int k=0,v, *kezdo=*veg=0; for(v=1;s[v]!='\0';v++) {if(s[v]!=s[v-1]) k=v; else if(v-k>*veg-*kezdo) {*kezdo=k;*veg=v;}}} int _tmain(int argc, _TCHAR* argv[]) {char s[20];int kezdo,veg; beolvas(s); azonosresz(s,&kezdo,&veg); printf("\nAz azonos resz: %i - tol %i - ig",kezdo, veg);} 41. ábra. Az 1.3.4.4. feladat programlistája
Készítsen olyan programot, amely beolvas Enter karakterig két db karaktertömböt . Függvény segítségével döntse el, hogy az első karaktertömb tartalmazza- e a második karaktertömböt ! Nem használhat sztringkezelő függvényeket! 1.3.4.5.
Egy függvény segítségével beolvassuk a két karaktertömböt . Első lépésként megkeressük, hogy az első karaktertömbünkben hol található a második karaktertömbünk kezdőkaraktere („kereselső”). Ha nincs benne, akkor végeztünk, az első karaktertömb nem tartalmazza a második karaktertömböt. Ha megtaláltuk az első karaktert, akkor ettől a pozíciótól kezdve karakterenként vizsgáljuk a két karaktertömböt. Ha a második karaktertömb végére értünk, akkor tartalmazza az első karaktertömb a második karaktertömböt . 28
Ha találunk karakter eltérést, akkor az eljárást kezdjük elölről, keressük az első karaktertömbünkben a második karaktertömb kezdőkarakterének következő előfordulását. Az eljárást addig folytatjuk, amíg az első karaktertömbünk végére nem érünk. void beolvas(char *s) {int i=0; printf("\nString="); do{scanf("%c",&s[i]); i++; }while(s[i-1]!='\n' && i<20); s[i-1]='\0'; return;} int kereselso(int i,char *s, char c) {while(s[i]!='\0' && s[i]!=c) {i++;} return i;} int tartalmazza(char *s1, char *s2) {int i=0,benne=false,vege=false,k=0; while(!benne && !vege) {k=kereselso(k,s1,s2[0]); //kezdőpozíció keresése if(s1[k]=='\0') {vege=true;} //elértük az s1 végét else //megvan a kezdőpozíció, karakterenkénti hasonlítás {i=0; while(s1[k]!='\0' && s2[i]!='\0' && s1[k]==s2[i]) {k++;i++;} if(s2[i]=='\0') {benne=true;};} }return benne;} int _tmain(int argc, _TCHAR* argv[]) {char s1[20], s2[20]; beolvas(s1); beolvas(s2); if(tartalmazza(s1,s2)) {printf("\nBennevan");} else {printf("\nNincs benne");}return 0;} 42. ábra. Az 1.3.4.5. feladat programlistája
Készítsen programot, amely két 1- nél nagyobb, egymástól különböző természetes szám esetén megoldja a következő feladatokat: külön mindkét szám összes osztóját a) megadja külön- külön mindkét szám összes valódi osztóját (e gy szám valódi b) megadja külön- osztóinak nevezünk minden olyan osztót, amely nem 1 és nem maga a szám.) c) megadja mindkét szám összes osztóját (növekvő sorrendben rendezetten) d) megadja mindkét szám összes valódi osztóját (növekvő sorrendben rendezetten) e) megadja mindkét szám közös osztóit e! Két szám relatív prím, ha egy közös valódi f) eldönti, hogy a két szám relatív prím- osztójuk sincs. 1.3.4.6.
A feladatot függvényekkel fogjuk megoldani. Az a) feladat esetén egy függvény egy tömbbe kigyűjti az adott szám összes osztóját. A függvényt először az első, majd a második számmal fogjuk meghívni. A b) feladat esetén a z a) feladathoz hasonlóan egy függvény kigyűjti az adott szám összes valódi osztóját . A c) feladat során a függvény a számok osztóit tartalmazó halmazok rendezett unióját fogja képezni az összefuttatás tétele segítségével. A d) feladat során a függvény a számok valódi osztóit tartalmazó halmazok rendezett unióját fogja képezni az összefuttatás tétele segítségével. 29
Az e) feladat során a két szám osztóit tartalmazó halmazok metszetét kell meghatározni. Az f) feladat során a két szám valódi osztóit tartalmazó halmazok metszetét kell meghatározni. Ha a metszethalmaz üres halmaz, akkor a két szám relatív prím. int beolvas() {int szam,ok; do{printf("\nSzam= ");fflush(stdin);ok=scanf("%i",&szam); }while(ok!=1 || szam<1);return szam;} void inic(int *h) {for(int i=0; i<100; i++) {h[i]=0;}} int osztokereses(int *h, int szam) {int i=0, oszto=1; inic(h); while(oszto<=szam) {if(szam%oszto==0) {h[i]=oszto; i++;} oszto++;}return i;} int valodiosztokereses(int *h, int szam) {int i=0, oszto=2;inic(h); while(osztoh2[j]) {h3[k]=h2[j];j++;}} while(h1[i]!=0) {k++;h3[k]=h1[i];i++;} while(h2[j]!=0) {k++;h3[k]=h2[j];j++;}return ++k;} int osztokkozoskereses(int *h1, int n, int *h2, int m, int *h3) {int i=0, j=0, k=0; for(i=0; i
printf("\n *** VALODI OSZTOK ***"); szam1on=valodiosztokereses(szam1osztoi,szam1); szam2on=valodiosztokereses(szam2osztoi, szam2); printf("\n%i osztoi: ",szam1); osztokkiir(szam1osztoi, szam1on); printf("\n%i osztoi: ", szam2); osztokkiir(szam2osztoi, szam2on); mindn= osztokmindkereses(szam1osztoi, szam1on, szam2osztoi, szam2on, osztokmind); printf("\n%i es %i osztoi: ",szam1, szam2);osztokkiir(osztokmind, mindn); kozosn=osztokkozoskereses(szam1osztoi, szam1on, szam2osztoi, szam2on, osztokkozos); printf("\n%i es %i osztoi kozos osztoi: ",szam1, szam2); osztokkiir(osztokkozos, kozosn); if(kozosn==0) {printf("\n%i es %i relativ primek",szam1, szam2);} else {printf("\n%i es %i nem relativ primek",szam1,szam2);}return 0;} 43. ábra. Az 1.3.4.6. feladat programlistája
Írjon olyan programot, amely egy maximum 100 elemű egész típusú tömb leggyakrabban előforduló elemét megkeresi és kiírja a standard outputra! 1.3.4.7.
A megoldás során meg kell határoznunk, hogy a tömb elemei hányszor fordulnak elő, majd kiválasztani a leggyakrabban előforduló elemet. A tömböt növekvő (vagy csökkenő) sorrendbe fogjuk rendezni, ekkor biztosa n egymás mellé fognak kerülni az azonos értékű elemek. A tömb elemeit végigjárva a maximum kiválasztás tétele segítségével kiválasztjuk azt az elemet, amely a legtöbbször előfordul. Amíg a szomszédos elemek egyenlők addig számolunk, ha már nem egyenlők, akkor a darabszámot hasonlítjuk a maxdarabszámhoz. int beolvas(int *t) {int i=0,n; do{printf("\n%i.elem= ",i);scanf("%i",&t[i]);i++; }while(t[i-1]!=0 && i<100); if(i==100) n=i; else n=i-1; return n;} void kiir(int *t,int n) {int i; printf("\nA tomb elemei:\n"); for(i=0; imaxdb {if(db>maxdb) {maxdb=db; db=0; maxi=i;}} }return maxi;} int _tmain(int argc, _TCHAR* argv[]) {int t[100],n; int maxi, maxdb; n=beolvas(t); kiir(t,n); rendez(t,n);kiir(t,n); 31
maxi=leggyakoribb(t,n,maxdb); if(maxdb!=0) printf("\nA leggyakrabban elofordulo elem %i, %i-szor fordul elo",t[maxi],maxdb); else {printf("\nA tomb csak kulonbozo elemeket tartalmaz");}return 0;} 44. ábra. Az 1.3.4.7. feladat programlistája
Írjon olyan progr amot, amely meghatározza egy maximu m 100 elemű egész típusú tömbben előforduló számok gyakoriságát. 1.3.4.8.
A megoldás során meg kell határoznunk, hogy a tömb elemei hányszor fordulnak elő. Célszerű a tömböt növekvő (vagy csökkenő) sorrendbe rendezni, így az egyenlő elemek egymás mellé fognak kerülni. A megszámolást egy gyakoriságmátrixszal fogjuk elvégezni. A mátrix első oszlopában a tömbelem fog szerepelni, a második oszlopában pedig az, hogy az adott tömbelem hányszor fordul elő a tömbben. int beolvas(int *t) {int i=0,n; do{printf("\n%i.elem= ",i);scanf("%i",&t[i]);i++; }while(t[i-1]!=0 && i<100); if(i==100) n=i; else n=i-1; return n;} void kiir(int *t,int n) {int i; printf("\nA tomb elemei:\n"); for(i=0; i
32
1.4.
Önállóan kidolgozandó feladatok C
1.4.1.
Kis programrészletek visszafejtése
Mit adnak eredményül, mit írnak ki a standard outputra a következő programrészletek? void main() {int a=9,b=3; do {if(a>b) {a=a/2;} else {b=b/2;} printf("\na=%d\tb=%d",a,b); }while(a!=b); }
void main() {int x=0,y=1,z=x+y; while(z<=5) {if(z%2!=0) {z=y+z; y++;} else {z=x+z; x++;} printf("\nx=%d y=%d z=%d",x,y,z); } }
void main() {int x,j; x=0; for(j=5;j<15;j=j+3) {x=x+j/3; printf("\nj=%d\tx=%d",j,x);}}
void main() {int a,d=0; for(a=2;a<20;a=a+d,d++) printf("%8d",a); }
Az alábbiakban egy -egy programozási tétel algoritmusát látja benne egy kis hibával! Nevezze meg a programozási tételt! Mi a hiba az alábbi algoritmusban! Indokolja válaszát, támassza alá a válaszát tesztadatokkal. Javítsa ki a hibát! Mutassa meg a tesztadatokkal, hogy jól működik az algoritmus. Valami(s,n,ö) for i do ö
Valami(s,n,T,db)
0 to n ö + s[i]
0 to n for i do if s[i] T tulajdonságú
Valami(s,n,ö)
then db
db+1
ö
0 for i do ö
Valami(s,n,m)
0 to n s[i]
m
Valami(s,n,T,van)
0 while s[i] nem T tulajdonságú do i i+1 van (i
0 for i
do if s[i]>max
i
Valami(s,n,T,van,sorsz)
i
0
while s[i] nem T tulajdonságú do
van if van
i i+1 (i
then sorsz
1 to n
then m
s[i]
Valami(s,n,m)
m
s[0] for i 1 to n do if s[i]>max then max
i
i
33
1.4.2.
Egyszerű programok (egyszerű adattípusok)
1.
Olvasson be a rendszer bemenetéről egy egész számot, írja ki a reciprokát! *
2.
Írjon programot, amely kiszámítja a téglalap kerületét és területét! / bemenő adatok: a,b: a téglalap oldalai /
3.
Írjon programot, amely kiszámítja a téglatest felszínét és térfogatát! / bemenő adatok: a,b,c: a téglatest élei /
4.
Írjon programot, amely kiszámítja az egyenes henger felszínét és térfogatát! / bemenő adatok: r: alapkör sugara ill. M: a henger magassága /
5.
Írjon programot, amely kiszámítja az egyenes körkúp térfogatát! / bemenő adatok: r: alapkör sugara ill. M: a kúp magassága / / V=(r*r*Pi*M)/3 /
6.
Három tetszőleges (beolvasott) számról döntse el, hogy lehetnek -e egy háromszög oldalai (szerkeszthető-e háromszög)!
7.
Készítsen algoritmust, amely kiszámítja egy háromszög kerületét és területét a HERON képlet segítségével! T=négyzetgyök((s*(s -a)*(s-b)*(s-c)); s=kerület/2*
8.
Készítse el a másodfokú egyenlet megoldó képlete alapján azt a programot, amely meghatározza egy tetszőleges másodfokú egyenlet valós gyökeit!
9.
Állítsa elő a Fibonacci-sorozat 1000-nél kisebb elemeit! A Fibonacci-sorozat eleje: 0, 1, 1, 2, 3, 5, 8, 13,… A sorozatban az első kettőt kivéve, bármely elem a megelőző kettő összegeként áll elő. Írja ki a képernyőre a sorozattagokat!
10. Olvasson be a rendszer bemenetéről egész számokat 0 végjelig, és írja
ki az átlagukat! *
11. Határozza
meg a páratlan számok összegét a -tól b-ig! (a és b bármelyike lehet páros vagy páratlan szám.) Írja ki az eredményt! *
12. Olvasson
be a klaviatúráról 2 pozitív egész számot, A -t és B-t! Írja ki a képernyőre az A és B közötti 7-tel osztható páros számokat csökkenő sorrendben! (A és B egyaránt lehet páros és páratlan is.) Végül írja ki a darabszámot is!
13. Írjon programot, amely meghatározza Euklidesi algoritmussal!* 14. Írjon programot, amely
két természetes szám legnagyobb közös osztóját
megadja két egész szám legkisebb közös többszörösét.
15. Írjon programot, amely eldönti egy számról, hogy
prím -e?
16. Írjunk
programot, amely két 1 -nél nagyobb, egymástól különböző természetes számról eldönti, hogy azok relatív prímek -e! Két szám relatív prím, ha egy közös valódi osztójuk sincs. (Egy szám valódi osztóinak nevezünk minden olyan osztót, amely nem 1 és nem maga a szám.)
17. Olvasson
be a rendszer bemenetéről egész számokat 0 végjelig! Határozza meg a beolvasott negatív számok összegét és darabszámát!
34
18. Olvasson
be a klaviatúráról egész számokat 0 végjelig! Adja meg a páros elemek darabszámát!
19. Határozza
meg az 1 -1000-ig terjedő intervallumban azoknak a természetes számoknak az átlagát, amelyek oszthatók 3 -mal!
20. Állítsa
elő és írassa ki a számtani sorozat első 10 tagját az első elem és a differencia beolvasása után!
21. Állítsa
elő és írassa ki a mértani sorozat első 10 tagját az első elem és a hányados beolvasása után! Figyeljen a túlcsordulásra!
22. Határozza meg egy szám osztóinak a
számát! Olvassa be a számot, írja ki az osztóit, végül
az osztók számát is! 23. Határozza
meg egy szám összes többszörösét, melyek nem nagyobbak, mint 100! Olvassa be a számot, majd írja ki a többszöröseit 100 -ig!
24. Írjon
olyan programot, amely az 1000 alatti prímszámokat kiírja a standard outputra! A kiírás táblázatos formában, egy sorba több számot írva történjen!
25. Olvasson
be a klaviatúráról 10 egész számot, majd írja ki a képernyőre a legnagyobb beolvasott számot, és azt is, hogy hányadikként olvasta be!
26. A
hőmérsékletet Celsius -fokban és Fahrenheit -fokban szokás megadni. A kettő közötti összefüggést a következő képlet adja meg: C=(5/9)*(F-32). Írjon olyan programot, amely elvégzi az átszámítást, ha a Fahrenheit-fokban megadott hőmérséklet 0 -tól 300-ig 20 fokonként változik! A Fahrenheit - ben és a hozzátartozó Celsius - ban kapott hőmérséklet értékeket táblázatos formában írja ki a képernyőre! A feladatot mindhárom ciklussal oldja meg!
27. Számolja
ki PI értékét az alábbi végtelen sorozat 100 tényezőjének figyelembevételével! PI/2=2/1*2/3*4/3*4/5*6/5*6/7*8/7*8/9*.... Az eredményt írja ki a képernyőre! *
28. Egy gyerek a szüleitől P Ft zsebpénzt kapott. Az első napon 10 Ft -ot költött, majd ezután minden nap 5 Ft- tal többet. Hány napig tudta ezt a költekezést folytatni, és mennyi „töredék” pénze maradt? A P -t olvassa be, az eredményt írja ki! * 29. Írjon
olyan programot, amelyben ellenőrzéssel beolvas a klaviatúráról legalább kétjegyű pozitív egész számokat, majd minden egyes szám beolvasása után kiírja a képernyőre a szám fordítottját!
30. Olvasson be egy 0- val
végződő, egészekből álló számsorozatot, írja ki a beolvasott legnagyobb számot és annak sorszámát is!
31. Készítsen
programot, amely az összes olyan háromjegyű páratlan természetes számot kiírja a képernyőre növekvő sorrendben, amely különböző számjegyekből áll!
32. Írjon
programot, amely nullától különböző egész értékeket olvas be a billentyűzetről a 0 végjelig. A program határozza meg és írja képernyőre azt a három értéket, amelynek átlaga maximális. 35
33. Írjon
olyan programot, amely egy beolvasott műveleti jel (| / !) alapján számol abszolút értéket, reciprokot, faktoriálist! A műveletek operandusát is olvassa be! A beolvasásokat ellenőrizze! (Használjon switch -case szerkezetet!)
34. Összegezze
egy dominókészlet pontjait és írja ki az eredményt a képernyőre! (A dominó legnagyobb értékű darabja a 8 -8.)
1.4.3. Egydimenziós tömbök (vektorok), karaktertömbök 35. Olvasson be 0 végjelig egész számokat egy egydimenziós tömbbe! * Adja meg a tömb elemeinek átlagát! Döntse el, hogy van -e páros elem a tömb elemei között! Adja meg az első páros elem indexét! Adja meg a páros elemek darabszámát! Adja meg a legkisebb és a legnagyobb elemet, valamint ezen elemek sorszámát! 36. Olvasson be legfeljebb 20 kétjegyű egész számot! Nem kétjegyű szám esetén fejezze be a
bevitelt! Írja ki, hogy hány számot olvasott, majd sorolja fel külön a páros és a páratlan számokat! 37. Olvasson
be a klaviatúráról egész számokat 0 végjelig! Adja meg a páratlan elemek
átlagát! 38. Olvasson be
0 végjelig egész számokat egy egydimenziós tömbbe! Adja meg a páros értékű elemek átlagát és darabszámát!
39. Töltsön
fel véletlen számokkal egy 20 elemű tömböt! Adja meg a tömb legkisebb és legnagyobb elemének indexét és értékét!
40. Töltsön
fel véletlen számokkal egy 10 elemű tömböt! Döntse el, hogy van -e 3-mal osztható a tömb elemi között! Ha van, adja meg az első 3 -mal osztható elem sorszámát! Adja meg, hogy hány db 3 -mal osztható elem van a tömb elemei között!
41. Töltsön fel egy 10 elemű egész típusú tömböt véletlen -szám generátorral, Ezután írja ki az
elemeket a képernyőre egy sorban, majd külön sorban a páratlan elemek számát is! 42. Töltsön
fel egy 10 elemű egész típusú tömböt a klaviatúráról történő beolvasással! Állapítsa meg, hogy a tömb elemei szigorúan monoton növekvő sorozatot alkotnak -e, majd az eredményről megfelelő szöveges üzenetet írjon a képernyőre!
43. Töltsön
fel két 10 elemű vektort véletlenszám generátorral! Írja ki a tömbök tartalmát, majd a két vektor skaláris szorzatát a képernyőre!
44. Készítsen
programot, mely egy 20 elemű vektor elemeit 1 hellyel előre mozgatja, és az első elem az utolsó helyre kerül. A feltöltést véletlenszám generátorral oldja meg, majd írja ki az eredeti és az új vektort!*
45. Írjon
olyan programot, amely egy 10 elemű egész típusú tömb elemeiről eldönti, hogy számtani sorozatot alkotnak -e! A tömböt a klaviatúráról történő beolvasással töltse fel, majd a megfelelő szöveges üzenetet írja ki a képernyőre! *
36
46. Töltsön fel egy 10 elemű egész típusú tömböt véletlenszám generátorral, úgy, hogy csupa
különböző eleme legyen. Ezután írja ki az elemeket a képernyőre. * 47. Írjunk
programot, amely a billentyűzetről egész értékeket olvas be a 0 végjelig! A program írja képernyőre azokat az értékeket, amelyek megegyeznek az előző két érték összegével!
48. K szám
keresése. Olvasson be egy n és m természetes számot. Keressük meg azt a természetes k számot, melyre: nk -1 m! nk
49. Inicializáljon
egy char típusú tömböt (sztringet) a saját nevével, majd írja ki a tömb elemeit karakterenként új sorba!
50. Olvasson be egy karaktersorozatot (sztringet) ’Enter ’
karakterig! Keresse meg az első
számjegy karaktert! 51. Olvasson be egy karaktersorozatot (sztringet) ’Enter ’ karakterig! Fordítsa meg a sztringet! 52. Olvasson be egy karaktersorozatot (sztringet) sztingben?
’Enter ’ karakterig! Van ’a’ betű a
53. Olvasson be egy karaktersorozatot (sztringet) ’Enter ’ karakterig! Vizsgálja meg, hogy palindrom-e! (Palindrom az a szöveg vagy szám, amely fordítva olvasva is ugyanaz.
Például: kerek vagy 13631.) * 1.4.4. Gyakorisági tömbök 54. Készítsen statisztikát kocka dobálás eredményeiről! A lehetséges dobás értékek: 1, 2, 3, 4, 5, 6. Minden kocka- dobást véletlenszám -generátorral oldjon meg! A számlálást gyakoriság tömb alkalmazásával végezze el, majd az eredményt áttekinthető formában írja ki a képernyőre!* 55. Írjon programot,
amely statisztikát készít a standard bemeneten beolvasott számokban előforduló számjegykarakterekről. A program számjegyenként írja ki, hogy melyik számjegy hányszor fordult elő. Ügyeljen rá, hogy nem csak számjegyek fordulhatnak elő. *
56. Készítsen
osztályzási statisztikát! Olvasson be a billentyűzetről osztályzatokat ellenőrzéssel. Készítsen statisztikát, hogy hány db 1 -es, 2-es, stb. született. Gyakoriság i tömbbel dolgozzon!
57. Olvasson
be a billentyűzetről max. 100 db egész számot. Gyakoriságtömb segítségével számolja meg, hogy hány pozitív, hány negatív és hány 0 eleme van a tömbnek!
58. Írjunk
programot, amely a billentyűzetről látható karaktereket olvas ’ Enter ’ végjelig! A program határozza meg és írja képernyőre a beolvasott különböző karaktereket és azok gyakoriságát!
59. Készítsen
programot, amely az összes olyan háromjegyű páratlan természetes számot kiírja a képernyőre növekvő sorrendben, amely különböző számjegyekből áll!
60. Készítsen programot, amely meghatározza egy sztringben lévő a,b,c,d,e,…,z karakterek előfordulásának gyakoriságát, majd a képernyőre írja ki az eredményt! 37
1.4.5. Kétdimenziós tömbök, mátrixok 61. Írjon olyan programot, amely véletlen számokkal feltölt egy 10*5 -ös mátrixot, és mátrix alakban kiírja a képernyőre! 62. Kétdimenziós
tömb alkalmazásával oldja meg a következő feladatot: Egy 10 fős tanulócsoport 6 tantárgyból szerzett osztályzatait kell feldolgozni. Ellenőrzött bevitellel vagy véletlenszám generátorral töltsük fel a 10*6 -os tömböt úgy, hogy minden tanuló esetében a tantárgyak sorrendje ugyanaz. Az osztályzatokat tanulónként kérjük be. A tanulókat és a tantárgyakat is sorszámmal azonosítjuk. A bevitt osztályzatokat mátrix alakban jelenítsük meg, úgy, hogy egy sorban egy tanuló osztályzatai legyenek, a sor végén a tanuló tanulmányi átlagával. Utolsó sorként írjuk ki a tantárgyak átlagát a tanulócsoportban!*
63. Töltsön
fel véletlen szám generátorral egy M*N -es mátrixot! Készítse el a mátrix transzponáltját!*
64. Töltsön fel véletlen szám szimmetrikus-e a mátrix?*
generátorral egy M*N -es mátrixot! Döntse el, hogy
65. Készítsen
Hilbert mátrixot! A Hilbert mátrix bármely eleme az elem sor - és oszlopindexének összege. Jelenítse meg a képernyőn a mátrixot!
66. Készítsen számokkal
olyan programot, amely feltölt egy négyzetes mátrixot páratlan egész véletlenszám generátor alkalmazásával; majd 0 -val helyettesíti a mátrix azon elemeit, melyek a főátlóban álló legnagyobb és legkisebb szám által meghatározott intervallumon kívül esnek.
67. Egy
egész típusú négyzetes mátrixot úgy töltsön fel, hogy minde n elem a sor- és oszlopindexének szorzata legyen! Ezután jelenítse meg az elemeket sorfolytonosan mátrix alakban, majd tükrözze a mátrix elemeit a főátlóra és az így kapott új tömböt is jelenítse meg ugyancsak mátrix alakban!
68. Írjon
olyan programot, amely: egy négyzetes mátrixot feltölt páratlan egész számokkal véletlen szám generátor alkalmazásával; 0 -val helyettesíti a mátrix azon elemeit, amelyek a főátlóban álló legnagyobb és legkisebb szám által meghatározott intervallumon kívül esnek; az így keletkezett mátrixot megjeleníti a képernyő n sorfolytonosan, táblázatos formában.
1.4.6. Függvények, paraméterátadás 69. Egy ellenőrzéssel beolvasott pozitív egész számról döntse el, hogy prímszám -e! A vizsgálatot függvénnyel végeztesse el, amely az eredményt „logikai érték” visszaadásával jelzi a főprogramnak! A szöveges üzenetet a főprogram írja ki a képernyőre! * 70. Olvasson
be ellenőrzéssel a klaviatúráról 2 pozitív egész számot, majd határozza meg a legnagyobb közös osztójukat! A legnagyobb közös osztó meghatározását függvénn yel végeztesse el, amely azt visszaadja a hívónak! Az eredményt a főprogram írja ki a képernyőre!
38
71. Írjon
olyan programot, amely egy 10 elemű egész típusú tömb legnagyobb elemét kiválasztja és kiírja a képernyőre! A tömböt a klaviatúráról történő beolvasással töltse fel! A legnagyobb elem kiválasztását függvénnyel végeztesse el, amely azt visszaadja a hívónak.*
72. Töltsön fel egy 10 elemű egész típusú tömböt a billentyűzetről
történő beolvasással, majd állapítsa meg, hogy a tömbelemek szigorúan monoton növekvő sorozatot alkotnak-e! Az eredményről írjon szöveges üzenetet a képernyőre! A szöveges üzenet kiírása egy függvény által visszaadott érték szerint történjen!
73. Töltsön
fel egy 10 elemű egész típusú tömböt véletlenszám generátorral, és írja ki a tömbelemeket a képernyőre! Ezután olvasson be egy egész számot, és a lineáris keresés algoritmusát alkalmazva állapítsa meg, hogy ez a szám előfordul -e a tömbelemek között! A lineáris keresést függvénnyel végeztesse el, amely a keresés eredményét logikai érték visszaadásával jelzi a főprogramnak! A szöveges üzenetet a főprogram írja ki a képernyőre!
74. Írjon
olyan egész értékű függvényt, amely egy paraméterként megadott kezdőcímű és elemszámú egész típusú vektorban megkeresi a legnagyobb számot, és ez t adja vissza a főprogramnak!*
75. Írjon
olyan érték nélküli függvényt, amely egy paraméterként megadott kezdőcímű és elemszámú egész típusú vektor elemeit segéd tömb használata nélkül csökkenő sorrendbe rendezi!
76. Írjon
függvényt annak megállapítására, hogy egy paraméterként megadott előjelnélküli egész számban van -e számjegyazonosság, és az eredményt megfelelő érték visszaadásával jelezze a főprogramnak!
77. Írjon
olyan egészértékű függvényt, amely egy paraméterként megadott kezdőcímű és elemszámú egész típusú tömb elemeiről eldönti, hogy számtani sorozatot alkotnak -e!
78. Írjon
olyan egész értékű függvényt, amely egy paraméterként megadott kezdőcímű sztringben a szomszédos karakterek azonosságát megszünteti! A visszaadott érték az új sztring hossza legyen. A feladatot segéd sztring használata nélkül oldja meg! (Például: „Asswerrt 3455cvvvx” esetén az új sztring: „Aswert 2345cvx” és a visszaadott érték: 14 .)
79. Írjon olyan programot, amely egy a klaviatúráról beolvasott sztringről megállapítja, hogy tartalmaz-e decimális számjegy karaktert, majd az eredményről írjon megfelelő szöveges
üzenetet a képernyőre! A vizsgálatot függvénnyel végeztesse el, amely a sztringet paraméterként kapja, az eredményt pedig logikai érték visszaadásával jelzi a hívónak! 80. Készítsen
egy függvényt, amely egy egész számot átalakít egy adott számrendszerbeli sztringgé! A függvény első paramétere az átalakítandó szám, második paramétere a számrendszer alapja, a visszatérési érték pedig az eredmény sztring. A számrendszer alapszáma a 2, . . . , 35 intervallumba esik.
81. Írjon
eljárást, amely paraméterként megkap egy karaktereket tartalmazó, tetsző leges méretű egydimenziós tömböt, és a tömb nem betű karaktereit kicseréli szóközre. 39
82. Írjon eljárást, amely
paraméterként megkap egy tetszőleges méretű, sztringeket tartalmazó vektort, és előállít egy olyan vektort, amely nek elemei rendre a paraméterként kapott vektor elemeinek annyiadik karakterét tartalmazzák, amennyi az adott elem indexe, illetve a @ karaktert, ha nem létezik ilyen elem. Egy sztring karaktereit 0 -tól sorszámozzuk.
83. Írjon olyan függvényt, amely megállapítja, hogy egy paraméterként kapott sztringben benne van-e egy másik, szintén paraméterként kapott sztring! A főprogram beolvassa a
sztringeket a klaviatúráról, majd a függvény által visszaadott eredmény szerint üzenetet ír a képernyőre. Ha előfordul, akkor a kezdő indexet kimenő paraméterben adja vissza a függvény a hívónak. * 84. Olvasson be a billentyűzetről ellenőrzéssel egy pozitív egész számot. Állapítsa meg, hogy van-e benne számjegy azonosság, majd erről írjon megfelelő szöveges üzenetet a
képernyőre! Ha van számjegy azonosság, írja ki, hogy melyik a leggyakrabban előforduló számjegy érték! Több azonos előfordulás esetén a legkisebb jegy értékét írja ki. A feladatot gyakorisági tömb alkalmazásával oldja meg! A főprogram az ellenőrzött bevitelt és az eredmény kiírását végezze el. A beolvasott pozitív szám vizsgálatát egy függvény végezze el 85. Írjunk
logikai függvényt, amely egy paraméterként megkapott, sztringeket tartalmazó négyzetes mátrixról eldönti, hogy szimmetr ikus-e!
86. Írjon
eljárást, amely egy paraméterként kapott tetszőleges méretű, egészeket tartalmazó egydimenziós tömbben meghatározza a legnagyobb összegű résztömb kezdő - és végindexét két kimenő paraméterében!
87. Készítsen olyan C++ programot, amely kiválasztja
egy pozitív egész számokat tartalmazó vektorból azt a számot, amelyben a számjegyek átlaga a legkisebb!
88. Készítsen
olyan programot, amely egy természetes számot felbont törzstényező inek szorzatára! A számot olvassa be, az eredményt írja ki!
A *-gal jelölt
40
feladatok megoldásai megtalálhatók a jegyzetben.
2.
Kidolgozott feladatok ASM programozásra
2.1.
Adatmozgató, aritmetikai és vezérlésátadó utasítások 7
Készítsen progr amot, amely eghatározza 2 db bájtos memóriaváltozó összegét, az eredményt tárolja egy szavas a) m memória változóban! eghatározza egy szavas és egy bájtos memóriaváltozó különbségét, az eredményt b) m el tárolja egy szavas memóriaváltozóban! 2.1.1.
Az Intel assembly programozási példák tanulmányozásához szükség lesz egy un. kódtáblára, amely megtalálható a jelen fájllal azonos könyvtárban AsmKodtabla.pdf néven (ha a link nem működik, kérem keresse meg a fájlt az adott útvonalon !). Az Intel assembly programozás során szavas regiszterek állnak rendelkezésünkre. Az Intel 8086/88 mikroprocesszor regiszterkészlete a 46. ábrán látható. Ezek a szavas regiszterek bájtos regiszterekként is használhatók (pl. AX szavas regiszter alsó bájtja, mint bájtos regiszter AL, felső bájtja, mint bájtos regiszter AH). Az utasítások során az operandusok típusának meg kell egyeznie. Pl. bájtos operandushoz bájtos operandust adhatunk hozzá. Következésképpen bájtos operandushoz szavas operandust hozzáadva hibát kapunk (hiszen az eredmény valószínűleg nem fér el 1 bájton), de szavas operandushoz bájtos operandust hozzáadhatunk adatvesztés nélkül (ekkor is warning figyelmeztető üzenetet fogunk kapni), de az eredményünk helyes lesz. Van egy un. flag regiszter, amely jelzőbiteket tartalmaz. Az I8086 assembly program szegmentált felépítésű. Minden program tartalmazni fog egy INT 21H utasítássort. Az INT (interrupt) egy szoftveres megszakítást generál, az INT 21H hatására egy (DOS szintű) szubrutingyűjtemény kerül meghívásra. Hogy melyik szubrutin fog végrehajtásra kerülni, azt a funkciókód (amit általában az AH regiszterbe töltünk) dönti el. Ha a funkciókód 4CH, ak kor a vezérlés visszaadódik az operációs rendszernek.
46. ábra. Az Intel 8086/88 7
mikroprocesszor regiszterkészlete
AsmKodtabla 3.-5. és 10.-12. oldal
41
ADAT A B EW D DK ADAT KOD
SEGMENT ;ADAT SZEGMENS KEZDETE DB 2 ;BÁJTOS MEM.VÁLTOZÓ DB 6 DW ? ;SZAVAS MEM.VÁLTOZÓ DW 200 DW ? ENDS ;ADAT SZEGMENS VÉGE SEGMENT ;KOD SZEGMENS KEZDETE ASSUME DS:ADAT, CS:KOD START: MOV AX,ADAT;A DS SZEGMENS REGISZTERBE BETÖLTJÜK AZ MOV DS,AX ;ADATSZEGMENS KEZDŐCÍMÉT MOV AX,0 MOV AL,A ;AZ A MEM.OP-OT AL REGISZTERBE TÖLTJÜK ADD AL,B ;AL-HEZ HOZZÁADJUK B MEM.OP -OT MOV EW,AX ;AZ EREDMÉNYT SZAVASAN KI MOZGATJUK MOV AX,D ;AX-BE BETÖLTJÜK A DK SZAVAS MEM.OP -OT MOV BH,0 MOV BL,A ;A BL-BE BETÖLTJÜK A BÁJTOS A MEM.OP -OT SUB AX,BX ;SZÓT SZÓBÓL VONUNK KI MOV DK,AX ;AZ AX-ET (AZ ELŐZŐ KIVONÁS EREDMÉNYÉT ;KIMOZGATJUK A DK SZAVAS MEM.OP-BA) MOV AH,4CH ;AZ AH-BA 4CH-T TÖLTÜNK INT 21H ;A PROGRAM LOGIKAI VÉGE, VISSZAADJUK A VEZÉRLÉST AZ OP. ;RENDSZERNEK KOD ENDS ;KOD SZEGMENS VÉGE END START ;A PROGRAM FIZIKAI VÉGE 47. ábra. A 2.1.1. feladat programlistája
Készítsen programot, amely a) 2 db memóriában tárolt bájtos adat szorzatát képezi, az eredményt eltárolja a memóriában! b) 2 db memóriában tárolt bájtos adat hányadosát képezi, az eredményt (a hányadost és a maradékot) letárolja a memóriában! 2.1.2.
A megoldás során a MUL és a DIV utasítást alkalmazzuk. Ez a két utasítás látszólag egyoperandusú utasítás. A másik operandus rejtett operandus. Mindkét műveletnek van bájtos és szavas változata is. Hogy melyik változatról van szó, azt az operandus típusa dönti el. ADAT A B SZW D DK H M ADAT KOD
SEGMENT DB 2 ;BÁJTOS MEM.VÁLTOZÓ DB 6 DW ? ;SZAVAS MEM.VÁLTOZÓ DW 200 DW ? DB ? DB ? ENDS SEGMENT ASSUME DS:ADAT, CS:KOD START: MOV AX,ADAT;A DS SZEGMENS REGISZTERBE BETÖLTJÜK AZ MOV DS,AX ;ADATSZEGMENS KEZDŐCÍMÉT MOV AL,A ;BÁJTOS SZORZÁS (AL)*(B) AZ EREDMÉNY AZ MUL B ;AX-BEN KÉPZŐDIK MOV SZW,AX MOV AX,0 MOV AL,A ;BÁJTOS OSZTÁS (AX)/(B) AZ EREDMÉNY DIV B ;AL-BEN A HÁNYADOS, AH -BAN A MARADÉK LESZ MOV H,AL 42
MOV MOV INT KOD
M,AH AH,4CH ;4CH FUNKCIÓKÓD BETÖLTÉSE AZ AH REGISZTERBE 21H ;A PROGRAM LOGIKAI VÉGE, VISSZADJUK A VEZÉRLÉST AZ OP. ;RENDSZENEK
ENDS END START 48. ábra. A 2.1.2. feladat
Készítsen programot, amely a memóriában tárolt 10 bájtos adat (tömb elemeinek) összegét képzi, és az eredményt letárolja szavasan a memóriában. 2.1.3.
Az algoritmusban bájtos adatokat fogunk összeadni, de az eredményt egy szón (16 biten) tároljuk. Az eredmény is lehetne bájtos adat, de ekkor nagy valószínűséggel túlcsordulás lépne fel. Ezt próbáljuk elkerülni úgy, hogy az eredményt egy szón tároljuk. A megoldás során a halmozott összegképzést (az összegzés tételét) alkalmazzuk. Indexelt címzést használunk, a 0. adat címéhez képesti eltolást mindig az SI indexregiszter fogja mutatni. Az assembly programozás során is van lehetőségünk ciklusok írására. Ciklust vezérlésátadó, ugró utasításokkal tudunk készíteni. Az ugró utasítások között kitüntetett szerepe van a LOOP utasításnak. A LOOP utasítással egy hátul -tesztelő ciklust tudunk készíteni. A LOOP automatikusan csökkenti (dekrementálja) a CX tartalmát, és ha a CX nem 0, akkor visszaugrik a megadott címkére, vagyis annyiszor hajtódik végre a ciklusmag, amennyi a CX értéke. ADAT T OSSZ ADAT KOD
SEGMENT DB 20,-11,26,30,45,-20,-65,125,45,68 DW ? ;A SZÁMOK ÖSSZEGE ENDS SEGMENT ASSUME DS:ADAT, CS:KOD START: MOV AX,ADAT MOV DS,AX MOV OSSZ,0 ;AZ ÖSSZEG KINULLÁZÁSA ;CIKLIKUSAN ÖSSZEADJUK A SZÁMOKAT MOV CX,10 ;CIKLUS SZÁMLÁLÓ, ITT A TÖMB ELEMEINEK A SZÁMA MOV SI,0 ;AZ ADOTT ELEM INDEXE MOV AH,0 CIKL: MOV AL,T[SI];INDEXELT CÍMZÉS. AZ AL-BE BETÖLTJÜK AZ ;ÉPPEN HOZZÁADANDO BÁJTOS SZÁMOT ADD OSSZ,AX ;SZAVAS ÖSSZEADÁS INC SI ;INDEX NÖVELÉSE LOOP CIKL ;CX CSÖKKENTÉSE, HA CX NEM 0, AKKOR UGRIK A CIKL CIMKÉRE MOV AH,4CH INT 21H ;VISSZADJUK A VEZÉRLÉST AZ OP. RENDSZERNEK KOD ENDS END START 49. ábra. A 2.1.3. feladat
Készítsen olyan programot, amely a memóriában letárolt 10 db bájtos adat közül meghatározza a legnagyobb elemet! 2.1.4.
Ebben az algoritmusban a maximum kiválasztás tételét alkalmazzuk. A megoldás során feltételezzük, hogy a 0. elem a legnagyobb. Ezt megjegyezzük egy MAX nevű változóba. A tömb többi elemét ehhez a változóhoz hasonlítjuk. 43
Ha találunk nagyobb elemet, akkor ezt megjegyezzük. Ebben a programban használjuk a CMP (compare) utasítást. A CMP célop, forrásop utasítás összehasonlítja a két operandus tartalmát, és az eredménytől függően állítja a flageket. Pl. ha a két operandus egyenlő, akkor a Zéró flag (ZF) 1 lesz. A példában szereplő JLE címke utasítás egy feltételes ugró utasítás. Akkor ugrik a megadott címkére, ha az előző CMP utasítás eredménye az volt, hogy céloperandus kisebb vagy egyenlő a forrásoperandusnál. ADAT T MAX ADAT KOD
SEGMENT DB 23, -10, 25, 31, 46, -21, -65, 125, 40, 67 DB ? ;AZ AKTUÁLIS LEGNAGYOBB ELEM ENDS SEGMENT ASSUME DS:ADAT, CS:KOD START: MOV AX,ADAT MOV DS,AX MOV SI,0 ;TÖMBINDEX LESZ MOV AL,T[SI] ;A TÖMB 0. ELEMET BETÖLTJÜK A MAX MOV MAX,AL ;VÁLTOZÓBA MOV CX,9 ;CIKLUSSZÁMLÁLÓ, A TÖMB ELEMEINEK SZÁMA INC SI ;INDEX NÖVELÉSE CIKL: MOV AL,T[SI] ;HASONLÍTJUK A TÖMB AKTUÁLIS ELEMÉT AZ CMP AL,MAX ;EDDIGI LEGNAGYOBB ELEMHEZ JLE TOV ;HA <=, AKKOR NINCS TEENDŐNK, UGRUNK MOV MAX,AL ;HA (AL)>MAX, AKKOR MEGJEGYEZZÜK TOV: INC SI ;INDEX NÖVELÉSE LOOP CIKL ;HA CX NEM 0 (VAN MÉG TÖMBELEM), UGRÁS A CIKL. CIMKÉRE MOV AH,4CH INT 21H ;VISSZADJUK A VEZÉRLÉST AZ OP. RENDSZERNEK KOD ENDS END START 50. ábra. A 2.1.4. feladat programlistája
Adott egy 10 bájtos tömb feltöltve. Másolja át egy 10 szavas tömbbe a bájtos tömb elemeit fordított sorrendben! A megoldás során két indexregisztert alkalmazunk. Az SI -vel a bájtos tömböt (kezdőértéke 0) indexeljük, a DI-vel a szavas tömböt (kezdőértéke 18) indexeljük. Ciklus segítségével töltjük át az elemeket, az SI-t 1-el növeljük (inkrementáljuk ), a DI-t 2-vel csökkentjük (dekrementáljuk ) (mivel szavas a tömb) egy -egy tömbelem áthelyezése után. 2.1.5.
ADAT TB TW ADAT KOD
SEGMENT DB 23, -10, 25, 31, 46, -21, -65, 125, 40, 67 DW 10 DUP(0) ENDS
SEGMENT ASSUME DS:ADAT, CS:KOD START: MOV AX,ADAT MOV DS,AX MOV CX,10 ;CIKLUSSZÁMLÁLÓ, ITT A TÖMB ELEMEINEK A SZÁMA MOV SI,0 ;SI ELÖLRŐL FOG INDEXELNI MOV DI,18 ;DI HÁTULRÓL FOG INDEXELNI MOV AX,0
44
CIKL:
KOD
MOV MOV INC DEC DEC LOOP MOV INT ENDS END
AL,TB[SI] TW[DI],AX SI ;INDEX NÖVELÉSE DI ;TW SZAVAS TÖMB, EZÉRT AZ INDEXET 2 -SÉVEL DI ;KELL MOZGATNI CIKL ;UGRÁS A CIKL CIMLÉRE, HA VAN MÉG TÖMBELEM AH,4CH 21H ;A PROGRAM LOGIKAI VÉGE START 51. ábra. A 2.1.5. feladat programlistája
Adott egy 10 szavas tömb feltöltve. A tömb minden elemét ossza el 5- tel, és a hányadosokat egy tömbben helyezze el! 2.1.6.
A megoldás során (mivel szavas adatot kell osztanunk) célszerűen bájtos osztást fogunk használni. Ciklikusan az AX regiszterbe betöltjük az osztandó tömbelemet, elosztjuk 5 -el (egy 5 értékű bájtos memóriaoperandussal). A hányados az AL regiszterben lesz, ezt kimozgatjuk a H nevű bájtos tömbünk aktuális elemébe. Mivel egy szavas és egy bájtos tömböt kell kezelnünk, célszerű két külön tömbindexet alkalmazni. A bájtos tömb indexét 1 -el, a szavas tömb indexét 2-el kell léptetnünk. ADAT T H OT ADAT KOD
SEGMENT DW 23, 10, 25, 31, 46, 21, 65, 125, 40, 67 DB 5 DUP(0) DB 5 ENDS SEGMENT ASSUME DS:ADAT, CS:KOD START: MOV AX,ADAT MOV DS,AX MOV CX,10 ;CIKLUSSZÁMLÁLÓ, ITT A TÖMB ELEMEINEK A SZÁMA MOV SI,0 ;SI A T TÖMBÖT INDEXELI MOV DI,0 ;DI A H TÖMBÖT INDEXELI CIKL: XOR AH,AH ;AH kinullázása MOV AX,T[SI] DIV OT ;BÁJTOS OSZTÁS MOV H[DI],AL ;HÁNYADOSOK KIMOZGATÁSA EGY TÖMBBE INC SI ;INDEX NÖVELÉSE INC SI INC DI LOOP CIKL ;UGRÁS A CIKL CIMKÉRE, HA VAN MÉG TÖMBELEM MOV AH,4CH INT 21H KOD ENDS END START 52. ábra. A 2.1.6. feladat programlistája
Adott egy 10 bájtos tömb feltöltve. Rendezze át a tömbelemeket úgy, hogy minden elem 1 hellyel előrelép, és az első elem a tömb utolsó helyére kerül! 2.1.7.
A megoldás során a tömb 0. elemét kimozgatjuk egy segédváltozóba, majd ciklikusan a tömb i. elemét felülírjuk az i+1. elemmel. A ciklus lefutása után az utolsó elem helyére bemozgatjuk a segédváltozóba kimentett 0. elemet. 45
ADAT T ADAT KOD
SEGMENT DB 1,2,3,4,5,6,7,8,9,10 ENDS SEGMENT ASSUME DS:ADAT, CS:KOD START: MOV AX,ADAT MOV DS,AX MOV BL,T[0] ;A 0. ELEM ELMENTÉSE MOV SI,0 ;TÖMBINDEX MOV CX,9 ;CIKLUSSZÁMLÁLÓ CIKL: MOV AL,T[SI+1] MOV T[SI],AL ;AZ SI+1.ELEM A SI. HELYRE KERÜL INC SI LOOP CIKL MOV T[9],BL ;AZ UTOLSÓ ELEM HELYÉRE BEMOZGATJUK ;A 0. ELEMET MOV AH,4CH INT 21h KOD ENDS END START 53. ábra. A 2.1.7. feladat programlistája
2.2.
Bitműveletek, logikai utasítások 8
Készítsen programot, amely meghatározza, hogy a memóriában letárolt 10 bájtos adat (tömb) elemei között hány db páros elem van! 2.2.1.
Ebben az algoritmusban a megszámolás tételét alkalmazzuk. A megoldás során az adatokat egyesével vizsgáljuk, megnézzük, hogy páros -e. Ha igen, akkor egy változót (PDB) megnövelünk 1 -el. Ha egy szám páros, akkor az utolsó bitje biztosan 0. Ebben a példában a TEST op,maszk utasítást használjuk. A TEST utasítás bitenkénti logikai „és” (AND) műveletet végez, az eredménytől függően állítja a flageket. A példánkban a vizsgált tömbelemet (amit betöltünk az AL regiszterbe) logikai „és” kapcsolatba hosszuk 01H -val. Ha a tömbelem legkisebb helyiértékű bitje 0 volt, akkor a TEST utasítás után 0 lesz az AL tartalma. Ekkor páros a vizsgált tömbelem. A logikai utasítások két operandussal rendelkeznek. Az utasítások a két operandussal bitenként végzik el a megadott logikai műveletet. Az eredmény az első operandus helyén keletkezik. Az AND utasítás bitenkénti „és”, az OR bitenkénti „vagy”, az XOR bitenkénti „kizáró vagy” műveletet végez. A NOT utasítás (tagadás) egyoperandusú művelet, a biteket ellentettjükre változtatja (egyes komponens). ADAT T PDB KETTO ADAT
8
SEGMENT DB 23,-10,25,31,46,-21,-65,125,40,67 DB ? ;A PAROS ELEMEK DARABSZAMA DB 2 ENDS
AsmKodtabla 7. oldal 46
KOD
SEGMENT ASSUME DS:ADAT, CS:KOD START: MOV AX,ADAT MOV DS,AX ;CIKLIKUSAN MEGVIZSGALJUK AZ ELEMEKET, HOGY AZ UTOLSÓ BIT 0 -E? MOV CX,10 ;CIKLUSSZÁMLALO MOV SI,0 ;INDEX MOV PDB,0 CIKL: MOV AH,0 ;AH-ba 0 AZ OSZTAS MIATT AX TARTALMA MEGVALTOZIK MOV AL,T[SI] TEST AL,01H ;LOGIKAI ÉS KAPCSOLAT 01H -VAL, HA AZ ;UTOLSÓ BIT 0, AKKOR 0 AZ EREDMÉNY JNZ TOV ;HA NEM 0 (ZF=0), AKKOR UGRAS INC PDB ;PÁROS, DB SZAMLALO NOVELESE TOV: INC SI LOOP CIKL MOV AH,4CH INT 21H KOD ENDS END START 54. ábra. A 2.2.1. feladat programlistája
elemű szavas tömb minden elemét tegye 8 - cal oszthatóvá úgy, hogy a 8-as osztás maradékát a számokból elveszi! Nem használhat DIV utasítást! 2.2.2. Egy 10
A megoldás során bitenkénti logikai műveleteket használunk. Egy szavas adat akkor osztható 8-al, ha az alsó 3 helyi értéken levő bit 0 (az első 1 -es bit a 23-on, vagyis a 8-as helyi értéken lehet). 8-al oszthatóvá úgy tudjuk tenni az elemeket, ha töröljük logikai AND művelettel az alsó 3 helyi értékű bitet. A maszkérték: FFF8H. A példában az AND műveletet használjuk, amely bitenként logikai „és” műveletet végez. ADAT T ADAT KOD
SEGMENT DW 110,120,130,140,150,160,170,180,190,200 ENDS SEGMENT ASSUME DS:ADAT, CS:KOD START: MOV AX,ADAT MOV DS,AX MOV CX,10 MOV SI,0 CIKL: AND T[SI],0FFF8H ;AZ ALSÓ 3 BITET TÖRÖLJÜK, INC SI ;EKKOR OSZTHATÓ 8 -AL INC SI LOOP CIKL MOV AH,4CH INT 21H KOD ENDS END START 55. ábra. A 2.2.2. feladat programlistája
Határozza meg egy 10 elemű szavas tömb 4- gyel osztható elemeinek a számát! Nem használhat DIV utasítást! 2.2.3.
A megoldás során bitenkénti logikai műveleteket használunk. Egy szavas adat akkor osztható 4-el, ha az alsó 2 helyi értéken levő bit 0 (az első 1 -es bit a 22-on, vagyis a 4- es helyi értéken lehet). 47
A vizsgált tömbelemet 4 -el oszthatóvá tesszük (töröljük az alsó két helyi értéken levő bitet logikai AND művelettel, a maszkérték: FFFCH), majd összehasonlítjuk az eredeti értékkel. Ha a két érték megegyezik, akkor 4 -el osztható az eredeti tömbelem, ekkor megnövelünk 1 -el egy számláló változót. ADAT T OSZT4 ADAT KOD
SEGMENT DW 110,120,130,140,150,160,170,180,190,200 DB 0 ENDS SEGMENT ASSUME DS:ADAT, CS:KOD START: MOV AX,ADAT MOV DS,AX MOV CX,10 MOV SI,0 CIKL: MOV AX,T[SI] AND AX,0FFFCH ;AZ ALSÓ 2 BITET TÖRÖLJÜK, ;EKKOR OSZTHATÓ 4 -EL CMP T[SI],AX ;ÖSSZEHASONLÍTJUK AZ EREDETI TÖMBELEMMEL JNZ NEM ;HA EGYENLŐ, AKKOR EREDETILEG 4 -EL ;OSZTHATÓ VOLT INC OSZT4 ;MEGNÖVELJÜK A DARABSZÁMOT NEM: INC SI INC SI LOOP CIKL MOV AH,4Ch INT 21H KOD ENDS END START 56. ábra. A 2.2.3. feladat programlistája
2.3.
Léptető (shift) és forgató (rotate) műveletek 9
Készítsen programot, amely megszámolja egy 10 elemű bájtos tömb azon elemeinek a számát, amelyben a bitek száma páros! 2.3.1.
A megoldás során a megszámolás tételét fogjuk alkalmazni. Meg kell számolnunk minden egyes tömbelem esetén az 1 -es értékű bitek számát. Az adott tömbelemet betöltjük egy regiszterbe, majd el fogjuk rotálni pl. balra úgy, hogy minden bit 1 helyi értékkel balra lép, a kilépő bit belép majd a legkisebb helyi értéken és megjelenik a Carry flagben is. Ezt a RCL utasítás valósítja meg. Vizsgáljuk a Carry flaget, ha 1, akkor a bit 1 -es, vagyis megnövelünk majd egy számlálót. 8 -szor kell majd rotálni, mivel 8 bites (1 bájtos) adatokkal dolgozunk. Ebben a példában szerepel még a PUSH op, illetve a POP op utasítás. A PUSH utasítás a szavas operandus értékét elmenti a verem memóriába, a POP utasítás egy szót kivesz a verem memóriából. ADAT SEGMENT T DB 2,4,6,8,10,12,14,16,18,20 P1DB DB 0 ADAT ENDS
9
AsmKodtabla 8.-9. oldal 48
KOD
SEGMENT ASSUME DS:ADAT, CS:KOD START: MOV AX,ADAT MOV DS,AX MOV CX,10 ;CIKLUSSZÁMLÁLÓ, ITT A TÖMBELEMEK SZÁMA MOV SI,0 MOV DI,0 CIKL: MOV AL,T[SI] ;A VIZSGÁLANDÓ TÖMBELEM PUSH CX ;A CX TARTALMÁT ELMENTJÜK A VEREM MEMÓRIÁBA MOV CX,8 ;8-SZOR KELL ROTÁLNI BIT1SZ: RCL AL,1 ;ROTÁLJUK 1 BITTEL BALRA JNC NEM1 ;HA A CF NEM 1, AKKOR UGRUNK INC DI ;MEGNOVELJUK AZ 1-ES BITEK SZAÁMÁT NEM1: LOOP BIT1SZ POP CX ;A VEREM MEM. LEGFELSŐ SZAVÁT KIVESSZÜK A CX REGISZTERBE AND DI,01H ;AZ 1-ES BITEK SZÁMA ESETÉBEN A LEGKISEBB HELYIÉRTÉK 0? JNZ NEMP INC P1DB ;IGEN, MEGNÖVELJÜK A P1DB -T NEMP: INC SI LOOP CIKL MOV AH,4CH INT 21H KOD ENDS END START 57. ábra. A 2.3.1. feladat programlistája
2.4.
Input/output műveletek 10
Az assembly nyelvben a beolvasás és kiírás nem olyan egyszerű, mint ahogy azt megszoktuk a magas szintű nyelveknél. Pl. az 12345 számot, mint decimális számot számjegyenként (ciklikus művelettel) tudjuk beolvasni. Beolvasáskor karaktereket olvasunk, vagyis ASCII kódokat kapunk. Egy -egy karaktert egyegy bájtra helyezhetünk el a memóriában. Ahhoz, hogy dolgoz ni tudjunk a beolvasott számmal, az 5 bájtos adatsorból (amely pl. az 12345 számjegyei) egy szavas (16 bites) bináris számot kell képeznünk. Kiíráskor egy-egy karaktert tudunk megjeleníteni a képernyőn, így pl. ha az 12345 -nek megfelelő bináris értéket decimális formában a képernyőn meg akarjuk jeleníteni, akkor számjegyekre kell bontani, a számjegyek ASCII kódját előállítani, majd karakterenként (ciklik us művelettel) megjeleníteni a képernyőn. Olvassunk be a billentyűzetről egy maximum 5 jegyű decimális számot Enter karakterig ellenőrzéssel, majd írjuk vissza a képernyőre! A megoldás során az INT 21H szoftver megszakítást alkalmazzuk. Beolvasás esetén az AH regiszterbe az 1 -es funkció kódot kell tölteni, az INT 21H visszatérése után a beolvasott karakter ASCII kódját kapjuk meg az AL regiszterben. Kiírás esetén a kiírandó karakter ASCII kódját a DL regiszterben kell elhelyezni, az AH regiszterbe a 2-es funkciókódot kell tölteni. Az INT 21H meghívása után a karakter megjelenik a képernyőn. 2.4.1.
10
AsmKodtabla 13. oldal
49
További hasznos lehetőség, hogy a képernyőn szöveget (sztringet) jeleníthetünk meg. Ekkor a kiírandó szöveg of fs zet címét a LEA utasítás segítségével a DX regiszterbe töltjük, az AH -ba a 9-es funkció kódot helyezzük el, és meghívjuk az INT 21H rutint. Fontos, hogy a kiírandó szöveget a $ jellel zárjuk le! ADAT SZJ
SEGMENT DB 5 DUP(?) ;A BEOLVASOTT SZÁMJEGYEK RÉSZÉRE ;LEFOGLALT HELY SZJSZ DW ? ;A BEOLVASOTT SZÁMJEGYEK SZÁMA SZOV1 DB 0AH,0DH,'ADAT= $' SZOV2 DB 0AH,0DH,'A BEOLVASOTT ADAT= $' SZOV3 DB 0AH,0DH,'HIBAS KARAKTER!!! $' ADAT ENDS KOD SEGMENT ASSUME DS:ADAT, CS:KOD START: MOV AX,ADAT MOV DS,AX LEA DX,SZOV1 ;A SZOV1 SZTRINGÜNK KEZDŐCÍMÉT BETÖLTJÜK A DX -BE MOV AH,9 INT 21H ;INPUT SZOVEG MEGJELENÍTÉSE ;BEOLVASAS CIKLIKUSAN MOV SZJSZ,5 MOV CX,5 ;MAX 5 DB SZÁMJEGYET OLVASUNK BE MOV SI,0 ;INDEX BE: MOV AH,1 INT 21H ;kar -> AL CMP AL,0DH ;ENTER KARAKTER? JE BEVEG ;HA ENTER, AKKOR KILÉPÜNK ;ELLENORZESEK CMP AL,'0' ;(AL)='0' JL HIBA ;(AL)<'0' HIBAS KARAKTER CMP AL,'9' ;(AL)='9' JG HIBA ;(AL)>'9' HIBAS KARAKTER ;HELYES KARAKTER, LETÁROLJUK MOV SZJ[SI],AL INC SI LOOP BE BEVEG: SUB SZJSZ,CX ;A BEOLVASOTT SZÁMJEGYEK SZÁMA CMP SZJSZ,0 ;HA 0 db KARAKTER LETT BEOLVASVA, AKKOR JE VEGE ;PROGRAM VEGE LEA DX,SZOV2 MOV AH,9 INT 21H ;KIÍRÁS SZÖVEG MEGJELENÍTÉSE MOV CX,SZJSZ MOV SI,0 KI: MOV DL,SZJ[SI] MOV AH,2 INT 21H INC SI LOOP KI JMP VEGE HIBA: LEA DX,SZOV3 ;HIBÁS KARAKTER MOV AH,9 INT 21H VEGE: MOV AH,4CH INT 21H KOD ENDS END START 58. ábra. A 2.4.1. feladat programlistája
50
Olvasson be maximum 80 karaktert a klaviatúráról, enter végjelig! Ezután írja ki a képernyőre; a kapott karaktersorozatot a decimális számjegy karakterek kihagyásával! A megoldás során karaktereket fogunk beolvasni a billentyűzetről. Minden egyes karaktert 1 1 bájton tárolunk. Utána a számjegy karakterek kivételével kiírjuk a karaktereket a képernyőre. A karakterek ASCII kódját fogjuk vizsgálni. Az adott karakter akkor számjegy, ha az ASCII kódja 30H és 39H közé esik. 2.4.2.
ADAT KAR KARSZ SOREM ADAT PROG
SEGMENT DB 80 DUP(20H) DB 0 DB 0AH,0DH,'$' ENDS SEGMENT ASSUME DS:ADAT, CS:PROG START: MOV AX,ADAT MOV DS,AX MOV CX,80 MOV SI,0 BE: MOV AH,1 INT 21H ;1 KARAKTER BEOLVASÁSA MOV KAR[SI],AL ;BEOLVASOTT KARAKTER LETÁROLÁSA INC SI CMP AL,0DH ;ENTER KARAKTER? LOOPNZ BE ;HA CX NEM 0 ÉS ZF NEM 1, AKKOR UGRÁS A BE CIMKÉRE LEA DX,SOREM MOV AH,9 INT 21H MOV CX,80 MOV SI,0 KI: MOV DL,KAR[SI] ;KIÍRANDÓ KARAKTER A DL-BE CMP DL,30H JL NEMSZ ;UGRIK, HA DL<'0' CMP DL,39H JG NEMSZ ;UGRIK, HA DL>'9' JMP SZ NEMSZ: MOV AH,2 INT 21H ;NEM SZÁMJEGY KARAKTER, KIÍRJUK SZ: INC SI CMP DL,0DH LOOPNZ KI MOV AH,4CH INT 21H PROG ENDS END START 59. ábra. A 2.4.2. feladat programlistája
Írjon olyan programot, amely egy 16 bites értéket binárisan kiír a képernyőre! A megoldás során léptető, rotáló és bitenkénti logikai műveleteket alkalmazunk. A kiírandó 16 bites adatot (ciklikusan 16- szor) 1 bittel balra léptetjük úgy, hogy a kilépő bit belép a legkisebb helyi értéken és a Carry flagben is megjelenik. Ezt a ROL utasítás valósítja meg. A Carry f lag tartalmát hozzáadjuk 0 -hoz, így ha a kilépő bit 1 -es volt, akkor az eredményünk 1 lesz, ha 0 volt, akkor 0 lesz. A Carry flaggel együtt való összeadást az ADC utasítás valósítja meg. A zónarész hozzáadása után megjelenítjük a megfelelő karaktert ’1’ vagy ’0’ a képernyőn. 2.4.3.
51
ADAT BSZAM ADAT KOD
SEGMENT DW 0A3EFH ;A BITENKÉNT KIÍRANDÓ HEXADECIMÁLIS SZÁM ENDS SEGMENT ASSUME DS:ADAT, CS:KOD START: MOV AX,ADAT MOV DS,AX MOV CX,16 MOV BX,BSZAM MOV AH,2 CIKL: XOR DL,DL ;A DL TARTALMÁT ÖNMAGÁVAL KIZÁRÓ VAGY KAPCSOLATBA ;HOZZUK, ÍGY TARTALMA KINULLÁZÓDIK ROL BX,1 ;ROTÁLJA BALRA CF -BEN IS MEGJENIK A BIT ADC DL,0 ;CF-EL EGYÜTT HOZZÁADJA DL -HEZ OR DL,30H ;ZÓNARÉSZ RÁHELYEZÉSE INT 21H ;MEGJELENÍTJÜK A KÉPERNYŐN LOOP CIKL MOV AH,4CH INT 21H KOD ENDS END START 60. ábra. A 2.4.3. feladat programlistája
Írjon olyan programot, amely beolvas a klaviatúráról egy legfeljebb 16 jegyű bináris számot ellenőrzéssel, majd a bináris értéket elhelyezi egy szavas változóban! A megoldás során léptető, és bitenkénti logikai műveleteket alkalmazunk. A konvertált részadatunkat tartalmazó regiszter tartalmát 1 bittel balra léptetjük (szorozzuk 2 -vel), majd a beolvasott aktuális karaktert (a zónarészét levágva) logikai OR művelettel hozzámásoljuk a konvertált részadatunkhoz. 2.4.4.
ADAT BSZAM ADAT KOD
SEGMENT DW 0 ;MEMÓRIASZÓ ENDS SEGMENT ASSUME DS:ADAT, CS:KOD START:MOV AX,ADAT MOV DS,AX MOV CX,16 XOR BX,BX MOV AH,1 XOR DX,DX BE: INT 21H ;AL-BEN OTT VAN A BEOLVASOTT ADAT MOV DL,AL CMP DL,0DH JZ KIBE CMP DL,30 JL BE ; <, HIBÁS ADAT CMP DL,31H JG BE ; >, HIBÁS ADAT AND DL,0FH ;ZÓNARÉSZ LEVÁGÁSA SHL BX,1 ;LÉPTETÉS BALRA, 2-VEL VALÓ SZORZÁS OR BX,DX ;BITENKÉNTI VAGY MŰVELET LOOP BE KIBE: MOV AH,4CH INT 21H KOD ENDS END START 61. ábra. A 2.4.4. feladat programlistája
52
2.5.
Konverziók
A következőkben nézzük meg, hogy hogyan tudjuk a konverziókat végrehajtani. Alapvetően mi a 10-es (decimális) számrendszerben dolgozunk, de a gépben az adatok 2 -es (bináris) számrendszerben vannak tárolva. Beolvasás esetén a számjegyeket a billentyűzetről karakterenként ASCII kódban tudjuk beolvasni. Pl. a 12345 beolvasásakor a billentyűzetről egy karaktersorozatot (31H, 32H, 33H, 34H, 35H) kapunk. Ebből a karaktersorozatból kell előállítanunk egy 16 bites számot , amely a decimális 12345 karaktersorozatnak megfelelő bináris érték. Kiírás esetén a számjegyeket a képernyőre karakterenként ASCII kódban kell kiküldenünk. Most fordított a helyzet, mint beolvasáskor. Az egy szón binárisan tárolt adatból karaktersorozatot (különálló számjegyeket kell készítenünk) a kiíráshoz. Ezeket a műveleteket valósítják meg a konverziók. Készítsen algoritmust, amely egy decimális számot (pl: 1234) (4 bájton van tárolva karakterenként a memóriában) átalakít egy 16 bites bináris adattá. Egy programban 4 jegyű ASCII kódú decimális számot sztringként tudunk definiálni (DB direktívával). Ilyen definíció esetén a számjegyek a memória egy adott címétől kezdődően egymást követő memóriarekeszekben helyezkednek el. (Ugyanez a helyzet, ha a számot input eredményeként tároljuk). A 65535 decimális értéknél kisebb bináris értékek biztosan elférnek egy szóban, hiszen a 65535 -nek megfelelő bináris érték: 1111 1111 1111 1111 (azaz 16 bites). Ezért az eredmény számára egy szó hosszúságú helyet kell biztosítanunk. Egy konkrét esetben pl., ha a decimális szám 1234, akkor a memóriában való elhelyezéskor a memóriarekeszek tartalma: 31 H, 32H, 33H, 34H . Ennek megfelelő bináris érték egy szóban: 2.5.1.
04D2H.
Mindenekelőtt minden ASCII kódú számjegy zóna részét (a 3-as értéket ) minden bájtból törölni kell, azaz el kell érni, hogy minden bájton az adott számjegy bináris értéke legyen. Ezután, vegyük figyelembe, hogy az egyes számjegyeknek milyen a helyértéke és a helyértékétől függően 10 megfelelő hatványával szorozni kell. Azért, hogy ne kelljen tárolni 10 különböző hatványainak értékeit, a műveletet az ún. Horner elrendezés szerint végezzük el, azaz az első számot szorozzuk 10 -zel, a szorzathoz hozzáadjuk a következő számot, majd ezt az összeget is szorozzuk 10 -zel, majd ehhez a szorzathoz hozzáadjuk a következő számjegyet és így tovább haladunk addig, amíg az utolsó számot hozzá nem adtuk az előzőleg kiszámított szorzathoz.
Pl., ha a szám abcd, ahol a,b,c,d, decimális számjegyek, akkor a bináris szám= (((a*10 + b ) * 10 ) +c )*10 + d 4 jegyű szám esetén 3-szor kell 10-zel szorozni és 3-szor kell összeadást is végezni, de 4 elemet kell elérni. Azért, hogy mindegyik elemmel hasonló műveletet kelljen elvégezni, az első elemet is hozzáadjuk egy szorzathoz, mégpedig egy 0 értékhez. Algoritmusunk a következő lesz: a bináris szám= (( (0 *10+ a )* 10 + b ) * 10 +c )*10 + d
53
ADAT DSZAM BSZAM TIZ ADAT KOD
SEGMENT DB '1234' ;4 JEGYŰ ASCII KÓDÚ DECIMÁLIS SZÁM DW ? ;AZ EREDMÉNY SZÁMÁRA FENNTARTOTT HELY DW 10 ENDS SEGMENT ASSUME DS:ADAT, CS:KOD START: MOV AX,ADAT MOV DS,AX MOV AX,0 ;EZT SZOROZZUK ELŐSZÖR 10-ZEL MOV SI,0 ;INDEX A SORON KÖVETKEZŐ SZÁMJEGYHEZ MOV CX,4 ;CIKLUSSZÁMLÁLÓ BEÁLLÍTÁSA MOV BH,0 ;A SORON KÖVETKEZŐ SZÁMJEGYET BL-BE TÖLTJÜK, ;DE SZÓKÉNT ADJUK A SZORZATHOZ, AMELY A DX,AX-BEN ;KELETKEZIK CIKL: MUL TIZ ;SZAVAS SZORZÁST HAJTUNK VÉGRE , MERT BÁJTOS ESETBEN A ;SZORZAT IS CSAK EGY BÁJTOS LEHETNE MOV BL,DSZAM[SI] AND BL,0FH ;ZÓNARÉSZ TÖRLÉSE ADD AX,BX INC SI LOOP CIKL MOV BSZAM,AX ;AZ EREDMÉNYT KIÍRJUK A MEMÓRIÁBA IS MOV AH,4CH INT 21H KOD ENDS END START 62. ábra. A 2.5.1. feladat programlistája
Készítsen algoritmust, amely egy bináris számot (pl: 3039H) számjegyekre bont, előkészít a kiírásra. Egy szó hosszúságú bináris szám ASCII kódú decimális számmá alakításánál először elő kell állítani a decimális szám számjegyeit egy -egy bájton, majd mindegyik számjegyet ASCII kódúvá kell alakítani. 1 szó hosszúságú bináris szám legfeljebb 5 jegyű decimális számnak felel meg. Ezért az eredmény számára egy 5 bájtos puffert tartunk fenn (1 számjegy 1 bájtra kerül). Az átalakítást a konverzióknál tanultaknak megfelelően 10 -zel való osztogatással végezzük. Az osztás maradéka adja a decimális szám egy számjegyét, a hányadost pedig tovább kell osztani 10 -zel. Elsőként az utolsó számjegyet kapjuk, majd az utolsó előttit és így tovább, majd amikor a hányados 0 lesz, akkor megkapjuk a legelső számjegyet. A maradékokat rendre tároljuk, természetesen fordított sorrendben. Az osztást addig végezzük, ameddig a hányados 0 nem lesz. Ha mindig 5 -ször hajtjuk végre, ilyenkor kisebb szám esetén elképzelhető, hogy a maradékok 0 értékűek lesznek (azaz vezető 0 -k, értéktelen számjegyek kerülnek tárolásra). 2.5.2.
ADAT DSZAM BSZAM TIZ ADAT
54
SEGMENT DB 5 DUP (?) ;5 JEGYŰ ASCII KÓDÚ DECIMÁLIS ;SZÁM RÉSZÉRE FENNTARTOTT HELY DW 2AB7H ;A BINÁRIS SZÁM AMELYEK KONVERTÁLUNK DW 10 ENDS
KOD
SEGMENT ASSUME DS:ADAT, CS:KOD START: MOV AX,ADAT MOV DS,AX MOV AX,BSZAM ;EZT KELL KONVERTÁLNI MOV SI,4 ;INDEX AZ UTOLSÓ MEMÓRIAREKESZHEZ MOV CX,5 ;CIKLUSSZÁMLÁLÓ BEÁLLÍTÁSA CIKL: MOV DX,0 ;SZAVAS OSZTÁSHOZ DIV TIZ ;SZAVAS OSZTÁST HAJTUNK VÉGRE, MERT BÁJTOS ;OSZTÁSNÁL A HÁNYADOS IS BÁJTON KELETKEZIK OR DL,30H ;ZÓNARÉSZ HOZZÁADÁSA MOV DSZAM[SI],DL DEC SI ;DECREMENTÁLJUK AZ INDEXET LOOP CIKL MOV AH,4CH INT 21H KOD ENDS END START 63. ábra. A 2.5.2. feladat programlistája
Készítsen algoritmust, amely egy hexadecimális számot (pl: 7A5EH) (4 bájton van tárolva karakterenként a memóriában) átalakít egy 16 bites bináris adattá. Ezt a feladatot az 14. feladatnál leírtakhoz hasonlóan meg lehet oldani, csak értelemszerűen itt az átalakítandó szám maximálisan 4 jegyű lehet és nem csak decimális (0 -9), hanem hexadecimális (A-F) értékek is szerepelhetnek a számjegyek között, valamint az egyes számjegyeket nem 10 -zel, hanem 16-tal kell szorozni. Ugyanezt a feladatot azonban más módon is meg lehet oldani a léptetési utasítások felhasználásával. Ennél a megoldásnál azt használjuk ki, hogy egy szavas érték 16 -tal való szorzása egyenértékű a szónak 4 bittel való balra léptetésével, valamint azt, hogy minden egyes hexadecimális számjegy 4 biten tárolódik. 2.5.3.
ADAT HSZAM BSZAM ADAT KOD
SEGMENT DB '7A5E' ;A HEXADECIMÁLIS SZÁM DW ? ;A KONVERTÁLT BINÁRIS ÉRTÉK ENDS SEGMENT ASSUME DS:ADAT, CS:KOD START: MOV AX,ADAT MOV DS,AX MOV CX,4 ;4.SZER FUT LE A CIKLUS MOV SI,0 ;INDEX MOV AX,0 ;AZ AX-BEN FOG AZ EREDMÉNY KÉPZŐDNI CIKL: PUSH CX ;CX TARTALMÁNAK ELMENTÉSE MOV BL,HSZAM[SI] ;AZ AKTUÁLIS SZÁMJEGY SUB BL,30H CMP BL,9 ;DECIMÁLIS SZÁMJEGY, VAGY BETŰ (A-F) JLE DECIM ;DECIMÁLIS SZÁMJEGY SUB BL,7 DECIM: MOV CL,4 SHL AX,CL ;AX-ET 4 BITTEL BALRA LÉPTETJÜK OR AX,BX ;BX TARTALMÁT RÁMÁSOLJUK AX-RE POP CX INC SI LOOP CIKL MOV BSZAM,AX ;AZ EREDMÉNY ELTÁROLÁSA 55
KOD
MOV AH,4CH INT 21H ENDS END START 64. ábra. A 2.5.3. feladat programlistája
Készítsen algoritmust, amely egy bináris számot (pl: 7A5EH) hexadecimális számjegyekre bontva előkészít a kiírásra. Ezt a feladatot a 15. feladatnál leírtakhoz hasonlóan meg lehet oldani, csak értelemszerűen itt az átalakított szám 4 jegyű lehet és nem csak decimális (0 -9), hanem hexadecimális (A -F) értékek is szerepelhetnek a számjegyek között, valamint az egyes számjegyeket nem 10 -zel, 2.5.4.
hanem 16-tal kell osztani.
Ugyanezt a feladatot más módon is meg lehet oldani a léptetési utasítások felhasználásával. Ennél a megoldásnál azt használjuk ki, hogy egy szavas érték 16 -tal való osztása egyenértékű a szónak 4 bittel való jobbra léptetésével, valamint azt, hogy minden egyes hexadecimális számjegy 4 biten tárolódik. Az algoritmus lényege az, hogy a szavas érték 4 tetrádját egy -egy bájtos memóriarekeszben helyezzük el, mégpedig az egyes értékeknek megfelelő ASCII kódban. A tetrádok elhelyezését a legfelső tetráddal kezdjük, ezért először balra léptetünk rotációval (a balra kilépő bitek jobbra belépnek), majd folytatjuk a műveletet 4 -szer. ADAT HSZAM BSZAM ADAT KOD
SEGMENT DB 4 DUP(?) ;A HEXADECIMÁLIS SZÁM SZÁMJEGYEI DW 7A5EH ;A KONVERTÁLANDÓ HEXA SZÁM(BINÁRIS ÉRTÉK) ENDS SEGMENT ASSUME DS:ADAT, CS:KOD START: MOV AX,ADAT MOV DS,AX MOV CX,4 ;4.SZER FUT LE A CIKLUS MOV SI,0 ;INDEX MOV AX,BSZAM ;A KONVERTÁLANDÓ BINÁRIS SZÁM CIKL: PUSH CX ;CX ELMENTÉSE MOV CL,4 ROL AX,CL ;AZ AX ÉRTÉKÉT ROTÁLJUK 4 BITTEL ;BALRA. A FELSŐ 4 ;BIT AZ ALSÓ 4 BIT HELYÉRE KERÜL MOV BL,AL ;A BL ALSÓ TETRÁDJÁN LESZ A SZÁMJEGY AND BL,0FH ;A FELSŐ TETRÁD TÖRLÉSE CMP BL,9 ;DECIMÁLIS SZÁMJEGYRŐL VAN SZÓ? JLE DECIM ;IGEN ADD BL,7 ;BETÜ (A-Z) DECIM: ADD BL,30H ;ZONARÉSZ RÁHELYEZÉSE MOV HSZAM[SI],BL ;A SZÁMJEGY ELMENTÉSE INC SI POP CX LOOP CIKL MOV AH,4CH INT 21H KOD ENDS END START 65. ábra. A 2.5.4. feladat programlistája
56
2.6.
Sztringműveletek 11
Készítsen olyan programot, amely a saját nevével inicializált memóriaterület tartalmát átpakolja egy másik memóriaterületre! A példát megoldjuk először úgy, hogy bájtonként pakoljuk át a sztringet, majd úgy, hogy ismétlő művelettel egy lépésben átpakoljuk a sztring bájtjait. A LODS, STOS, MOVS műveleteket fogjuk használni. A LODS utasítás az SI -vel megcímzett forrássztringből 1 bájtot vagy szót tölt be az AL vagy AX regiszterbe. A STOS utasítás az AL vagy AX regiszterből 1 bájtot vagy szót tölt ki a DI -vel megcímzett memóriaterületre. A MOVS utasítás sztring mozgatását végzi egyik memóriahelyről a másikba. Az utasítás kiadása előtt a forrás sztring DS-beli offszet címét az SI-be, a célsztring ES-beli offszet címét a DI-be indexregiszterbe kell betölteni. A DF (direction) flag t artalmától függően SI és DI automatikusan inkrementálódik (ha DF=0), vagy dekrementálódik (ha DF=1). A példában ciklikusan kell mozgatni a sztring bájtjait. Ezt megtehetjük a REP prefix utasítások segítségével is. A REP utasítás az egyszerű sztring utasításokat annyiszor hajtják végre, amíg a CX regiszter értéke 0 nem lesz. A REP Prefix utasítás, hatás a csak a következő utasításra terjed ki . 2.6.1.
ADAT NF NC1 NC2 NC3 NC4 ADAT KOD
SEGMENT DB 'Gipsz Jakab';FORRÁS SZTRING DB 11 DUP(?) ; CÉL SZTRING DB 11 DUP(?) DB 11 DUP(?) DB 11 DUP(?) ENDS SEGMENT ASSUME DS:ADAT, ES:ADAT, CS:KOD START: MOV AX,ADAT MOV DS,AX MOV ES,AX ;atpakolas bajtonkent CLD ;DF=0, SI INKREMENTÁLÓDIK MOV CX,11 MOV SI,OFFSET NF MOV DI,OFFSET NC1 CIKL1: LODS NF ;EGY BÁJT -> (AL) STOS NC1 ;(AL) -> EGY BÁJT LOOP CIKL1 STD ;DF=1, SI DEKREMENTÁLÓDIK MOV CX,11 MOV SI,OFFSET NF ADD SI,CX ;A SZTRING VÉGÉRE ÁLLÍTJUK AZ SI-T DEC SI MOV DI,OFFSET NC2 ADD DI,CX ; A SZTRING VÉGÉRE ÁLLÍTJUK AZ DI-T DEC DI CIKL2: LODS NF ;EGY BÁJT -> (AL) STOS NC1 ;(AL) -> EGY BÁJT LOOP CIKL2 ;atpakolas ismetelt stringmuveletekkel CLD ;DF=0, SI ÉS DI INKREMENTÁLÓDIK MOV SI,OFFSET NF ;FORRÁS SZTRING ELTOLÁSI CÍME MOV DI,OFFSET NC3 ;CÉL SZTRING ELTOLÁSI CÍME 11
AsmKodTabla 14. oldal
57
MOV MOVS STD MOV MOV ADD DEC MOV ADD DEC MOVS MOV INT ENDS END
REP
REP
KOD
CX,11 NC3,NF ;DF=1, SI ÉS DI DEKREMENTÁLÓDIK CX,11 SI,OFFSET SI,CX SI DI,OFFSET DI,CX DI NC4,NF AH,4CH 21H
NF ; A SZTRING VÉGÉRE ÁLLÍTJUK AZ SI-T NC4 ; A SZTRING VÉGÉRE ÁLLÍTJUK AZ DI-T
START 66. ábra. A 2.6.1. feladat programlistája
2.7.
Procedúrák, makrók használata
A programozás során gyakran előfordul, hogy azonos, vagy hasonló feladatokat kell megoldanunk többször. Ilyenkor érdemes ezt a programrészt kiemelni, és a programon belül csak hivatkozni rájuk. Az Intel assembly nyelvben két lehetőség áll rendelkezésünkre; a procedúra és a makro. A procedúra definícióját a kódszegmensben kell elhely ezni a program logikai vége (a vezérlés visszaadása az operációs rendszernek) után. A procedúra meghívása a CALL utasítással történik, ekkor a vezérlés átadódik a procedúrának. A procedúra lefutása után a RET utasítás adja vissza a vezérlést a hívó programnak. Amikor egy procedúrát hívunk (CALL procedúra_név), mielőtt a vezérlés átkerülne rá, a következő utasítás címe eltárolódik a STACK- ben. Ezzel válik lehetővé, hogy a procedúra végén RET hatására a vezérlés visszatérjen a hívást követő utasításra. A RET a stack tetején lévő érték alapján tér vissza a hívási helyre. A paraméterátadás vagy regisztereken, vagy a STACK memórián keresztül történik. A makro definíciót a makro meghívása elé kell elhelyezni. A makro meghívása a nevével és az aktuális paraméterlistával történik. A makro hívás során az assembler az első menetben a makro kódját bemásolja a makro definíciós táblázatba. A második menetben az assembler a formális paraméterek helyébe behelyettesíti az aktuális paramétereket, és a makro kódját bemásolja a programkódba. Ha többször hívjuk meg a makrót, akkor annyiszor másolódik be a makro kódja, amennyiszer meghívjuk a makrót. 2.7.1.
Procedúrák
Készítsen olyan programot, amely beolvas Enter karakterig (de maximum 5 számjegyig) két decimális számot. A két számot összeadja, majd az eredményt megjeleníti a képernyőn. A beolvasást és a kiírást procedúrával oldja meg! 2.7.1.1.
A megoldás során a „beolvas” procedúra fogja tartalmazni a „decimális - bináris” konverziót, a „kiir” procedúra pedig tartalmazni fogja a „bináris -decimális” konverziót. A paraméterátadást a verem (stack) memórián keresztül oldjuk meg .
58
A beolvasást végző procedúra : Bemenet:
A stackben annak a memória területnek a címe, ahova a beolvasott számot binárisan el fogjuk helyezni. A memóriacímet (offszetcím) egy LEA utasítás segítségével töltjük be a BX regiszterbe és a PUSH BX utasítással tesszük be a stack memóriába. Kimenet:
A memóriában a BX regiszter segítségével közvetlenül elhelyezzük a beolvasott számot 16 biten binárisan. A beolvasó procedúra végzi el a „decimális - bináris” konverziót. A kiírást végző procedúra. Bemenet: A stackben a kiírandó szám bináris formában.
A stackben a memóriacím, ahova a kiírandó szám karaktereit el kell helyezni. Kimenet:
A képernyőn megjelennek a szám karakterei. A kiíráshoz szükséges bináris -decimális konverziót a kiíró procedúra végzi. A kiírásnál felhasználjuk az INT 21H rutint, amelyet ha az AH=9 funkció kóddal hívunk meg, akkor a DX- ben megadott kezdőcímű sztringet jeleníti meg a képernyőn. Ehhez a kiírandó karaktereknek fenntartott memória helyet kezdetben szóközökkel töltjük fel, majd ebbe írjuk be a számjegy karaktereit. Ügyelnünk kell arra, hogy a kiírandó számjegyek mögé a memóriában egy ’$’ karakter is kerüljön. A „beolv” és a „kiir” procedúrán belül a „SZAM1 és SZAM2” illetve az „EREDM” változóra a memóriabeli offszet címén keresztül hivatkozunk. A procedúra meghívása előtt a verem memóriában elhelyezzük az adott változó offszet címét, a procedúrán belül pedig a BX bázis regiszter segítségével (amibe betöltjük az adott változó offszet címét) hivatkozunk a változóra (pl. MOV [BX], AX). ADAT SZAM1 SZAM2 EREDM SZJE TIZ SZOV1 SZOV2 ADAT KOD
SEGMENT DW ? ;AZ ELSŐ SZÁM BINÁRIS ALAKBAN DW ? ;A MÁSODIK SZÁM BINÁRIS ALAKBAN DW ? ;AZ EREDMÉNY BINÁRIS ALAKBAN DB 5 DUP(20H),'$' ;AZ EREDMÉNY KIÍRÁSÁHOZ SZÓKÖZÖK+$ DW 10 DB 0AH,0DH,'ADAT= $' DB 0AH,0DH,'EREDMENY= $' ENDS SEGMENT ASSUME DS:ADAT, CS:KOD START: MOV AX,ADAT MOV DS,AX LEA BX,SZAM1 PUSH BX CALL BEOLV ;AZ ELSŐ SZÁM BEOLVASÁSA LEA BX,SZAM2 PUSH BX CALL BEOLV ;A MÁSODIK SZÁM BEOLVASÁSA MOV AX,SZAM1 ADD AX,SZAM2 ;MŰVELETVÉGZÉS MOV EREDM,AX MOV AX,EREDM ;A KIÍRANDÓ ÉRTÉK BINÁRISAN 59
LEA BX,SZJE ;AZ EREDMÉNY SZÁMJEGYEINEK MEMÓRIABELI KEZDŐCÍME PUSH AX PUSH BX CALL KIIR ;AZ EREDMÉNY KONVERTÁLÁSA KIÍRÁSHOZ ÉS KIÍRÁS MOV AH,4CH INT 21H ;PROGRAM VÉGE ;BEOLVAS PROCEDURA ;BEMENET: STACKBEN A MEMÓRIA CÍM, AHOVÁ A BEOLVASOTT SZÁM BINÁRIS KÓDJÁT ;EL KELL HELYEZNI ;KIMENET: A MEMÓRIÁBAN TÁROLÁSRA KERÜL A BEOLVASOTT SZÁM BINÁRIS KÓDJA BEOLV PROC LEA DX,SZOV1 MOV AH,9 INT 21H ;INPUT SZÖVEG KIÍRÁSA MOV BP,SP MOV CX,5 ;MAX 5 JEGYŰ LEHET A SZÁM MOV AX,0 ;AZ AX-BEN FOG KÉPZŐDNI A BINÁRIS ÉRTÉK BE: PUSH AX ;AZ AX ELMENTÉSE A STACKBE EGYÉBKÉNT ELVESZNE ;A TARTALMA KARAKTER BEOLVASASKOR MOV AH,1 ;EGY KARAKTER OLVASÁSA A BILLENTYŰZETRŐL. INT 21H ;A KAR. AL-BE KERÜL XCHG AX,BX ;AX ELMENTÉSE A DX REGISZTERBE. ;A BEOLVASOTT KARAKTERÜNK A DL-BEN VAN POP AX ;AX-VISSZAVÉTELE A STACKBŐL ;ITT KEPZŐDIK A KONVERTÁLT ÉRTÉKÜNK CMP BL,0DH ;ENTER KARAKTERT OLVASTUNK? JE BEVEG ;IGEN, BEOLVASÁS VÉGE AND BL,0FH ;ZÓNARÉSZ LEVÁGÁSA MOV BH,0 MUL TIZ ;AX*10 ADD AX,BX LOOP BE BEVEG: MOV BX,[BP+2] ;A STACKBŐL A BX-BE TÖLTJÜK ;A BEOLVASANDÓ SZÁM MEMÓRIACÍMÉT MOV [BX],AX ;A KONVERTÁLT ÉRTÉK ELMENTÉSE A MEMÓRIÁBAN RET BEOLV ENDP ;KIIR PROCEDURA ;BEMENET: STACKBEN A KIÍRANDÓ SZÁM BINÁRIS FORMÁBAN STACKBEN A MEMÓRIACÍM, ;AHOVÁ A KONVERTÁLT KARAKTEREKET EL KELL HELYEZNI ;KIMENET: A MEMÓRIÁBAN MEGJELENNEK A SZÁMJEGYEK A KEPERNYŐN ;MEGJELENNEK A SZÁMJEGYEK KIIR PROC ;KONVERZIÓ MOV BP,SP MOV BX,[BP+2] ;SZÁMJEGYEK ELHELYEZÉSÉRE SZOLGÁLÓ ;MEMÓRIATERÜLET KEZDŐCIME MOV AX,[BP+4] ;KONVERTÁLANDÓ ÉRTÉK MOV CX,5 ;MAX 5 JEGYŰ LESZ A SZÁM MOV SI,4 ;INDEX KONV: MOV DX,0 DIV TIZ ;AX/10 HÁNYADOS AZ AX-BEN, MARADÉK A DX-BEN OR DL,30H ;ZÓNARÉSZ MOV [BX][SI],DL ;A SZÁMJEGY ELMENTÉSE CMP AX,0 ;AX=0? JE VEGE ;HA IGEN, AKKOR VÉGE A KONVERZIÓNAK DEC SI LOOP KONV
60
VEGE:
KIIR KOD
LEA MOV INT MOV MOV INT RET ENDP ENDS END
DX,SZOV2 AH,9 21H ;OUTPUT SZÖVEG KIÍRÁSA DX,BX ;A KIÍRANDÓ MEMÓRIA TERÜLET KEZDŐCÍME AH,9 21H ;AZ EREDMÉNY KIÍRÁSA SZTRINGKÉNT
START 67. ábra. A 2.7.1.1. feladat programlistája
Készítsen olyan pro cedúrát , amely egy kezdőcímével és hosszával adott karakter alakú decimális számot pakolt decimálissá (BCD) alakít, majd elhelyez egy ugyancsak a kezdőcímével adott memória területre! A főprogram végezze el az ellenőrzött bevitelt a klaviatúráról, majd az átalakítást a procedúra meghívásával végeztesse el! A számjegyek száma lehet páros és páratlan is, max. 12 jegy! A megoldás során a billentyűzetről olvasunk be karaktereket (’0’ -’9’) ellenőrzéssel. Egy-egy számjegy karakter egy -egy bájton kerül tárolásra. A feladat az, hogy a számjegyeket BCD formátumúra alakítsuk. Pl. 31H és 32H - ból, ami két bájton van tárolva, 12H lesz, ami 1 bájton van tárolva. A megoldás: betöltjük egy regiszterbe a 31H -t, 01H-t készítünk belőle (zónarész levágása), elléptetjük balra 4 bittel (10H), betöltjük egy regiszterbe a 32H -t, zónarészt levágjuk (02H). A két bájtos regiszter tartalmát összemásoljuk OR művelet segítségével, így megkapjuk a 12H értéket egy bájton. 2.7.1.2.
ADAT SZAM SZSZ ADAT ADCEL PSZAM PSZSZ ADCEL KOD
SEGMENT DB 12 DUP(0) DW 0 ENDS SEGMENT DB 6 DUP(0) DW 0 ENDS SEGMENT ASSUME DS:ADAT, ES:ADCEL, CS:KOD START: MOV AX,ADAT MOV DS,AX MOV AX,ADCEL MOV ES,AX MOV CX,12 MOV SI,0 MOV AH,1 BE: INT 21h CMP AL,0DH JZ KIBE CMP AL,30h JL BE CMP AL,39h JG BE MOV SZAM[SI],AL INC SI LOOP BE KIBE: MOV SZSZ,SI ;A BEOLVASOTT SZÁMJEGYEK SZÁMA LEA BX,SZAM PUSH BX 61
MOV PUSH LEA PUSH CALL MOV INT PROC MOV MOV MOV TEST JZ ADD SHR
PAKOL
UG:
CX,SZSZ CX BX,PSZAM BX PAKOL AH,4CH 21h BP,SP BX,[BP+6] CX,[BP+4] CX,0001h UG CX,1 CX,1
MOV SI,0 MOV DI,0 XOR AX,AX MOV AH,[BX][SI] AND AH,0FH PUSH CX MOV CL,4 SHL AH,CL POP CX INC SI CMP SI,[BP+4] JZ TOV
CIKL:
;PÁRATLAN? HA IGEN, AKKOR PÁROSAT KÉSZÍTÜNK BELŐLE ;CX TARTALMÁT OSZTJUK 2-VEL, A BCD BÁJTOK SZÁMA ;FELE AZ EREDETINEK
;BETÖLTJÜK AZ ELSŐ BÁJTOT ;ZÓNARÉSZT LEVÉGJUK ;ELLÉPTETJÜK 4 BITTEL
;AH ELÉRTÜK A VÉGÉT , VAGYIS PÁRATLAN AZ ;ELEMSZÁM , AKKOR UGRUNK MOV AL,[BX][SI] ;BETÖLTJÜK A MÁSODIK BÁJTOT AND AL,0FH ;ZÓNARÉSZT LEVÁGJUK OR AL,AH ;ÖSSZEMÁSOLJUK A KÉT TETRÁDOT MOV ES:[BX][DI],AL ;KIMOZGATJUK A MEMÓRIÁBA INC SI INC DI LOOP CIKL RET ENDP ENDS END START
TOV:
PAKOL KOD
68. ábra. A 2.7.1.2. feladat programlistája
2.7.2.
Makrók
Készítsen programot, amely összeadja egy adott elemszámú tömb elemeit! Az összegzést makróval végezzük! 2.7.2.1. ADAT T1 T2 E1 E2 ADAT
62
SEGMENT DB 21,32,54 DB 34,-54,21,5,-3 DW ? DW ? ENDS
KOD
SEGMENT ASSUME DS:ADAT, CS:KOD START: MOV AX,ADAT MOV DS,AX ;MAKRO DEFINIALASA OSSZ MACRO T,ESZ,EM LOCAL CIKL MOV CX,ESZ ;A TÖMB ELEMEINEK A SZÁMA MOV AX,0 ;AZ EREDMÉNY AZ AX -BEN FOG KÉPZŐDNI MOV SI,0 CIKL: MOV BH,0 MOV BL,T[SI] ADD AX,BX INC SI LOOP CIKL MOV EM,AX ENDM ;MAKRO HIVASA OSSZ T1,3,E1 ;AZ ELSŐ TÖMB ELEMEINEK ÖSSZEADÁSA OSSZ T2,5,E2 ;A MÁSODIK TÖMB ELEMEINEK ÖSSZEADÁSA MOV AH,4CH INT 21H KOD ENDS END START 69. ábra. A 2.7.2.1. feladat programlistája
2.8.
Gépi kódos példák
Ebben a részben assembly utasítások gépi kódra való visszafejtésére oldunk meg példákat . Egy gépi kódú utasítás hossza minimum 1 bájt, maximum 6 bájt. Egy gépi kódú utasítás két részből áll: 1. Milyen műveletet kell a mikroprocesszornak végrehajtania. (1 bájt Műveleti kód) 2. Hol találhatók azok az adatok, amelyekkel az adott műveletet végre kell hajtani. (2 -6. bájt) Egy gépi kódú utasítás a következő mezőkből áll:
Az egyes mezők jelentése a következő: 1. bájt: Operációs, műveleti kód. Leírja a mikroprocesszor számára a végrehajtandó műveletet. 2. bájt: Címzési mód: Milyen módon érhetők el a műveletben szereplő adatok. Az I8086-os mikroprocesszor 1 címes processzor, ami azt jelenti, hogy csak az egyik operandus lehet memóriaváltozó. 3. bájt: A műveletben szereplő memória operandus eltolási címének (DISP) alacsonyab b helyi értékű bájtja vagy közvetlen adat (DATA) alacsonyabb helyi értékű bájtja. 63
A DISP azt adja meg, hogy az adott memória operandus (szimbólum, változó) az adott szegmens elejéhez képest (amelyben a memóriaváltozót definiáltuk) hány bájttal van eltolva. 4. bájt: A műveletben szereplő memória operandus eltolási címének (DISP) magasabb helyi értékű bájtja vagy közvetlen adat (DATA) magasabb helyi értékű bájtja. 5. A műveletben szereplő közvetlen adat (DATA) alacsonyabb helyi értékű bájtja. 6. A műveletben szereplő közvetlen adat (DATA) magasabb helyi értékű bájtja. Nézzünk meg néhány példát! Adott a következő adatszegmens! ADAT A1 A2 ADAT
SEGMENT DW 23H,233H,5566H,4567H DW 1122H,3344H,5566H,7788H DB 19,11,22,37,44 DB 56,66,77,88,100 ENDS
Ábrázoljuk a „memóriában” az adat szegmenst! Az A1 szimbólummal kezdődő adatok szavas, az A2 szimbólummal kezdődő adatok bájtos adatok. A memóriában a magasabb és az alacsonyabb helyi értékű bájt mindig fordított sorrendben ábrázolódik. DISP
0
1
2
3
4
5
6
7
8
9
23
00
33
02
66
55
67
45
22
11
A
B
C
D
E
F
A1
44
33
66
55
88
77
DISP
10
11
12
13
14
15
16
17
18
19
A2
13
0B
16
25
2C
38
42
4D
58
64
A1 DISP
A táblázat 2., 4. és 6. sorában az adatokat láthatjuk, az 1. , 3. és az 5. sorban pedig az adott adat eltolási címét (DISP) a szegmens elejéhez képest. Vagyis az A1-es szimbólum esetén DISP=0; az A2 szimbólum esetében, pedig DISP=10H. Egy utasítás általános alakja: MNEMONIK cél-operandus, forrás -operandus Határozzuk meg a MOV AX, A1 utasítás gépi kódját 12 ! Első lépésként megkeressük a kódtáblázatunkban az aktuális utasítás csoportot, jelen esetben a MOV adatmozgató utasítást. Mint látható nem egy utasításkód szerepel, hanem több. Ezekről azt kell tudni, hogy az első utasításkód formula általánosan használható, a többi eset valamilyen speciális esetet ír le. Egy konkrét feladatnál meg kell néznünk, hogy valamely speciális eset ráhúzható -e a feladatra. Ha nem, akkor az általános formulát használjuk. 2.8.1.
A MOV esetében: MOV mem/reg1, mem/reg2: MOV mem, data: 12
AsmKódtábla 3. oldal
64
Általános formula, minden esetben használható, de ez adja a leghosszabb kódot. Egy memória operandusba közvetlen adatot mozgatunk.
MOV reg, data: MOV ac, mem:
Egy regiszter operandusba közvetlen adatot mozgatunk. Az akkumulátor regiszterbe egy direkt címzéssel címzett memória operandust mozgatunk. Itt fontos megjegyezni, hogy az ac kizárólag az
AX vagy AL regiszter lehet! MOV mem, ac: A 4-es pont fordított esete. MOV sr, mem/reg: Egy szegmens regiszterbe (DS, ES, CS, SS) adatot
mozgatunk memória
operandusból vagy regiszter operandusból. MOV mem/reg, sr: A 6-os pont fordított esete. A1 esetben, mivel ac=AX és az A1 szimbólum elérése direkt címzéssel történik (a címképzésben csak az A1 szimbólum DISP címe szerepel, nem szerepel bázis regiszter (BX, BP) illetve indexregiszter (SI, DI), ezért a 4 -es formulát használhatjuk. A MOV AX,
Második lépésként meghatározzuk az egyes mezők értékét. Utasítás
OP KÓD
MOV AX,A1
1010000w 10100001
MOD
REG
R/M
DISP/ DATA DISP 00000000
DISP/ DATA DISP 00000000
DATA
DATA
A kódban használatos biteket, illetve bit mezőket a kódtáblázatunk első oldalán található táblázatok, jelmagyarázatok alapján határozzuk meg. A w=1, mivel szavas műveletről van szó. A 16 bites AX regiszterbe bemozgatjuk az A1-es memóriaváltozóban található 16 bites értéket. Az A1-es memóriaváltozó DISP értéke 0, hiszen az A1 -es változó eltolása az ADAT szegmenshez képest 0. Határozzuk meg a MOV AX, A1[SI] utasítás gépi kódját! Az előző példában alkalmazott 4 -es formula nem használható, mivel nem DIREKT címzéssel érjük el a memória operandust. A címképzésben az A1 szimbólum DISP értéke és az SI indexregiszter értéke vesz részt. A memória operandus címét a DISP + [SI] adja. Az első, általános formulát kell alkalmaznunk. 2.8.2.
Utasítás
OP KÓD
MOD
REG
R/M
MOV AX,A1[SI]
100010dw
mod
reg
10001011
10
000
r/m
DISP/ DATA (DISP)
DISP/ DATA (DISP)
100
00000000
00000000
DATA
DATA
A w=1, mivel szavas műveletről van szó. A d bit 1, ha a mod r/m bitcsoportok a forrás operandust definiálják. Ha megnézzük a mod r/m jelentését a kódtáblázatunkban, láthatjuk, hogy a mod r/m bitcsoporttal (a mod=11 regiszter operandust kivéve) mindig a memória operandus eléréséhez szükséges címszámítási módot írjuk le. Vagyis mondhatjuk azt, hogy ha az utasításban van memóriaoperandus, akkor a d bit a memória operandus utasításban elfoglalt helyét (forrás vagy cél) írja le. Következésképpen, ha a forrás operandus a memória operandus, akkor a d bit értéke 1, ha a memória operandus nem a forrás operandu s, akkor a d bit 0. Jelen esetben a d=1, mivel a memória operandus a forrás operandus. Az utasításban memória operandus szerepel, így a mod mező étéke azt mondja meg, hogy a memória operandus címszámításában résztvevő DISP eltolási cím hány bájtos. 65
Az általános formula leírásából látható (DISP, DISP), hogy 2 bájtos eltolási címmel dolgozunk, vagyis mod=10. Az r/m mező a címszámítás módját írja le. Mivel A1[SI] a memória operandusunk, ebből látszik, hogy a címszámítás DISP+[SI], vagyis r/m=100. A reg mező azt írja le, hogy az utasításban melyik regiszter vesz részt. Jelen esetben az AX regiszter, vagyis reg=000. A DISP mező pedig 0 (ezt két bájton kell leírni az általános formula szerint), hiszen az A1-es szimbólum az ADAT szegmens kezdetéhez képest 0 bájtta l van eltolva. 2.8.3.
Határozzuk meg a MOV BL, A2 utasítás gépi kódját!
Utasítás
OP KÓD
MOD
REG
R/M
MOV BL,A2
100010dw 10001010
mod 00
reg 011
r/m 110
DISP/ DATA (DISP) 00010000
DISP/ DATA (DISP) 00000000
DATA
DATA
Látjuk, hogy egyik speciális eset sem húzható rá erre az utasításra, marad az általános formula. A 4-es formula azért nem jó, mert az ac csak az AX, AL lehet. A w=0, mivel bájtos műveletről van szó. A d=1, hiszen a memória operandus a forrás operandus helyén található. Mivel direkt címzésről van szó (csak a DISP vesz részt a címszámításban) ez egy kivételes eset, ekkor a mod=00 és r/m=110. A reg=011, hiszen az utasításban a BL regiszter szerepel. A DISP=10H, mivel az A2- es szimbólum 16 bájttal (10H) van eltolva az ADAT szegmens kezdetéhez képes t. 2.8.4.
Határozzuk meg a MOV A1, AX utasítás gépi kódját!
Utasítás
OP KÓD
MOV A1,AX
1010001w 10100011
MOD
REG
R/M
DISP/ DATA DISP 00000000
DISP/ DATA DISP 00000000
DATA
DATA
Erre az utasításra a MOV mem, ac 5-ös speciális formula húzható rá, mivel az A1 memória operandust direkt címzéssel érjük el, és a regiszter operandus az AX elsődleges akkumulátor regiszter. A w=1, mivel szavas műveletről van szó, a DISP=0, mivel az A1 -es szimbólum eltolása az adatszegmens kezdetéhez képest 0. 2.8.5.
Határozzuk meg a MOV A1[SI], AX utasítás gépi kódját!
Utasítás
OP KÓD
MOD
REG
R/M
MOV A1[SI],AX
100010dw
mod
reg
10001001
10
000
r/m
DISP/ DATA (DISP)
DISP/ DATA (DISP)
100
00000000
00000000
DATA
DATA
Ebben az esetben egyik speciális eset sem húzható rá a feladatra, vagyis marad az általános formula. A w=1, mivel szavas műveletről van szó. A d=0, mivel a memória operandus most a cél operandus. (lásd az 1 -es feladatot). Az utasításban szereplő A1[SI] cél operandus elérési módját írjuk most le a mod r/m bájt segítségével. Az általános formula leírásában látható, hogy két bájtos DISP értékkel dolgozunk, tehát mod=10. Az A1[SI] leírásból látszik, hogy a memória operandus címszámításában az A1 szimbólum DISP értéke és az SI index regiszter vesz részt (vagyis DISP + [SI]), ebből következik, hogy r/m=100. A reg=000, mivel az utasításban az AX regiszter szerepel, mint regiszter operandus. 66
A DISP mező pedig 0 (ezt két bájton kell leírni az általános formula szerint), hiszen az A1 -es szimbólum az ADAT szegmens kezdetéhez képest 0 bájttal van eltolva. Ha összehasonlítjuk a MOV A1[SI], AX és a MOV AX, A1[SI] utasítás gépi kódját, látható, hogy a két kód a d bit értékében különbözik egymástól. 2.8.6.
Határozzuk meg a MOV BL, 10 utasítás gépi kódját!
Utasítás
OP KÓD
MOV BL,10
1011wreg 10110011
MOD
REG
R/M
DISP/ DATA data 00001010
DISP/ DATA (data)
DATA
DATA
Erre a feladatra a MOV reg, data 3- as
speciális formula húzható rá. A w=0, hiszen bájtos műveletről van szó. A reg=011, mivel a műveletben a BL regiszter szerepel. A közvetlen adat amit be kell töltenünk, data=10. 2.8.7.
Határozzuk meg a MOV AX, 5 utasítás gépi kódját!
Utasítás
OP KÓD
MOV AX,5
1011wreg 10111000
MOD
REG
R/M
DISP/ DATA data 00000101
DISP/ DATA (data) 00000000
DATA
DATA
Erre a feladatra a MOV reg, data 3- as
formula húzható rá. A w=1, mivel szavas műveletről van szó, az AX regiszter 16 bites, 1 szavas. A reg=000, mivel az utasításban az AX regiszter szerepel. A közvetlen adat, amit be kell töltenünk 5, de mivel szavas műveletről van szó, ezért 2 bájton kell leírnunk a közvetlen adatot, és az alacsonyabb és magasabb helyi értékű bájtot fel kell cserélnünk. 2.8.8.
Határozzuk meg a MOV A2, 5 utasítás gépi kódját!
Utasítás
OP KÓD
MOD
REG
R/M
MOV A2,5
1100011w 11000110
mod 00
reg 000
r/m 110
DISP/ DATA (DISP) 00010000
DISP/ DATA (DISP) 00000000
DATA
DATA
(data) 00000101
(data)
Erre a feladatra a MOV mem, data 2-es
formula húzható rá. A w=0, mivel bájtos műveletről van szó. A mod=00 és r/m=110, mivel a memória operandust direkt címzéssel érjük el. A címképzésben csak az A2 -es szimbólum szegmens kezdetéhez képesti eltolási címe szerepel. Jelen esetben DISP=10H, de ezt szavasan (két bájton) kell leírni, és az alacsonyabb és magasabb helyi értékű bájt helyet cserél. A data=5, mivel 5-öt kell betöltenünk az A2 -es memória változóba. 2.8.9.
Határozzuk meg a MOV A2[SI], 10 utasítás gépi kódját!
Utasítás
OP KÓD
MOD
REG
R/M
MOV
1100011w
mod
000
11000110
10
000
DISP/ DATA (DISP)
DATA
DATA
r/m
DISP/ DATA (DISP)
data
(data)
100
00010000
00000000
00001010
A2[SI],10
Ebben az utasításban használhatjuk a 2 -es (MOV mem, data) speciális esetet. A w=0, hiszen bájtos műveletről van szó (A2-es szimbólum DB direktívával van definiálva). A mod=10, hiszen a kód leírásból látható, hogy 2 bájtos eltolási címmel dolgozunk. A reg mező=000, az r/m=100, hiszen a címszámításban az A2 -es szimbólum DISP értéke mellett az SI vesz részt. 67
A DISP=10H, az A2- es
szimbólum eltolása az adatszegmens kezdetéhez képest 16 bájt. A
betöltendő adat 10. 2.8.10. Határozzuk meg a MOV AX, CX utasítás gépi kódját! Utasítás
OP KÓD
MOD
REG
R/M
MOV AX,CX
100010dw 10001011
mod 11
reg 000
r/m 001
DISP/ DATA (DISP)
DISP/ DATA (DISP)
DATA
DATA
Ha megfigyeljük a speciális formulákat egyik sem húzható rá a feladatra, így marad az 1 -es általános formula. De különbözik az eddigi műveletektől, mivel mindkét operandus regiszter operandus. Ekkor a d bit mindig 1.
A w=1, hiszen szavas műveletről van szó, a mod=11, mivel regiszter operandussal dolgozunk. A d=1, így az r/m bitcsoport a forrás operandust írja le, ez a CX regiszter, melynek kódja 001, vagyis r/m=001. A reg mező a másik regiszter operandust írja le, ez az AX regiszter, melynek a kódja 000, vagyis reg=000. 2.8.11. Határozzuk meg a MOV CX, AX utasítás gépi kódját! Utasítás
OP KÓD
MOD
REG
R/M
MOV CX,AX
100010dw 10001011
mod 11
reg 001
r/m 000
DISP/ DATA (DISP)
DISP/ DATA (DISP)
DATA
DATA
A d=1, mivel mindkét operandus regiszter. A w=1, hiszen szavas műveletről van szó, a mod=11, mivel regiszter operandussal dolgozunk. A d=1, így az r/m bitcsoport a forrás operandust írja le, ez a z AX regiszter, melynek kódja 000, vagyis r/m=000. A reg mező a másik regiszter operandust írja le, ez a CX regiszter, melynek a kódja 001, vagyis reg=001. 13
2.8.12. Határozzuk meg a LEA BX, A2 utasítás gépi kódját! Utasítás
OP KÓD
MOD
REG
R/M
LEA BX,A2
10001101
mod 00
Reg 011
r/m 110
DISP/ DATA (DISP) 00010000
DISP/ DATA (DISP) 00000000
DATA
DATA
Ezzel az utasítással a BX regiszterbe betöltjü k az A2-es memória változó ofszet címét, vagyis a DISP értéket. A mod és az r/m mezők értéke 00, 110, mivel direkt címzésről van szó. A reg mező az utasításban résztvevő regiszter kódja, reg=011. 2.8.13. Határozzuk meg az ADD BX, AX utasítás gépi kódját!
14
Ezzel az utasítással a BX regiszter tartalmához hozzáadjuk az AX regiszter tartalmát. Az eredmény a BX regiszterben képződi k. Mint a táblázatból látható, a három lehetséges eset közül az első (általános) kell használnunk. Utasítás
OP KÓD
MOD
REG
R/M
ADD BX,AX
000000dw 00000011
mod 11
Reg 011
r/m 000
DISP/ DATA (DISP)
DISP/ DATA (DISP)
DATA
DATA
Mivel mindkét operandus regiszter, ezért a d=1. A w=1, hiszen szavas műveletről van szó. A mod=11, mivel regiszter operandussal dolgozunk.
13
AsmKodTabla 3. oldal AsmKodTabla 4. oldal 68 14
A d=1, így az r/m bitcsoport a forrás operandust írja le, ez az AX regiszter, melynek kódja 000, vagyis r/m=000. A reg mező a másik regiszter operandust írja le, ez a BX regiszter, melynek a kódja 011, vagyis reg=011. 15
2.8.14. Határozzuk meg a MUL BL utasítás gépi kódját!
Ennél az utasítás csoportnál az operandus Utasítás OP. Kód típusa határozza meg, hogy melyik formulát MUL BL 11110110 kell alkalmaznunk. Bájtos szorzást végzünk, hiszen a BL regiszter bájtos, így a MUL reg (8 bit) formulát kell használnunk.
11100reg 11100011
2.8.15. Határozzuk meg a MUL CX utasítás
gépi kódját! Ennél a példánál szavas szorzást végzünk, hiszen a CX regiszter szavas, így a MUL reg (16 bit) formulát használjuk.
Utasítás MUL CX
OP. Kód 11110111
11100reg 11100001
16
2.8.16. Határozzuk meg az INC SI utasítás gépi kódját!
Mint a táblázatból látható, két eset közül kell Utasítás OP. Kód INC SI 01000reg választanunk. A második eset egy speciális eset, 01000110 amikor valamely regiszter tartalmát inkrementáljuk (növeljük) egyel. Ebben a példában ezt használhatjuk. A művelet op. kódjában a reg=110, hiszen a műveletben az SI indexregiszter vesz részt. 2.8.17. Határozzuk meg az INC A2 utasítás gépi kódját! Utasítás
OP KÓD
MOD
REG
R/M
INC A2
1111111w 11111110
mod 00
000 000
r/m 110
DISP/ DATA (DISP) 00010000
DISP/ DATA (DISP) 00000000
DATA
DATA
A w=0, mivel az A2- es
szimbólummal jelölt memória operandus bájtos. A mod=00 és r/m=110, hiszen direkt címzésről van szó. A DISP=10H, az A2 -es szimbólum eltolása az adatszegmens kezdetéhez képest. 2.8.18. K észítsük el egy egyszerű program (cikluson belüli néhány utasításának gépi kódú
listáját )! Legyen ez a program a maximum
kiválasztás tétele!
A programrészlet: ADAT T MAX ADAT CIKL:
TOV:
SEGMENT DB 23, -10, DB ? ENDS MOV AL,T[SI] CMP AL,MAX JLE TOV MOV MAX,AL INC SI LOOP CIKL
25, 31, 46, -21, -65, 125, 40, 67 ;AZ AKTUALIS LEGNAGYOBB ELEM ;HASONLITJUK A TOMB AKTUALIS ELEMET AZ EDDIGI ;LEGNAGYOBB ELEMHEZ ;HA <=, AKKOR NINCS TEENDONK, UGRUNK ;HA (AL)>MAX, AKKOR MEGJEGYEZZUK ;CX TARTALMA 1-EL CSOKKEN. UGRAS, HA CX NEM 0
15
AsmKodTabla 5. oldal AsmKodTabla 5. oldal
16
69
2.8.19. Határozzuk meg a CMP AL,MAX utasítás gépi kódját! Utasítás
OP KÓD
MOD
REG
R/M
CMP AL, MAX
001110dw
mod
000
00111010
00
000
r/m
DISP/ DATA (DISP)
DISP/ DATA (DISP)
110
00001010
00000000
DATA
DATA
Keressük meg a kód táblázatunkban a CMP (összehasonlító) utasítást. Itt három kódok találunk, az első az általános eset, a másik kettő speciális eset. esetben az akkumulátor regiszter értékét hasonlítjuk egy memória változó értékéhez, vagyis az általános esetet kell alkalmaznunk. A w=0, mivel bájtos műveletről van szó. A mod r/m bájt a memória operandust írja le. Mivel a memória operandus a forrás operandus, így a d=1. Mivel a MAX nevű memória operandust direkt címzéssel érjük el, így mod=00, r/m=110. A DISP=0AH, mivel a MAX változó eltolása az adat szegmens kezdetéhez képest 10 bájt. A kódtáblabeli leírásból látható, hogy a DISP értékét két bájton kell leírni. Jelen
2.8.20. Határozzuk meg a JLE TOV utasítás gépi kódját! Utasítás
OP KÓD
JLE
01111110
TOV
MOD
REG
R/M
DISP/ DATA disp 00000011
DISP/ DATA
DATA
DATA
Keressük meg a kód táblázatunkban a vezérlésátadó utasításokat! A JLE címke utasítás esetén azt látjuk, hogy az OP kód: 7E. A gépi kódban szerepel még a disp eltolási cím. A táblázatban használt jelöléseknél látható, hogy a disp relatív eltolást jelent. Meg kell határoznunk, hogy az a címke, amelyre át kell adnunk a vezérlést (rá kell ugranunk) hány bájtra található az éppen aktuális utasítástól. Ez lehet pozitív vagy negatív szám is attól függően, hogy a címke a vezérlés átadó utasítás előtt vagy mögött van. Ahhoz, hogy ezt ki tudjuk számolni meg kell határozni a vezérlésátadó utasítás és a címke között található utasítások bájtban kifejezett hosszát. Ha meghatározzuk a MOV MAX,AL utasítás gépi kódját, akkor látható, hogy ez 3 bájtos utasítás, vagyis a TOV címke relatív eltolása az ugró utasításhoz képest 3 bájt. 2.8.21. Határozzuk meg a LOOP CIKL utasítás gépi kódját! Utasítás
OP KÓD
LOOP CIKL
11100010
MOD
REG
R/M
DISP/ DATA disp 11110010
DISP/ DATA
DATA
DATA
A LOOP címke utasítás esetén azt látjuk, hogy az OP kód: E2. A gépi kódban szerepel még a disp eltolási cím, amely az előző példához hasonlóan egy relatív eltolási cím. Jelen esetben ez egy negatív szám lesz, mivel a LOOP előtt található a CIKL nevű címke. Meg kell határoznunk, hogy hány bájt van a LOOP és a CIKL nevű címke között (magát a LOOP utasítás bájtokban kifejezett hosszát is bele kell számolni). Jelen esetben azt látjuk, hogy 16 bájt. Vagyis -16 bájttal távolabb levő utasításra kell adni a vezérlést. A negatív számokat kettes komplemens kódban ábrázoljuk, vagyis: 16 d=00010000b, -16d=11110000b
70
2.9.
Önállóan kidolgozandó feladatok ASM
2.9.1.
Címzési módok, aritmetikai utasítások, ciklusok
1.
Adja össze 2 memóriabájt értékét, majd képezze egy memóriaszó és egy memóriabájt különbségét! a) A két memóriabájt értéke legyen FF, az eredmény képződjön bájton! Mit tapasztal? CF=?
b) A két memóriabájt értéke legyen FF, az eredmény képződjön szón! Mit tapasztal? CF=? 2.
Készítsen programot, amely összead két memóriában tárolt bájtos adatot, és az eredményt letárolja a memóriában!*
3.
Készítsen programot, amely két memóriában tárolt bájtos adat szorzatát képzi, és az eredményt letárolja a memóriában !*
4.
Készítsen programot, amely két memóriában tárolt bájtos adat hányadosát képzi, és az eredményt (hányados és maradék) a memóriában tárolja!*
5.
Készítsen programot, amely a memóriában letárolt 5 bájtos adat (tömb elemeinek) összegét képzi, és az eredményt letárolja szavasan a memóriában !*
6.
Készítsen programot, amely megadja, hogy a memóriában letárolt 5 bájtos adat (tömb elemei) között hány darab páros elem van !*
7.
Írjon egy olyan programot, amely a saját nevével inicializált memóriarész tartalmát átpakolja az adott szegmensen belül lefoglalt másik memóriaterületre ! Az átpakolást végezze el úgy, hogy a) indexelt címzést használjon és az átpakolást az első karakterrel kezdje, b) indexelt címzést használjon és az átpakolást az utolsó karakterrel kezdje !
8.
Készítsen olyan programot, amely megadja a memória egy bizonyos területén letett 10 db bájtos adat közül a páratlan elemek darabszámát és összegét!
9.
Készítsen olyan programot, amely a memóriában letett 10 db bájtos adat közül meghatározza a legnagyobb elemet! *
10. Másoljon át egy 10 elemű
bájtos tömböt egy szavas tömbbe!
11. Fordítsa meg egy 10 elemű szavas tömb
elemeinek sorrendjét helyben!
12. Adott egy 10 bájtos tömb feltöltve. Másolja át egy 10 szavas tömbbe a bájtos tömb
elemeit fordított sorrendben!* 13. Adott egy 10 szavas tömb feltöltve. Minden szó alsó helyi értékű bájtját
helyezze el egy
bájtos tömbbe! 14. Adott egy 10 bájtos tömb feltöltve. Adja össze az elemeket, és helyezze el memóriaváltozóban! (Az összeg 16 bites lesz!)
az összeget egy
71
15. Adott egy 10 szavas tömb feltöltve. A tömb minden elemét ossza el 5 -tel, és a
hányadosokat egy tömbben helyezze el! (Milyen méretű lesz a hányados?) * 16. Adott egy 10 bájtos tömb feltöltve, valamint egy 5 szavas tömb. A bájtos tömb
számpárjainak szorzatát állítsa elő a szavas tömbbe! (A bájtos tömb első 2 elemének szorzatát helyezze a szavas tömb első elemébe,…stb.) 17. Definiáljon egy 20 elemű bájtos és egy 20 elemű szavas tömböt! A bájtos tömböt töltse fel
az első 20 páratlan számmal, majd a négyzetüket helyezze el a szavas tömbbe! 18. Adott egy 10 bájtos tömb feltöltve. Rendezze át a tömbelemeket úgy, hogy minden elem
1
hellyel előrelép, és az első elem a tömb utolsó helyére kerül! * 19. Adott egy 10 elemű szavas tömb
feltöltve. Helyezze át egy másik tömbbe az elemeket bájtonként regiszter indirekt címzéssel! (LEA utasítás használata)
2.9.2.
Klaviatúra - képernyő I/O, összehasonlítás, vezérlés átadás
20. Írja ki a
képernyőre a "Hello Világ!" szöveget!
21. Írjon olyan programot, amely a billentyűzetről beolvassa a saját nevét, elhelyezi egy
sztringben, majd kiírja a standard outputra, úgy, hogy minden karakter után tesz egy szóközt! 22. Írjon olyan programot, amely egy sztring karaktereit kiírja a standard outputra fordított sorrendben! 23. Írja ki
a képernyőre karakterenként a decimális számjegyeket csökkenő sorrendben, majd külön sorba írja ki az angol ABC 26 nagybetűjét az ABC szerinti sorrendben! (Ne használjon tömböt!)
24.
Olvasson be maximum 80 karaktert a klaviatúráról, enter végjelig! Ezután írja ki a képernyőre a kapott karaktersorozatot a decimális számjegy karakterek kihagyásával!
2.9.3.
Bitműveletek - logikai utasítások
25. Egy 5 bájtos memóriaterületen helyezzünk el ASCII kódú számjegyeket. Töröljük az
egyes számjegyek zónarészét! 26. Egy 20 elemű szavas tömb minden elemét
tegye 8 -cal oszthatóvá úgy, hogy a számokat az osztási maradékkal csökkenti! Nem használhat DIV utasítást! *
27. Egy tetszőlegesen feltöltött 10 elemű bájtos tömb
minden elemében a 4 -es és az 5 -ös bit
legyen 1 értékű! 28. Egy 10 bájtos memóriaterületen helyezzük el a
lehetséges decimális számjegy értékeket tetszőleges sorrendben, majd egy ciklusban írjuk ki a bájtok értékei szerinti számjegyeket! (Kiírni csak ASCII kódú karaktereket tudunk)
29. Olvasson be maximum 80 karaktert a klaviatúráról, enter végjelig!
Írja ki a képernyőre a kapott karaktersorozatot fordított sorrendben, majd az előfordult decimális számjegy karakterek számát is!
72
30. Számlálja meg egy 20 elemű szavas tömb 4 -gyel osztható elemeit, és az eredményt írja ki
a képernyőre! Nem használhat DIV utasítást! * 31. Egy 10 bájtos memóriaterületen helyezzünk el ASCII kódú számjegyeket. Töröljük az
egyes számjegyek zónarészét! 32. Írjon olyan programot, amely egy 16
bites értéket binárisan kiír a képernyőre!
33. Írjon olyan programot, amely a memória ötödik szavában előforduló 1 értékű bitek
számát
kiírja a képernyőre! 34. Írjon olyan programot, amely a PSP
első szavában előforduló 0 értékű bitek számát kiírja
a képernyőre! 35. Írjon olyan programot, amely beolvas a klaviatúráról egy
legfeljebb 16 jegyű bináris számot ellenőrzéssel, majd a bináris értéket elhelyezi egy szavas változóban!
36. Írjon olyan programot, amely egy legfeljebb 10
jegyű decimális számot ellenőrzéssel beolvas a standard inputról, majd a beolvasott számjegyeket egy 10 bájtos puffer területre átpakol úgy, hogy a pufferben a számjegyek jobbra igazítottan, vezető nullákkal feltöltve helyezkedjenek el!
37. Írjon olyan programot, amely egy maximum
12 jegyű decimális számot ellenőrzéssel beolvas a standard inputról, majd megállapítja, hogy a beolvasott szám osztható -e 9-cel! Az eredményről írjon szöveges üzenetet a képernyőre!
38. Adott egy 10 szavas tömb feltöltve. Állapítsa meg, van -e olyan tömbelem, amelyben az 1 értékű bitek száma osztható 4 -gyel! 39. Adott egy 10 szavas tömb feltöltve. Írja ki annak
az elemnek a sorszámát, amelyben az 1
értékű bitek száma a legnagyobb! 40. Adott egy 20 bájtos tömb feltöltve. Írja ki, hogy hány tömbelemben páros az 1 értékű
bitek száma! 41. Írjon olyan programot, amely egy legfeljebb 4 jegyű decimális számot ellenőrzéssel beolvas a standard inputról, majd a beolvasott számot binárisan elhelyezi egy szavas változóba. Végül írja ki külön -külön ennek a szónak a bájtjait decimálisan a képernyőre! Mit tapasztal? A program működjön ciklusban!* 42. Írjon olyan programot, amely egy legfeljebb 4
jegyű hexadecimális számot ellenőrzéssel beolvas a standard inputról, majd a beolvasott számot binárisan kiírja a képernyőre! A program működjön ciklusban!
43. Írjon olyan programot, amely egy legfeljebb 16
jegyű bináris számot beolvas ellenőrzéssel a klaviatúráról, majd a hexadecimális megfelelőjét kiírja a képernyőre! A program működjön ciklusban!
73
2.9.4. Alprogramok 44. Írjon olyan programot, amely a billentyűzetről beolvas kettő , max. 5 jegyű számot, és a beolvasott számokat binárisra konvertálja! Adja össze a két számot, majd az eredményt
írja ki a képernyőre! * 45. Írjon olyan programot, amely a - a billentyűzetről beolvas 2 (maximum 5 jegyű) számot - elosztja a két számot, - az eredményt (külön a hányadost és a maradékot) kiírja a képernyőre! 46. Válassza ki egy 20 elemű szavas tömb
legnagyobb elemét, majd írja ki a képernyőre a
legnagyobb elem sorszámát! 47. Írjon olyan programot, amely megszámolja egy bájtos adatokból álló tömb
páros elemeit!
A megszámolást procedúrával végezze! a) A paraméterátadás regisztereken keresztül történjen! b) A paraméterátadás a stack memórián keresztül történjen! 48. Írjon olyan programot, amely megszámolja egy bájtos adatokból álló tömb
páros elemeit!
A megszámolást makróval végezze! 49. Írjon olyan programot, amely összead két bájtos
adatot! Az eredmény szavas legyen (az
összeadást procedúrával végezze)! a) A paraméterátadás regisztereken keresztül történjen! b) A paraméterátadás a stack memórián keresztül történjen! 50. Írjon olyan programot, amely egy 10 db bájtos adatból álló tömb elemeit összegzi! Az
összegzést procedúrával végezze! a) A paraméterátadás regisztereken keresztül történjen! b) A paraméterátadás a stack memórián keresztül történjen! 51. Írjon olyan programot, amely egy 10 db bájtos adatból álló tömb páratlan elemeit
összegzi! Az összegzést procedúrával végezze! a) A paraméterátadás regisztereken keresztül történjen! b) A paraméterátadás a stack memórián keresztül történjen! 52. Írjon olyan programot, amely megadja egy 10 db
bájtos adatból álló tömb legnagyobb elemét! A maximum kiválasztást procedúrával végezze! a) A paraméterátadás regisztereken keresztül történjen! b) A paraméterátadás a stack memórián keresztül történjen!
53. Írjon olyan programot, amely a - a billentyűzetről beolvas 2 (maximum 5 - összeadja a két számot, - az eredményt kiírja a képernyőre!
jegyű) számot
A *-gal jelölt feladatok megoldásai megtalálhatók a jegyzetben. 74