Az előadás letöltése folymat van. Kérjük, várjon

Az előadás letöltése folymat van. Kérjük, várjon

Programozási Nyelvek (C++) Gyakorlat Gyak 02. Török Márk D-2.620 1.

Hasonló előadás


Az előadások a következő témára: "Programozási Nyelvek (C++) Gyakorlat Gyak 02. Török Márk D-2.620 1."— Előadás másolata:

1 Programozási Nyelvek (C++) Gyakorlat Gyak 02. Török Márk D

2 Tartalom Erősen típusos nyelvek fogalma Vezérlési szerkezetek Mutatók és dereferálás Függvények bevezetése Paraméterátadás Kódelemzés

3 Típusozás Erősen és gyengén típusos nyelvek Statikus és dinamikus típusrendszerek

4 Típusozás Típus: névvel azonosított halmaz, melyen műveleteket értelmezünk. – értékhalmaz – típusműveletek

5 Erősen típusos nyelv Különböző típusú értékek hogyan adhatóak egymásnak értékül. Valójában nincs egzakt meghatározás rá. Forrás: Ada for the C++ or Java Developer, Quentin Ochem, Technical Papers, AdaCore Nincs implicit típuskonverzió Operandusok azonos típusúak – Primitív művelet esetén – A standard műveletekre értjük, a túlterhelés más!

6 Erősen típusos nyelv (Ada) procedure Strong_Typing is Alpha : Integer := 1 ; Beta : Integer := 10 ; Result : Float; begin Result := Float ( Alpha ) / Float ( Beta ) ; end Strong;

7 Gyengén típusos nyelv Implicit típuskonverzió – Bővítő automatikus – Szűkítő típuskényszerítéssel Hibás végeredmény – Konverzió néha kerekít

