Tartalmi kivonat
Pohl László C++ gyak. és labor jegyzet BME 2006 Tartalom Tartalom . 2 Bevezetés. 4 1. UNIX gyorstalpaló [labor] 5 1.1 Bejelentkezés 5 1.2 stty 5 erase, kill, intr, echo . 6 raw és cooked. 6 fontos. 6 1.3 Alapvető parancsok 6 2. Integrált fejlesztőkörnyezet [labor] 8 3. C ismétlés [gyakorlat] 10 3.1 Feladat 10 3.2 Feladat 10 3.3 Feladat 10 3.4 feladat 11 3.5 feladat 11 4. Const, referencia, string [labor] 14 4.1 Const 14 4.2 Referencia 15 4.3 String 16 5. Vándorlás C-ről C++-ra [gyakorlat] 19 5.1 C++ kiírás 19 5.2 Mutatók, tömbök, referenciák 19 5.21 Változók 19 5.22 Swap 20 5.3 Függvények 20 5.4 cin, cout, cerr 21 5.5 Kivétel 21 5.6 Stack, névtér, kivétel 22 6. Osztályok és operátorok [gyakorlat] 24 6.1 Osztály struct-ból 24 6.11 Osztály 24 6.12 Objektumok és szorzás 24 6.13 Szorzás valóssal 26 6.14 Abszolút érték 26 6.15 Házi feladat 27 6.2 Osztály class-ból 27 6.21 Osztály 27 6.22 Konstruktor 28 6.23
Egyenlőségjel operátor 30 6.24 Kiírás és beolvasás 31 6.25 Nem inline tagfüggvény 31 6.26 Konstruktorok összevonása 32 6.27 Házi feladat 32 7. String osztály [labor] 33 Feladatok . 33 string class h.cpp 33 2 string2.cpp 37 8. Dinamikus adattagokat tartalmazó osztályok [gyakorlat] 40 8.1 10 komplex szám tárolására alkalmas tömb 40 8.2 Diákok adatai példa 41 8.3 Gyakorló feladatok: 44 9. Öröklés 45 9.1 Ablakok 45 9.2 IOSTREAM 48 F Hivatkozások . 52 3 Bevezetés Ez a jegyzet azokat a gyakorlati ismereteket kívánja bemutatni, melyek a C++ programozás tanulása során felmerülnek, és a tárgy tematikának részei. A C++ nyelvet, hasonlóan a beszélt nyelvekhez, nem lehet elsajátítani önálló tanulás nélkül, ezért mindenképpen oldjunk meg gyakorló feladatokat óráról órára, egyedül, otthon! A példaprogramokat nem kell begépelni. A jegyzet elektronikus formában a http://www.eetbmehu/~pohl/ oldalon megtalálható, a pdf-ből ki
lehet másolni a szöveget, ha az Adobe Reader felső eszköztárán a Select Text-et választjuk, de a példaprogramok zip-elve is letölthetők ugyanonnan, így még a formázás is megmarad. A jegyzettel kapcsolatos kritikákat, hibalistákat a pohl@eet.bmehu címre várom 4 1. UNIX gyorstalpaló [labor] A félév során végig C++-szal fogunk foglalkozni, de bevezetésképp nagyon röviden megismerkedünk a UNIX legfontosabb parancsaival. Irodalom: [1,2,3] 1.1 Bejelentkezés Az Ural2 szerveren futó UNIX használatához témaszámra van szükség, mely a megfelelő operátori fülkékben átvehető. A számítógépen indítsuk el a Windowst, innen a putty.exe terminál programmal tudunk bejelentkezni az Ural2-re. Az Ural2 eléréséhez használjuk az SSH módot (11 ábra)! 1.1 ábra: A putty terminál konfigurációs képernyője Ha helyesen töltöttük ki a konfigurációs adatokat, és az Open gombra kattintunk, egy szöveges terminál ablak jelenik meg. Itt először
meg kell adni azonosítónkat és jelszavunkat Ha először jelentkezünk be, a rendszer új jelszót kér. A jelszó legalább 6 karakter legyen, és tartalmazzon legalább egy számjegyet és két betűt az első hat karakterében. Ha sikeresen bejelentkeztünk, kapunk néhány tájékoztató üzenetet, és megjelenik a prompt. Ide írhatjuk a parancsokat. Figyeljünk arra, hogy a UNIX érzékeny a kis- és nagybetűk megkülönböztetésére! 1.2 stty Azaz set teleltype. Írjuk be, hogy stty -a Ennek hatására megjelennek a konzol beállításai. Pl: speed 9600 baud; line = 1; intr = ^C; quit = ^; erase = DEL; kill = ^U; eof = ^D; eol <undef>; swtch = ^Z lnext = ^V; werase = ^W; rprnt = ^R; flush = ^O; stop = ^S; start = ^Q -parenb -parodd cs8 -cstopb hupcl cread clocal -loblk -tostop -ignbrk brkint ignpar -parmrk -inpck istrip -inlcr -igncr icrnl -iuclc 5 ixon -ixany -ixoff isig icanon -xcase echo echoe echok -echonl -noflsh opost -olcuc onlcr -ocrnl -onocr -onlret
-ofill -ofdel tab3 Ezek közül csak néhánnyal foglalkozunk. erase, kill, intr, echo Alapértelmezés szerint általában az stty erase DEL szerepel, vagyis a DEL billentyűvel törölhetünk. Ha a # billentyűvel szeretnénk törölni, írjuk ezt: stty erase # ! Ha ki akarjuk törölni a parancssorba eddig begépelt összes szöveget, a kill funkciót használjuk. A fenti esetben ez ^U, azaz Ctrl+U Ha ki akarunk lépni egy futó programból, az intr funkciót használjuk, ami általában Ctrl+C. stty echo, stty –echo: az elsőt beállítva a leütött billentlyűk megjelennek a képernyőn, a második esetben (--szal) nem, ilyenkor tehát vakon kell gépelnünk. raw és cooked stty raw, vagy stty -cooked esetén nem dolgozza fel a rendszer a vezérlő karaktereket (pl. a kill, erase stb-t sem), stty –raw vagy stty cooked esetén feldolgozza. További részletetek: http://www.szabilinuxhu/ufi/13 1html#egy ill man parancs fontos A bash raw módot kapcsol, ezért valójában a
kill és az erase nem az, amit beállítunk. Viszont ha egy programot elindítunk (pl. cat), már az stty-nal beállított értékek vannak érvényben 1.3 Alapvető parancsok További parancsokért, illetve a parancsok további beállításaiért lásd [1,2,3]. man A UNIX elektronikus kézikönyvében (manual) kereshetünk vele. ls Kilistázza a mappa tartalmát. Néhány kapcsolója: -a: minden állományt listáz -l: részletes adatokat közöl az állományokról -r: fordított sorrendben listáz -t: időrendben listáz A kapcsolókat össze is vonhatjuk. Pl: ls –alrt cat Összefűzi a paraméterként kapott fájlokat, és kiírja azokat a standard kimenetre. Ha nem írunk paramétert, vagy --t írunk, a standard bemenetről olvas EOF-ig. (Az EOF-ot is beállíthatjuk a stty-nal). Fájl kiírása a képernyőre: cat fajlnev Két fájl összefűzése: cat fajlnev1 fajlnev2 > fajlnev3 Az eredmény a fajlnev3-ba kerül. 6 echo A paraméterként kapott szöveget
megjeleníti a standard outputon. cd Change directory: mappaváltás. cd . : egy mappával feljebb cd / : a gyökérbe cd mappanev : a mappanev nevű mappába pwd Print working directory: kiírja a munkamappa (az aktuálisan használt mappa) nevét. passwd Új jelszót adhatunk meg. rm, rmdir Fájl ill. mappa eltávolítására rm * : kitörli az aktuális mappából az összes fájlt. (Vigyázat, nincs kuka, ahonnan visszaállítsuk!) mkdir Új mappa létrehozása. mv Fájl mozgatása vagy átnevezése. more Fájl kiírása a standard outputra. cp Fájl másolása. -r vagy –R: rekurzív másolás, azaz ha a forrás mappa, annak tartalmát a célmappába másolja chmod Fájl vagy mappa védelmi kódjának módosítása. Csak a tulajdonos, vagy rendszergazda változtathatja. chmod g-rwx fájlnév : megtiltja az írást, olvasást és végrehajtást a csoporttársaknak chmod 0764 fájlnév : a tulajdonos írhat, olvashat, végrehajthat, a csoporttagok olvashatnak és
írhatnak, a többi felhasználó csak olvashat. Feladat: http://www.iitbmehu/~szebi/unixlab/vedelemhtml ln Link vagy szimbolikus link létrehozása. ln forrasfajl ujnev : létrehozza az ujnev nevű linket forrásfájlra. A kettőnek fizikailag azonos disken kell lennie. ln –s forrasfajl ujnev : létrehozza az ujnev nevű szimbolikus linket forrásfájlra. A kettőnek nem kell fizikailag azonos disken lennie. df Display free disk space du Disk usage. Feladatok: http://www.iitbmehu/~szebi/unixlab/feladat1html A haladók megpróbálhatják első szorgalmi házijukat elérni. Fájlok feltöltésére jól használható a WinSCP nevű program, melyben commanderhez hasonlóan tudunk fájlokat másolni. 7 2. Integrált fejlesztőkörnyezet [labor] A laboron tetszőleges korszerű C++ fordító használható (a borland C++ nem ilyen). A jegyzetben a Visual C++ .NET 2003-mal találkozhatunk majd Ebben kicsit másképpen kell létrehozni a Console Application projektjét. 1. lépés:
2. lépés: 3. lépés: 8 4. lépés: 5. lépés: 9 3. C ismétlés [gyakorlat] 3.1 Feladat Készítse el a „Hello Világ!” programot szabványos C nyelven, pontosvessző használata nélkül! 3.2 Feladat Készítsen szabványos C programot, mely a paraméterként kapott szöveges fájlt olyan formában írja a képernyőre, hogy csak a magánhangzók, és a soremelések maradnak a helyükön, az összes többi helyett szóköz jelenjen meg! Egy megoldás: //* #include <stdio.h> #include <stdlib.h> //* //* void error(const char * s){ //* printf("%s",s); exit(-1); } //* void main(int argc,char * argv){ //* int c; FILE * fp; if(argc<2)error("Tul keves parameter, inditaskor adja meg a hivando fajl nevet!"); if((fp=fopen(argv[1],"rt"))==NULL)error("Nem tudom megnyitni a fajlt"); while((c=getc(fp))!=EOF){ switch(toupper(c)){ case 'A': case 'E': case 'I': case 'O': case
'U': case ' ':fprintf(stdout,"%c",c);break; default: fputc(' ',stdout); } } } A programban nem használtuk a feof() függvényt, mert utólag működik, ami azt jelenti, hogy akkor jelzi, hogy a fájl végére értünk, ha már egy művelet sikertelen volt. Emiatt jobban járunk, ha a művelet sikertelenségére figyelünk. Beolvasásnál használhattuk volna a fscanf() függvényt is, ebben az esetben nem azt nézzük, hogy a visszatérési érték egyenlő-e az EOF konstanssal, mert sohasem lesz egyenlő, hanem azt, hogy a visszatérési érték megegyezik-e a beolvasni kívánt változók számával. 3.3 Feladat a) Írjon függvényt, mely kiszámítja két egész szám összegét és négyzetösszegét! b) Írjon programot, mely egészekből álló számpárokat olvas a standard inputról, meghívja a fenti függvényt, kiírja az összeget és négyzetösszeget, egész addig, míg az egyik beolvasott szám 0 nem lesz. Nem használhat
globális változókat! Egy megoldás: 10 //* #include <stdio.h> #include <stdlib.h> //* //* void osszegzo(int a,int b,int * sum,int nsum){ //* *sum=a+b; *nsum=aa+bb; } //* void error(const char * s){ //* printf("%s",s); exit(-1); } //* void main(){ //* int a,b,s,ns; fflush(stdin); if(scanf("%d %d",&a,&b)!=2)error("Sikertelen beolvasas"); while(a!=0&&b!=0){ osszegzo(a,b,&s,&ns); printf("ossz=%d negyzetossz=%d ",s,ns); fflush(stdin); if(scanf("%d %d",&a,&b)!=2)error("Sikertelen beolvasas"); } } Olvassuk el a C jegyzet 7.12 fejezetében a veremkezelésről szóló részt! Mi történik, ha lemarad az & jel a függvényhívásnál? 3.4 feladat Írjon függvényt, mely kiszámítja két, paraméterként kapott double típusú szám szorzatát! Írjon függvényt, mely kiszámítja két, paraméterként kapott, stringként megadott valós szám szorzatát, és az eredményt egy
paraméterként kapott karaktertömbben adja vissza! Egy megoldás: //* void mul(const char * a,const char b,char c){ //* double d1=0,d2=0,d3; sscanf(a,"%lg",&d1); sscanf(b,"%lg",&d2); d3=d1*d2; sprintf(c,"%g",d3); } 3.5 feladat Írjon programot, mely tartalmaz egy struktúra típust: //* struct String{ //* char * p; int len; }; Készítsen függvényt, mely • összefűz két ilyen Stringet • visszaadja a String valahányadik karakterét (azaz indexeli) • létrehoz egy ilyen típusú változót egy char * típusú stringből • létrehoz egy ilyen típusú változót egy karakterből 11 • kiír egy ilyen Stringet • kitörli a paraméterként kapott Stringből a dinamikus tömböt Készítsen main függvényt, melyben ezt kipróbálja! Nem használhat globális változókat! Egy megoldás: //* #include <stdio.h> #include <stdlib.h> #include <string.h> //* //* struct String{ //* char * p; int len; }; //* void
error(const char * s){ //* printf("%s",s); exit(-1); } //* String osszefuz(const String a,const String b){ //* String c; int n=a.len+blen+1; c.len=n-1; c.p=(char *)malloc(nsizeof(char));//a sizeof(char) definíció szerint 1 if(c.p==NULL)error("osszefuz -> Memoriafogalalas nem sikerult!"); for(int i=0;i<a.len;i++)cp[i]=ap[i]; for(int i=0;i<b.len;i++)cp[i+alen]=bp[i]; c.p[clen]=0; return c; } //* char index(const String s,const int n){ //* return (n>=0&&n<s.len)?sp[n]:0; } //* String letrehoz1(const char * s){ //* String a; a.len=strlen(s); a.p=(char*)malloc(a.len+1);// most nem írjuk ide a sizeof-ot if(a.p==NULL)error("letrehoz1 -> Memoriafogalalas nem sikerult!"); strcpy(a.p,s); return a; } //* String letrehoz2(const char c){ //* String a; a.len=1; a.p=(char*)malloc(2);// most nem írjuk ide a sizeof-ot if(a.p==NULL)error("letrehoz2 -> Memoriafogalalas nem sikerult!"); a.p[0]=c; a.p[1]=0; return a; } 12 //*
void kiir(const String s){ //* printf("%s",s.p); } //* void torol(String * s){ //* free(s->p); s->p=NULL; s->len=0; } //* void main(){ //* String a=letrehoz1("Sikerult "); String b=letrehoz2('a'); String c=letrehoz1(" letrehozas"); String d=osszefuz(a,b); String e=osszefuz(d,c); kiir(e); torol(&a); torol(&b); torol(&c); torol(&d); torol(&e); } Ebben a programban már használtunk néhány C++ elemet. C++-ban a struktúra (és az enumé is) neve típusnak számít, tehát ezzel közvetlenül létre lehet hozni ilyen változót (pl. nem kellett odaírni a main()-ben, hogy struct String a). A másik: C++-ban bárhol lehet definiálni változót, ahol egyébként utasítás állhat, tehát nem csak blokk elején. Pl: for(int i=0;i<alen;i++)cp[i]=ap[i]; A szabványos C++-ban a for fejében definiált i változó lokális a for ciklusra nézve, tehát azon kívül nem látszik, ezért szerepelhet a következő sorban
egy ugyanolyan definíció. Figyelem! A Visual C++ 6-ban ez nem igaz, ott az így definiált i később is látszik. A későbbi Visual C++ fordítók már elfogadják a szabványos felépítést is, meg a korábbiból örököltet is, ami annyit jelent, hogy a szabványosan megírt program is lefordul, nem szól amiatt, hogy a változót újradefiniáltuk volna, viszont a változó a for cikluson kívül is elérhető marad, ami sajnos egy hibalehetőség. 13 4. Const, referencia, string [labor] 4.1 Const Töltsük le Szeberényi tanár úr oldaláról a http://www.iitbmehu/~szebi/proga2/const hcpp fájlt!: // // Állapítsa meg, hogy milyen hibák vannak az alábbi C++ állományban! // Magyarázza meg, hogy az egyes számozott programrészekben mi miért hiba! // Ha valameyik részben nicsn hiba, akkor azt is indokolja! // // 0. void ff(const int *ip) { *ip = 3; } int main(){ // 1. const int i; // 2. const int j = 10; j++; // 3. const int l = 10; int *p=&l; (*p)++; // 4.
extern void f(int *i); const int iv = 100; f(&iv); // 5. const int ivv = 100; ff(&ivv); // 6. const int v[] = {1,2,3}; v[1]++; // 7. const int siz = 20; int t[siz]; // 8. char s1[] = "Hello konstans szoveg"; const char *pc = s1; pc[0] = 'A'; pc++; // 9. char s2[] = "Hello konstans pointer"; char* const cp = s2; cp[0] = 'B'; cp++; // 10. char s3[] = "Hello konstans szoveg konstans pointer"; const char* const cpc = s2; cpc[0] = 'C'; cpc++; // 11. enum Szinek { tok, zold, makk, piros }; Szinek adu; 14 adu = 1; adu = Szinek(10); return(0); } Találjuk ki, hogy mely sorok hibásak, és miért? Lehetőleg első körben ne használjuk a fordító segítségét! 4.2 Referencia Töltsük le Szeberényi tanár úr oldaláról a http://www.iitbmehu/~szebi/proga2/ref hcpp fájlt!: // // Állapítsa meg, hogy milyen hibák vannak az alábbi C++ állományban! // Magyarázza meg, hogy az egyes számozott programrészekben mi
miért hiba! // Ha valameyik részben nicsn hiba, akkor azt is indokolja! // // 1. long glob; float fglob; // 2. long& fr(){ return glob; } // 3. int& fifi(){ int a; return a; } // 4. int *fp(){ int a; return &a; } // 5. long& fr(long x){ return x; } // 6. long& fr(long& a){ return a; } // 7. float& fr(long x){ return fglob; } // 8. int szg(int a = 1, float x){ return a * x; } // 9. int main(){ fr()++; fr() = 54; fr() = fr() + 4; return 0; } 15 Találjuk ki, hogy mely sorok hibásak, és miért? Lehetőleg első körben ne használjuk a fordító segítségét! 4.3 String Töltsük le Szeberényi tanár úr oldaláról a http://www.iitbmehu/~szebi/proga2/string hc fájlt!: // // Egészitse ki az alábbi C programot a megfelelő helyeken úgy // hogy az működőképes legyen ! // #include <stdio.h> #include <malloc.h> #include <string.h> // Kiiratáshoz // Dinamikus memóriakezeléshez // Stringműveletekhez // A string
struktúránk. // A 'p'-ben vannak a karakterek (a lezáró nullával együtt), 'len' a hossza. // (A lezáró nulla léte vagy hiánya implementációs kérdés). struct String { char *p; // pointer az adatra int len; // hossz lezaró nulla nélkül }; // Stringet készít egy karakterből struct String createFromChar(char ch) { struct String temp; // Meghatározzuk a hosszát temp.len = 1; // Lefoglaljuk a helyet + a lezaro nulla helyet temp.p = (char*)malloc(temp.len+1); // if (temp.p == NULL) mi tegyunk ? Nagyvonaluan elhagyjuk a vizsgálatot // Betesszuk a karaktert temp.p[0] = ch; temp.p[1] = '