Programozási Nyelvek (C++) Gyakorlat Gyak 03.

Download Report

Transcript Programozási Nyelvek (C++) Gyakorlat Gyak 03.

Programozási Nyelvek (C++) Gyakorlat

Gyak 03.

Török Márk [email protected]

D-2.620

1

Kódelemzés

• Feladat: Olvassunk be betüket a sabványos bemenetről (a – z), és írjuk ki a nagybetűs párjukat (A – Z).

Különleges karakterek, nagybetűk helyben maradnak, angol abc-vel dolgozunk.

Tömbök

Konstansokról

• Nézzünk egy példát: – strlen implementálása: int { strlen( char * s ) char while *p = s; ( *p != '0' { ) ++p; } // hello world0, előre zavarom a p-t.

return p - s; // két pointer különbsége az adott szó hossza.

} 4

Konstansokról

• Mi van akkor, ha: int { strlen( char * s ) char while *p = s; ( *p = '0' { ++p; } return p - s; } ) // hiba lehetőség!

5

Konstansokról

} • Javítsuk: int { strlen( const char * s ) const char while *p = s; ( *p = '0' // csak együtt lehetnek!

) // így már szemantikai hiba!

{ ++p; } return p - s; 6

Kódelemzés

• Áttekintés: – Kezdjünk egyből C++-vel!

– Ha egy C++ programot írunk, érdemes a biztonságra törekedni.

• Azaz, kerüljük, hogy egyszerre megírjuk az egészet, és csak utána fordítunk!

• Részenként kell csinálni! (és úgy fordítani!) – Ezek a lépések: 1.

2.

3.

Elso lépésként megnézzük, hogy a stdinputot másolja át a stdoutputra!

Második lépésként nézzük meg, hogy felismerie a kisbetűt.

Majd harmadik lépésként alakítsuk a felismert kisbetűket nagybetűssé!

Kódelemzés

#include int { main() char ch; std::cin >> std::ios_base::noskipws; while { ( std::cin >> ch ) std::cout << ch; } return 0 ; }

Kódelemzés

•Megoldás: #include using namespace std; int { main() char while ch; (cin >> noskipws >> ch) { cout << …(???) } } – noskipws: io-manipulátor, nem ugorja át a whitespaceket (space, tab ,…), ennek testvére a skipws, mely átugorja azokat.

Kódelemzés

• Fordul! Yeehaaa!

• Kisbetűk felismerése a feladat!

Kódelemzés

#include int { main() char ch; std::cin >> std::ios_base::noskipws; while { ( std::cin >> ch ) if { ( 'a' <= ch && ch <= 'z' ) // #1 std::cout << ch + 'A' 'a' ; // #2 } else { std::cout << ch; } } return 0 ; }

Kódelemzés

• #1 Kérdés: Működik-e char-ok között a <= operator? Mivel mindegyik int-re konvertálódik, így az ascii kódok között történik meg a <= vizsgálat!

• #2 Kérdés: Hogyan konvertáljuk a karaktereket nagybetűvé?

Mivel ascii-val dolgozunk, ezért ch + 'A' - 'a'

Kódelemzés

• int-ek kerülnek kiírásra, mivel a + és - szintén nincs értelmezve a char-ok között!

• ascii kód íródik ki, ahelyett, hogy char érték íródott volna ki!

Kódelemzés

#include int { main() char ch; std::cin >> std::ios_base::noskipws; while { ( std::cin >> ch ) std::count << 'a' <= ch && ch <= 'z' } return 0 ; } ? ch 'a' + 'A' : ch;

Kódelemzés

• Mi történt?

– A kiértékelés miatt precedenciaproblémák vannak!

Kódelemzés

#include int { main() char ch; std::cin >> std::ios_base::noskipws; while { ( std::cin >> ch ) std::count << ( 'a' <= ch && ch <= 'z' } return 0 ; ? ch 'a' + 'A' : ch); }

Kódelemzés

• Továbbra is számok íródnak ki! Meglepő módon most már a betűk helyett is számok íródnak ki!

• T1 T2 ==> T • Fordítási időben meg kell mondania, hogy melyik kiíró operátort válassza meg! A fordítónak fordítás alatt tudnia kell, hogy milyen a kifejezés típusa!

• Itt: int op char => int

Kódelemzés

• Promotion rules: – short, char => int – float => double – double => long double • Odafelé jól mentek a dolgok, maguktól mentek a konverziók!

• Visszafelé már nem!

Kódelemzés

• Megoldások: – char(i), ha i : integer, akkor i-t char-ra konvertáljuk.

– static_cast(i) (Később) – char ch = i;

Kódelemzés

#include int { main() char ch; std::cin >> std::ios_base::noskipws; while { ( std::cin >> ch ) std::count << char ( 'a' } return 0 ; <= ch && ch <= 'z' ? ch } 'a' + 'A' : ch);

Kódelemzés

• Más lehetőség: – Saját toupper metódus írása!

• Amit egyszer már megírtak, azt ne írjuk meg mégegyszer!

– Beépített toupper metódus használata

Kódelemzés

• Írjunk olyan utility-t, ami úgy működik, mint egy unixparancs.

• Ha nem adunk paramétert, akkor stdinput /outputot használja, ha adunk paramétert, akkor azt, mint fájlt akarja használni!

Kódelemzés

#include int { main( int argc; char *argv[]) ...

}