8 Gyengén típusos nyelv (C++) void weakTyping ( void ) { int alpha = 1 ; int beta = 10 ; float result; result = alpha / beta; // 0 }

9 Gyengén típusos nyelv (Java) void weakTyping () { int alpha = 1 ; int beta = 10 ; float result; result = alpha / beta; // 0 }

10 Statikus típusrendszer Statikus típusrendszerű nyelv – Minden változódeklarációkor meg kell adni az adott változó típusát. – Azaz fordítási időben minden változóról, minden függvény paraméteréről, illetve minden függvény (művelet) visszatérési értékéről kell tudni, hogy milyen típusú. – Def szerint: a típus meghatározza, hogy milyen műveleteket végezhetek el rajta.

11 Dinamikus típusrendszer Értelmezett (interpretált) nyelvek Automatikus memóriakezelés – Trükközni mindig lehet Deklaráció típus nélkül – Az inicializáláskor dől el, hogy milyen a típusa a változónak Függvények esetén – Nincs visszatérési típus deklarálva – Paraméterátadás: Duck-typing

12 Alap típusok és módosítók Típusok: int, float, double, char, (bool már csak C++-ben) Modifiers: short, long, signed, unsigned int: – short int: -32,768 -> +32,767 (16 bit) – unsigned short int: 0 -> +65,535 (16 bit) – unsigned int: 0 -> +4,294,967,295 (32 bit) – int: -2,147,483,648 -> +2,147,483,647 (32 bit) – long int: -2,147,483,648 -> +2,147,483,647 (32 bit) char: – signed char : > +127 – unsigned char: 0 -> +255 float: 32 bit double: – double : 96 bit – long double : 64 bit

13 Erőssen (?) típusos nyelv (Na, mégegyszer) Házi feladat: Hogy is van ez? #include int main() { short s = 10; short int si = 1; printf ("s : %f\t, si : %f\n", sizeof(s), sizeof(si)); }

14 Típusos nyelv #include int main() { short s = 10; short int si = 1; printf ("s : %d\t, si : %d\n", sizeof(s), sizeof(si)); }

15 Erőssen (?) típusos nyelv Házi feladat: Hogy is van ez? #include int main() { short s = 10; short int si = 1; printf ("s : %f\t, si : %f\n", sizeof(s), sizeof(si)); } A float leveszi a memóriából azt a részt, ami neki kell, így viszont az intnek egy része kimarad!

16 C++ típusrendszere C++-ben a leggyakoribb alaptípusok: – Egész számok típusa: int, short int, long int – Lebegopontos számok típusa: float, double, long double – Logikai típus: bool C-ben int volt a bool megfelelője! – Karakter típus: char – Karakterlánc típus: string Ez C-ben char*

17 C++ típusrendszere C++11 újdonságai – auto fordítás idejű típuskikövetkeztetés – register Regiszterekbe rakja az értékét a változónak a memória helyett, gyorsabb elérést biztosít – dectype

18 Statikus típusrendszer (C++-ben) int main() { auto i; return 0; } error: declaration of ‘auto i’ has no initializer

19 Statikus típusrendszer (C++-ben) int main() { auto i; i = 12; return 0; } error: declaration of ‘auto i’ has no initializer

20 Statikus típusrendszer (C++-ben) int main() { auto i = 12; return 0; }

21 Statikus típusrendszer (C++-ben) #include int main() { auto i = 12; std::cout << typeid(i).name(); // i return 0; }

22 Statikus típusrendszer (C++-ben) #include class Clazz; int main() { auto i = new Clazz(); std::cout << typeid(i).name(); return 0; } error: unable to deduce ’auto’ from ’ ’

23 Statikus típusrendszer (C++-ben) #include class Clazz { }; int main() { auto i = new Clazz(); std::cout << typeid(i).name(); // PlClazz return 0; }

24 Statikus típusrendszer (C++-ben) Függvény visszatérési értékének típusa és a függvény paramétere nem lehet auto típusú!

25 Statikus típusrendszer (C++-ben) int main() { register int i = 12; return 0; }

26 Statikus típusrendszer (C++-ben) #include int main() { int i = 12; decltype(i) j = ’c’; std::cout << typeid(j).name(); // i return 0; }

27 Statikus típusrendszer (C++-ben) Más, statikus típusrendszerű nyelvek (C/C++): Java, C# Ada (Erősen típusos! Láttuk!) Dinamikus típusrendszerű nyelvek: Python, Ruby, Perl Lua JavaScript (Elképesztő gyenge lábakon álló típusrendszer)

28 Deklaráció és értékadás Deklaráció: – típusnév változónév1; – típusnév változónév1, változónév2, …; Értékadás: – változónév = érték; – típusnév változónév = érték; Kezdeti érték: – undefined, ha nincs inicializáció.

29 Deklaráció és értékadás int main() { int i; i = 0; int k; }

30 Deklaráció és értékadás int main() { int i = 0; int k; }

31 Deklaráció és értékadás C-ben: #include int main() { int i, j, k = 0; printf("%d | %d | %d", i, j, k); return 0; }

32 Deklaráció és értékadás C-ben: – Fordítás: gcc dek01.c -o dek01 –Wall – Fordítás eredménye: dek01.c: In function ‘main’: dek01.c:5: warning: ‘i’ is used uninitialized in this function dek01.c:5: warning: ‘j’ is used uninitialized in this function Már gondolhatjuk az előrejelzésből: Nem sikerült, amit szeretnénk! – Output: | | 0 Nem tudunk egy lépésben deklarálni és értékül adni? Vagy mégis?!?!

33 Deklaráció és értékadás C-ben: #include int main() { int i = j = k = 0; printf("%d | %d | %d", i, j, k); return 0; }

34 Deklaráció és értékadás C-ben: – Fordítás: gcc dek01.c -o dek01 –Wall – Fordítás eredménye: dek01.c: In function ‘main’: dek01.c:5: error: ‘j’ undeclared (first use in this function) dek01.c:5: error: (Each undeclared identifier is reported only once dek01.c:5: error: for each function it appears in.) dek01.c:5: error: ‘k’ undeclared (first use in this function) Error! Más út?

35 Deklaráció és értékadás C-ben: #include int main() { int i, j, k; i = j = k = 0; printf("%d | %d | %d", i, j, k); return 0; }

36 Deklaráció és értékadás C-ben: – Fordítás: gcc dek01.c -o dek01 –Wall – Fordítás eredménye: Nincs hiba, sem warning! Siker! – Output: 0 | 0 | 0 Nem tudunk egy lépésben deklarálni és értékül adni? Nem tudunk egy lépésben deklarálni és értékül adni! Házi feladat: És ha egy lépésben deklarálunk, és ott adunk értéket külön- külön az elemeknek?

37 Deklaráció és értékadás Hogy megy ez C++-ben? #include int main() { int i, j, k = 0; std::cout << "|" << i << "|" << j << "|" << k; } Szokásos történet!

38 Deklaráció és értékadás Hogy néz ez ki másik nyelveken? Nézzük meg Adában! with ada.text_io; procedure dek01inada is i, j, k : integer := 0; begin ada.text_io.put_line( Integer'Image(i) & Integer'Image(j) & Integer'Image(k)); end dek01inada;

39 Deklaráció és értékadás Az output: $ gnatmake dek01inada.adb … $./dek01inada Siker! Adában meg lehet csinálni!

40 Üres utasítás A jó öreg skip! ; int main() { ;;; // három üres utasítás return 0; }

41 Vezérlési szerkezetek Elágazás: – Feltétel vizsgálata – Ez lehet egész, logikai vagy object – Ha nem if, akkor else. Ez opcionális – Ha nem if, akkor else if. Ez is opcionális. – else if után jöhet több else if. – else if után jöhet a végén else, opcionálisan.

42 Vezérlési szerkezetek Elágazás (C): #include int main() { int i = 10; if ( i < 15 ) // log kif! { //... } return 0; }

43 Vezérlési szerkezetek Elágazás (C): #include int main() { int i = 10; if ( i < 15 ) // log kif! { //... } else { //... } return 0; }

44 Vezérlési szerkezetek Elágazás (C): #include int main() { int i = 10; if ( i < 15 ) // log kif! { //... } else if ( i > -1 ) { // … } else { //... } return 0; }

45 Vezérlési szerkezetek Elágazás(C++): #include int main() { bool b = true; if ( b ) // log kif! { //... }

46 Vezérlési szerkezetek Elágazás(C++): #include int main() { bool b = false; if ( b == true ) // log kif! { //... } // else … }

47 Vezérlési szerkezetek Elágazás(C): – Ha egy elágazás feltételvizsgálatában nullától különböző számot adunk meg, akkor az megfelel az igaz kiértékelésnek. – float, int, double, short, … #include int main() { int i = 10; if ( i ) // nem log kif, de jó! { //... } // else … }

48 Vezérlési szerkezetek Elágazás(C): – Ha egy elágazás feltételvizsgálatában nulla (0) számot adunk meg, akkor az megfelel a hamis kiértékelésnek. #include int main() { int i = 0; if ( i ) // nem log kif, de jó! { //... } // else … }

49 Vezérlési szerkezetek Elágazás(C++): – Ha nem NULL egy object, akkor true. – Ha NULL egy object, akkor false. #include int main() { Kutya k = new Kutya(); // Később megnézzük, mi ez a Kutya! if ( k ) // nem log kif, de jó! { //... } // else … }

50 Vezérlési szerkezetek Elágazás(C++): – Ha nem NULL egy object, akkor true. – Ha NULL egy object, akkor false. #include int main() { Kutya k = NULL; // Később megnézzük, mi ez a Kutya! if ( k ) // nem log kif, de jó! { //... } // else … }

51 Vezérlési szerkezetek Elágazás(C++): – Nézzük a bugos részt! Mitől döglik a légy? Meg a program? – A feltétel kiértékelése : logikai, szám, object – Értékadás is lehet benne! – Oka: A feltételben szereplő kiértékelés eredményét később is szeretnénk felhasználni. Kevesebb erőforrást használunk! Egyszer értékeljük ki a függvényt, később is használjuk az eredményét

52 Vezérlési szerkezetek Elágazás(C++): – Nézzük a bugos részt! Mitől döglik a légy? Meg a program? – Akkor is előfordul, ha nem szeretnénk! (Gépelési hiba!) – Míg az első kiértékelés false, a második már true! #include int main() { bool b = false; if ( b == true )//log kif { std::cout << ”bent”; } // else … } => Helyett => #include int main() { bool b = false; if ( b = true )// log kif { std::cout << ”bent”; } // else … }

53 Vezérlési szerkezetek Elágazás(C++): – Nézzük a bugos részt! Mitől döglik a légy? Meg a program! – Akkor is előfordul, ha nem szeretnénk! (Gépelési hiba!) – Míg az első kiértékelés false, a második már true! #include int main() { int i = 10; if (i == 0) // log kif! { std::cout << ”bent”; } // else … } => Helyett => #include int main() { int i = 10; if ( i = 0 ) // log kif! { std::cout << ”bent”; } // else … }

54 Vezérlési szerkezetek Elágazás más nyelveken: – Vannak nyelvek, melyek erősebb megszorításokat tesznek az if-ben történő értékadásra! – Nézzük ezt Java-ban. – Szuper! Logikaira ugyanolyan veszélyes! public class Main { public static void main() { boolean l = false; if(l = true) { System.out.println("1"); } else { System.out.println("2"); }

55 Vezérlési szerkezetek Elágazás más nyelveken: – Vannak nyelvek, melyek erősebb megszorításokat tesznek az if-ben történő értékadásra! – Nézzük ezt Java-ban. – Szuper! int-re már nem megy! Fordítási hiba! public class Main { public static void main() { int i = 10; if( i = 0 ) { System.out.println("1"); } else { System.out.println("2"); }

56 Vezérlési szerkezetek Elágazás más nyelveken: – Vannak nyelvek, melyek erősebb megszorításokat tesznek az if-ben történő értékadásra! – Nézzük ezt Ada-ban. – Fordítási hiba! procedure Elag01inada is b : Boolean := true; begin if b := false then null; end if; end Elag01inada;

57 Vezérlési szerkezetek ternary operator (? : ) (condition) ? (if_true) : (if_false) (x == y) ? a : b // GNU C : a = x ? : y; // megegyezik: a = x ? x : y;

58 Vezérlési szerkezetek Más nyelvekben: – Java, C# hasonló – C#-ban: ?? Operator int? x = null; // y = x, ha x nem null, ha viszont az, akkor y = -1. int y = x ?? -1; – javascript, ruby, …: obj = obj || {} obj ||= {};

59 Vezérlési szerkezetek switch: – Nem logikai vizsgálat, hanem illesztés / összehasonlítás switch: integer-expression (int alapú vagy arra konvertálható értékek) – case kiértékelőág. Utasítások végrehajtása egyenlőség vizsgálat után Egy érték egyszer fordulhat elő Több utasítás esetén blokk: { … } Utasításmentes case ág is lehet. Továbbfolyás lehetséges Továbbfolyás megakadályozása: break; – default ág: Ami nem illeszkedik, az ide jön! Nem kötelező a switch végén lennie!

60 Vezérlési szerkezetek switch: #include int main() { int i = 1; switch( i ) { case 0: std::cout << 0; break; case 1: std::cout << 1; break; case 4: std::cout << 4; break; case 5: std::cout << 5; default : std::cout << "def"; }

61 Vezérlési szerkezetek switch: #include int main() { int i = 1; switch( i ) { case 0: { std::cout << 0; std::cout << 1; std::cout << 4; }; break; case 5: std::cout << 5; default : std::cout << "def"; }

62 Vezérlési szerkezetek switch: Továbbfolyás #include int main() { int i = 1; switch( i ) { case 0: std::cout << 0; case 1: std::cout << 1; case 4: std::cout << 4; break; case 5: std::cout << 5; default : std::cout << "def"; }

63 Vezérlési szerkezetek switch: Házi feladat: Mi az eredmény ha: – i = 1; – i = 6; esetén? #include int main() { int i = 1; switch( i ) { case 1: std::cout << 1; default : std::cout << "def"; case 4: std::cout << 4; break; case 5: std::cout << 5; }

64 Vezérlési szerkezetek Ciklus: Előltesztelős #include int main() { int i = 0; while (i < 10) { i += 1; }

65 Vezérlési szerkezetek Ciklus: Hátultesztelős #include int main() { int i = 0; do { // … } while (i < 10); }

66 Vezérlési szerkezetek Ciklus: Számlálós #include int main() { for(int i = 0; i < 10; i += 1) { // … }

67 Vezérlési szerkezetek Ciklus: Számlálós #include int f(int); int main() { for(int i = 0, j = 0; i + j < 10; i = f(j), j += 1) { // … }

68 Vezérlési szerkezetek Ciklus: Végtelen ciklusok #include int main() { for(;;) { // … } int main() { while ( true ) { // … }

69 Vezérlési szerkezetek Ciklus: Feltétlen vezérlést átadó utasítások #include int main() { int i = 1; while ( i < 10 ) { i += 1; std::cout << i << std::endl; if ( i != 5 ) { break; } std::cout << "kint vagyok" << std::endl; }

70 Vezérlési szerkezetek Ciklus: Feltétlen vezérlést átadó utasítások #include int main() { int i = 1; while ( i < 10 ) { i += 1; if ( i < 5 ) { std::cout << i << std::endl; continue; } std::cout << "kesobb jon!" << std::endl; }

71 Vezérlési szerkezetek break; continue; labels

72 Vezérlési szerkezetek Összefoglaló: – using namespace-name::name; – type-name name; – type-name name = value; – type-name name(args); – expression; – { statements; }

73 Vezérlési szerkezetek – while(condition) { statement; } – for(init-statement; condition; expression) { statement; } – if (condition) statement – if (condition) statement else statement2 – return val;

74 Mutatók, dereferálás Ha T egy típus, T* a „T-re hivatkozó mutató” típus lesz, azaz egy T* típusú változó egy T típusú objektum címét tartalmazhatja. int* p12

75 Mutatók, dereferálás Változó deklarációja: int i; – A változó bizonyos (4 bájt) memóriát foglal le. Változó, mely pointer: int *pi = &i; – Az i által lefoglalt memória helye az adott változó címe. – Címének visszaadása: &i – i változó által lefoglalt memória mérete: sizeof(i)

76 Mutatók, dereferálás Példa: int *pi = 12; char c = 'a'; char *p = &c; // p a c címét tárolja

77 Mutatók, dereferálás Deklarálása: int* pa, pb; Mi a típusa a változóknak? typeid(pa).name(); // Pi vagy int* typeid(pb).name(); // i vagy int typeid(&pb).name(); // Pi vagy int* – typeid a typeinfo headerben Nem mindegy, hogy hova kerül a * !

78 Mutatók, dereferálás Jobb, ha így: int *pa, *pb; Lint: – Használjuk a *-t a változónál, ne a típusnál. Így automatikusan elkerüljük az ismertetett hibát.

79 Mutatók, dereferálás Értékadás: int *p; p = 47; Mihez rendeltünk értéket? – Megváltoztattuk a címét! – Nem mindig fordul! – g++ -Wall main.cpp -fpermissive Nagy így már fordul fpermissive kapcsoló: hibákat error szintről warningra nyom le.

80 Mutatók, dereferálás A mutatókon elvégezhető művelet a „dereferencia”, azaz a mutató által mutatott objektumra való hivatkozás. indirekciónak is hívják; jele: *

81 Mutatók, dereferálás Dereferálás int i = 10; int *pi = &i; *pi = 12; std::cout << i << std::endl; *mutató: a hivatkozott értékhez hozzáférés, lekérdezés, beállítás

82 Mutatók, dereferálás #include int main() { char c = 'a'; char *p = &c; std::cout << p << std::endl; // a }

83 Konstansokról Néha szeretném, ha egy memóriaterület ne változzon meg. const kulcsszó const int ci = 12; Azaz ci értékét nem tudom megváltoztatni a későbbiekben. 83

84 Konstansokról A const a típusrendszer része, const int külön típus! Constot beviszem a típusrendszerbe: – egy int *ip nem mutathat rá. Megkövetelem : const int *cip legyen, ekkor cip = &ci; De: cip konstans referencia, ezért *cip = 13 nem lehet! ++cip működik, ++*cip nem!

85 Konstansokról Más nyelvekben: – Java : final – C# : const/readonly – Ada : constant 85

86 Konstansokról Mi lehet konstans? Változó, pointer, paraméter, függvény, osztály?

87 Konstansok const int i = 12; Deklarálunk egy int változót (i néven). Konstans! Tehát értékét nem tudjuk megváltoztatni! Értékadás a deklarációkor kötelező, mert i értéke a const miatt nem változtatható! 87

88 Konstansok int main() { const int i; return 0; } Kimenet: const01.cpp: 3: error: uninitialized const ’i’ 88

89 Konstansok int main() { const int i = 12; ++i; return 0; } Kimenet: const01.cpp: 4: error: increment of read-only variable ’i’ 89

90 Konstansok Csináljunk pointert! Ráállítom a pointert a változóra! (nem const-ra) A konstans nem változhat! És a mutatott érték? 90

91 Konstansok Olyan pointer, melynek nem változhat! – Cím nem változik – És a mutatott érték? const int *cip = &ci; – Konstans int-re mutató pointer – Nem kötelező inicializálni. Egyszerű pointer! int *const icp = &i; – intre mutató konstans pointer – Érték változhat, cím nem! – Itt is hiba, ha nem inicializáljuk a konstanst.

92 Konstansok int main() { int i = 12; int *const ip = &i; return 0; } Kimenet: pipa 92

93 Konstansok #include int main() { int i = 12; int *const ip = &i; std::cout << i << ” ” << ip << std::endl; return 0; } Kimenet: pipa 12 0xf2342da324 93

94 Konstansok #include int main() { int i = 12; int *const ip = &i; std::cout << ++i << ” ” << *ip << std::endl; return 0; } Kimenet: pipa (figyeljünk a kiértékelés sorrendjére!!!) 94

95 Konstansok #include int main() { int i = 12; int *const ip = &i; i = 11; std::cout << i << ” ” << *ip << std::endl; return 0; } Kimenet: pipa

96 Konstansok #include int main() { int i = 12; int *const ip = &i; std::cout << ++i << ” ” << ++(*ip); return 0; } Kimenet: pipa Rontsuk el! ;] (Kiértékelési sorrend!!! Jobbról kezd!!!) 96

97 Konstansok #include int main() { int i = 12; int *const ip = &i; std::cout << ++i << ” ” << ++ip; return 0; } Kimenet: const05.cpp: 7: error: increment of read-only variable ’ip’ 97

98 Konstansok Ok, de én egy olyan pointert akarok, amit tudok változtatni, de az értéket, amire mutat, azt nem! 98

99 Konstansok (nézzük csak másképp!) #include int main() { int i = 12; const int *ip = &i; std::cout << ++i << ” ” << ++(*ip); return 0; } Kimenet: const05.cpp: 7: error: increment of read-only variable ’* ip’ 99

100 Konstansok (nézzük csak másképp!) #include int main() { int i = 12; const int *ip = &i; std::cout << ++i << ” ” << ++ip; return 0; } Kimenet: 13 0x12df321c5 100

101 Konstansok (nézzük csak másképp!) #include int main() { const int i = 12; int *ip = &i; std::cout << i << ” ” << ++*ip; return 0; } Kimenet: const08.cpp:6: error: invalid conversion from ’const int*’ to ’int*’ 101

102 Konstansok Ajánlott odafigyelni a sorrendre: – const int* i – int* const i 102

103 Konstansok Egy olyan pointer kell, amit nem változtathatok és az általa mutatott értéket sem! 103

104 Konstansokról const int *const cicp = &ci; – Mutathat konstansra, de mindig ugyanoda kell, hogy mutasson. 104

105 Konstansok Javítsuk ki, hogy az inkrementációs operátorra panaszkodjon! 105

106 Konstansok #include int main() { const int i = 12; const int* const ip = &i; std::cout << i << ” ” << ++*ip; return 0; } Kimenet: const08.cpp:7: error: increment of read-only location `*(const int*)ip` 106

107 Konstansok #include int main() { const int i = 12; int* const ip = &i; std::cout << i << ” ” << ++*ip; return 0; } Kimenet: const08.cpp:6: error: invalid conversion from ’const int*’ to ’int*’ 107

108 Konstansok Tehát egy olyan pointerünk van a const int változó mellett, mely egy const intre mutat, és ezzel együtt nem lehet megváltoztatni az értékét. const int *const ip = &i; int const *const ip = &i; A fenti kettő megegyezik! – De utóbbit kerüljük! Kevésbé érthető, kevésbé használt! 108

109 Konstansokról class Date {... } const Date mybirthday =...; mybirthday =... mybirthday.f(); 109

110 Konstansokról Azok a függvények, melyek nem változtatják meg a függvény belsejét, deklarálhatom konstans tag-függvénynek. 110

111 Konstansokról class Date { … // ha ez const lenne, // akkor hibát dobna a fordító! void set_day(int x) { day = x; } int get_day() const { return day; } … } 111

112 Függvények bevezetése Tartalom: –Függvénydeklaráció és –definíció –Paraméterátadás –Visszatérési érték

113 Függvények Függvénydefiníció: –A program kisebb egységekre bontása. –Minden függvényt valahol meg kell határoznunk. –Függvénydefiníció olyan deklaráció, ahol megadjuk a függvény törzsét. –Felépítése: type name ( parameter1, parameter2,...) { statements }

114 Függvények Más nyelvekben: – C/C++ alapú nyelvekben szintén void és társai – Adában function és procedure keyword

115 Függvények Definíció: – A teljes specifikáció! type name ( parameter1 [paramname], parameter2,...) Szignatúra: – Visszatérési érték típusát nem tartalmazza – Paraméterneveket szintén nem name ( parameter1, parameter2,...)

116 Függvények Függvények deklarációja: – Forward declaration – Megadom a függvény használatának módját – Ezt hívjuk még function prototype-nak is

117 Függvények Példa: void swap(int*, int*); // deklaráció, function proto. //... void swap(int *p, int *q) // definíció { int t = *p; *p = *q; *q = t; }

118 Függvények Paraméterátadás –Amikor egy függvény meghívódik, a fordítóprogram a formális paraméterek számára tárterületet foglal le, az egyes formális paraméterek pedig a megfelelő valódi (aktuális) paraméter-értékkel töltődnek fel. –A paraméterátadás szerepe azonos a kezdeti értékátadáséval –A fordítóprogram ellenőrzi, hogy az aktuális paraméterek típusa megegyezik-e a formális paraméterek típusával, és végrehajt minden szabványos és felhasználói típuskonverziót

119 Függvények Paraméterátadás – Érték szerinti – Cím szerinti – Referencia szerinti – Eredmény szerinti

120 Függvények Paraméterátadás: érték szerint int sum(int a, int b) { return a + b; } int main() { std::cout << sum(12, 34) << std::endl; }

121 Függvények Paraméterátadás: cím szerint (pass by address, pass by pointer) int f(int *a) { // a mutatott érték módosítása std::cout << ++*a; return *a; } int main() { int i = 10; int *ip = &i; // megkapja i címét! std::cout << f(ip) << ”|” << *ip << std::endl; } Kimenet: 11 11|10

122 Függvények Mi történik itt? – A pointerek (címek) mindig érték szerint adódnak át!

123 Függvények Referencia szerinti paraméterátadás void f(int &a) { a += 1; } int main() { int i = 1; f(i); std::cout << i << std::endl; // 2 }

124 Függvények Referencia szerinti paraméterátadás void f(int &a) { a += 1; } int main() { int i = 1; f(10); std::cout << i << std::endl; } type ‘int&’ from an rvalue of type ‘int’

125 Függvények rvalue : (később) int a = 42; int b = 43; // a, b l-value: a = b; // ok b = a; // ok a = a * b; // ok // a * b rvalue: int c = a * b; // ok, rvalue jobb oldalon a * b = 42; // error, rvalue bal oldalon

126 Függvények Paraméterátadás: Érték és referencia szerint void f(int val, int& ref) { val++; ref++; } void main() { int i = 1; int j = 1; f(i,j); // i == 1, j == 2 }

127 Függvények Eredmény szerinti – pass-by-result vs. pass-by-value-return – Az átadott paraméter (pointer) lemásolódik. – Maga az érték nem kerül másolásra Ada

128 Függvények Egyéb: – pass-by-name – pass-by-value-returned – pass-by-lazy-evaluation (lusta kiértékelés)

129 Függvények Más nyelvekben: – Ada: paraméter átadásától függő, in, out, in out – Java: minden érték szerint

130 Függvények Visszatérési érték szerint megkülönböztetünk: – Eljárásokat (void) – Függvényeket (minden más)

131 Függvények return : – visszatérés void esetén: – return ; vezérlés megszakítása – return 10; hiba! void nem int!

132 Függvények Függvények esetén: – Return utasítás nem kötelező – Ez veszélyes! int f() { std::cout << ”Hello”; }

133 Függvények int f() {} int main() { int i = f(); std::cout << i; // kimenet: 1 }

134 Függvények int f() { return; } int main() { int i = f(); std::cout << i; } error: return-statement with no value,...

135 Függvények Visszatérési érték –A main() kivételével minden nem void metódusnak kell visszatérési értékkel rendelkeznie. –lokális változóra hivatkozó mutatót soha nem szabad visszaadni

136 Függvények i nt f1() { } // hiba: nincs visszatérési érték, ettől még lehet jó void f2() { } // rendben int f3() { return 1; } // rendben void f4() { return 1; } // hiba: visszatérési érték void függvényben int f5() { return; } // hiba: visszatérési érték hiányzik void f6 () { return; } // rendben

137 Függvények Nézzük a rázós eseteket. Kezdjük kicsivel.

138 Függvények int f() { return ’c’; } int main() { std::cout << f() << std::endl; // 99 return 0; }

139 Függvények int f() { int i = a + b; } int main() { std::cout << f(10, 12); // 22 return 0; }

140 Függvények int f() { int i = a + b; int k; } int main() { std::cout << f(10, 12); // 22 return 0; }

141 Függvények int f() { int i = a + b; int k; ; } int main() { std::cout << f(10, 12); // 22 return 0; }

142 Függvények int f() { int i = a + b; int k; ; i = b + 100; } int main() { std::cout << f(10, 12); // 112 return 0; }

143 Függvények int f() { int i = a + b; int k; ; i = b + 100; i = a + 1; } int main() { std::cout << f(10, 12); // 11 return 0; }

144 Függvények int f() { int i = a + b; int k; ; i = b + 100; i = a + 1; std::cout << ”hello”; } int main() { std::cout << f(10, 12); // return 0; }

145 Függvények int f() { int i = a + b; int k; ; i = b + 100; i = a + 1; std::cout << ”hello”; k = 19 + a; } int main() { std::cout << f(10, 12); // 29 return 0; }

146 Függvények bevezetése Túlterhelés: –Később!

147 Konstansok és függvények Függvények visszatérési értéke gubancos lehet! Baj van, ha valami gubanc futás időben derül ki! Javítsuk úgy a kódot, hogy fordítási időben kiszűrjük a bajos részeket! 147

148 Konstansok (függvény visszatérési értéke) #include char* f() { return ”szoveg”; } int main() { f()[0] = ’b’; } Segmentation fault 148

149 Konstansok (függvény visszatérési értéke) #include const char* f() { return ”szoveg”; } int main() { f()[0] = ’b’; } Kimenet: fconst01.cpp:10: error: assignment of read-only location ’* f()’ 149

150 Konstansok (függvény visszatérési értéke) #include int* f() { int i = 12; const int* ip = &i; return ip; } Kimenet: fconst01.cpp:7: error: invalid conversion from ’const int*’ to ’int*’ 150

151 Konstansok (paraméterátadás) Érték, referencia, pointer szerint! void f( int i ) { i = 10; } void f( int& i ) { i = 10; } void f( int* i ) { *i = 10; } 151

152 Konstansok Kicsit előre ugrunk! User-defined type void f( myType &my ); Ekkor: – Valamilyen belső műveletet szeretnénk elvégeztetni rajta! – Optimalizálás: csak a címét másoljuk, ne az egész objektumot! Gyorsabb, nő a hatékonyság! De mi van akkor, ha valaki módosítja a saját tudta nélkül? Arra gondol, hogy úgy sem módosul a metódus belsejében! Gubancos! void f( const myType &my ); 152

153 Konstansok Haladjunk az osztályok mentén még mindig! Osztály specifikációja: class Clazz { void f(); int i; } 153

154 Konstansok Ennek az implementációja: void Clazz::f() { ++i; } Mi történik, ha a specifikációban megtiltom, hogy az adott metódus implementációja módosítsa az osztály adott mezőjét? Nézzünk egy példát! 154

155 Konstansok class Clazz { void f() const; int i; } Kimenet: increment of data-member ’Clazz::i’ in read-only structure 155

156 Konstansok És akkor nézzünk valami nagyon advanced-et! Interjún megkérdezhetik! Mit csinál az alábbi metódus! Mondj el mindent, amit tudsz róla! const int* const Method3( const int* const& ) const; 156

157 Kódelemzés Feladat: Írj olyan programot, mely kiszámolja egy Fahrenheit értékhez tartozó Celsius értéket! -100-tól indulunk, +300-ig megyünk, és 10 a lépésnagyság!

158 Kódelemzés fahr2cels v1 (C): #include // a program fahrenheit és ahhoz megfelelő celsius értékeket ír ki int main() { int fahr; for (fahr = -100 ; fahr <= 300; fahr += 10) { printf("fahr = %d\t cels =%d\n", fahr, 5/9 * (fahr - 32)); } return 0; } Kimenet: F = 0 C = 0 F = 40 C = 0...

159 Kódelemzés Mi történik itt? Statikus típusrendszerű nyelvek esetén a fordítóprogramnak már fordítási időben kell tudnia, hogy milyen típusokkal dolgozik, e szerint foglal majd memóriát, vizsgálja a műveleteket! int / int => int Fordító nem foglalkozik azzal, hogy értékvesztéssel jár a művelet, fordítási időben nem tudja, hogy milyen érték kerül a változóba

160 Kódelemzés fahr2cels v2 (C): #include // a program fahrenheit és ahhoz megfelelő celsius értékeket ír ki int main() { int fahr; for (fahr = -100; fahr <= 300; fahr += 10) { printf("fahr = %d\t cels =%d\n", fahr, 5./9 * (fahr - 32)); } return 0; } Kimenet: fahr2cels2.c: In function ‘main’: fahr2cels2.c:13: warning: format ‘%d’ expects type ‘int’, but argument 4 has type ‘double’

161 Kódelemzés A kód ugyan lefordul, de a warning mindig rossz ómen! float / int => float

162 Kódelemzés fahr2cels v3 (C): #include // a program fahrenheit és ahhoz megfelelő celsius értékeket ír ki int main() { int fahr; for (fahr = -100; fahr <= 300; fahr += 10) { printf("fahr = %d\t cels =%f\n", fahr, 5./9 * (fahr - 32)); } return 0; } Kimenet: F = 0 C = F = 40 C =

163 Kódelemzés fahr2cels v4 (C): #include #define LOWER -100 #define UPPER 300 #define STEP 10 // a program fahrenheit és ahhoz megfelelő celsius értékeket ír ki int main() { int fahr; for (fahr = LOWER; fahr <= UPPER; fahr += STEP) { printf("fahr = %d\t cels =%f\n", fahr, 5./9 * (fahr - 32)); } return 0; } Kimenet: F = 0 C = F = 40 C =

164 Kódelemzés Ha már megoldottuk C-ben, láttuk a hátrányait, akkor nézzük meg ugyanezt a feladatot C++-ben!

165 Kódelemzés fahr2cels v5 (C++): #include using namespace std; int main() { for ( int fahr = 0; fahr <= 200; fahr+=40) { cout << "F = " << fahr << '\t' << "C = " << 5./9*(fahr-32) << endl; } return 0; // Opcionális! }

166 Kódelemzés Egyszerűen típushelyesen tudom kiíratni, és fordítási időben kapok jelzés, ahelyett, hogy futásidőben szállna el, vagy kapnék rossz eredményt!

167 Kódelemzés fahr2cels v6 (C++): #include using namespace std; int main() { const int lower = 0; const int upper = 200; const int step = 40; for ( int fahr = lower; fahr <= upper; fahr+=step ) { cout << "F = " << fahr << '\t' << "C = " << 5./9*(fahr-32) << endl; } return 0; }

168 Kódelemzés Mi az a const és miért kell? Növeltük a maintence-t! Kiemeltük a constans értékeket! const : nem állhat az értékadás bal oldalán!

169 Kódelemzés fahr2cels v7 (C++): #include using namespace std; inline double fahr2cels( double f ) { return 5./9 * ( f-32 ); } int main() { const int lower = 0; const int upper = 200; const int step = 40; for ( int fahr = lower; fahr <= upper; fahr+=step ) { cout << "F = " << fahr << '\t' << "C = " << fahr2cels(fahr) << endl; } return 0; }

170 Kódelemzés inline: az egyik legjobb hatékonyságnövelő eszköz. Abban az esetben, amikor egyszerű fgv-törzsről van szó, behelyettesíti az adott kódot a meghívó helyére! Egy esetben nem lehet ezt megcsinálni, amikor virtuális fgv-eket használok! Ugyanis futásidőben dől el, hogy a dinamikus kötések melyikével, melyik implementációval futtassa a fgv-t! Ezek kiértékelése a fordító számára sokkal lassabb! (De ezekről később)

171 Kódelemzés Feladat: Írjuk meg a jó öreg cat parancsot! Amit begépelünk, azt adja vissza a következő sorban, ha entert vagy Ctrl+D-t ütöttünk!

172 Kódelemzés cat (C): #include int main() { int ch; while ( (ch = getchar()) != EOF) { putchar(ch); } return 0; } Kimenet: asdf asd fasd fas

173 Kódelemzés cat (C++): #include int main() { char ch; std::cin >> ch; // egy előolvasás! while ( std::cin.good() ) { std::cout << ch; // ha nem volt hiba, akkor mehetünk tovább! ch << std::cin; } return 0; }

174 Kódelemzés cat (C++): #include using namespace std; int main() { char ch; // fontos, defaultból tetsz. karakter while ( cin >> ch ) { cout << ch; } return 0; } Kimenet: asdf asd fasd fas

175 Kódelemzés #include int main() { char ch; std::cin >> noskipws; std::cin >> ch; // egy előolvasás! while ( std::cin.good() ) { // ha nem volt hiba, akkor mehetünk tovább! std::cout << ch; std::cin >> ch; } return 0; }

176 Kódelemzés cat (C++): #include using namespace std; int main() { char ch; // fontos, defaultból tetsz. Karakter // cin >> átugorja a whitespace-eket!!! while ( cin.get(ch)) { cout.put(ch); } return 0; } Kimenet: asdf asd fasd fas


Letölteni ppt "Programozási Nyelvek (C++) Gyakorlat Gyak 02. Török Márk D-2.620 1."

Hasonló előadás


Google Hirdetések