Kódelemzés

#include void toupper(std::istream&, std::ostream&); int { main( int argc; char *argv[] ) if { ( argc < 2 ) toupper(std::cin, std::cout); } }

Kódelemzés

• Akár van fájl, akár nincs, ugyanazt csinálom, ezzel megóvom magamat a dupla munkától!

• az istream, ostream osztályoknak a copyconstruktora private, hogy ne lehessen másolni, így mindig referencia szerint adom át öket paraméternek.

Kódelemzés

#include #include void toupper(std::istream&, std::ostream&); int { main( int if { argc; char ( argc < 2 ) *argv[]) toupper(std::cin, std::cout); } else { // folyt.

} return 0 ; }

Kódelemzés

for { ( int i= 1 ; i < argc; ++i ) // Meg kell nyitni a fájlt! ifstream inp(argv[i]); if { ( !inp ) std::cerr << "Can't open" } else { toupper(inp, std::cout); } << argv[i] << std::endl; }

Kódelemzés

• Kérdés: Kell-e close-t mondanom?

– Amikor a zárójelet becsukom, akkor az ifstream destruktora meghívódik!

Kódelemzés

• Feladat: Számoljuk meg, hogy a bemeneten hány sor volt. (Sorvége-jel: ‘\n’)

Kódelemzés

#include #include void lines(std::istream&, std::ostream&); int { main( int if { argc; char ( argc < 2 ) *argv[]) lines(std::cin, std::cout); } else { // folyt.

} return 0 ; }

Kódelemzés

for { ( int i= 1 ; i < argc; ++i ) ifstream inp(argv[i]); if ( !inp ) { std::cerr << "Can't open" << argv[i] << std::endl; } else { lines(inp, std::cout); } }

Kódelemzés

• Egy adott karakter előfordulása egy egyszerű számlálás!

Kódelemzés

void { lines( std::istream& inp, std::ostream& outp ) int char cnt = 0 ; prev = '\n' ; char while curr; ( std::cin.get(curr) ) { cnt = f(cnt, prev, curr); prev = curr; } }

Kódelemzés

int { f( int cnt, char prev, char if { ( '\n' == prev ) ++cnt; } return cnt; } curr ) // warning!

Kódelemzés

int { f( int cnt, char prev, char if { ( '\n' == prev ) ++cnt; } return cnt; } ) // így már nem!

Kódelemzés

} • Javítás: void { lines( std::istream& inp, std::ostream& outp ) int char cnt = 0 ; prev = '\n' ; char while curr; ( std::cin.get(curr) ) { cnt += '\n' == prev; prev = curr; }

Kódelemzés

•Megoldás: #include int { main() int ls = 0 ; char while c; ( std::cin >> std::noskipws >> c) { if { (c == ‘\n’ ) ls += 1; } } std::cout << ls << std::endl; return 0 ; }

Kódelemzés

•Megoldás: más út #include int { main() int char ls = 0 ; c; while (std::cin >> std::noskipws >> c) { return ls = (c == ‘\n’ 0 ; ? ls + 1 } std::cout << ls << std::endl; : ls); }

Kódelemzés

• Kimenet: alma szilva ctrl-D eredmény: 2 alma szilva ctrl-D eredmény: 1

Kódelemzés

• Feladat: Írjuk át úgy a programot, hogy ne az ‘\n’ karaktereket keressük, mert az utóbbi esetben hibás a végrehajtás.

Kódelemzés

•Megoldás: int f ( char { return } prev, int prev == ls) ‘\n’ ? ls + 1 : ls; char while c, prev; ( std::cin >> std::noskipws >> c) { ls = f(prev, ls); prev = c; }

Kódelemzés

• Feladat: Szavak számának a számolása.

alma (1) „ „ szilva (2) …

Kódelemzés

•Megoldás: int { f ( char prev, char c, int ls) return ( prev == ‘\n’ && c != ‘\n’ || prev == && c != ‘\t’ ‘\t’ || prev == && c != ‘ ’ ‘ ‘ ? ls + ) 1 : ls; }

Kódelemzés

•Megoldás: Más út bool { isWS( char c) … }