450 likes | 581 Views
Programozási Nyelvek (C++) Gyakorlat Gyak 03. Török Márk tmark @ caesar.elte.hu 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.
E N D
Programozási Nyelvek (C++) GyakorlatGyak 03. Török Márk tmark@caesar.elte.hu 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.
Konstansokról • Nézzünk egy példát: • strlen implementálása: intstrlen( char* s ) { char *p = s; while ( *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. }
Konstansokról • Mi van akkor, ha: intstrlen( char* s ) { char *p = s; while( *p = '0' ) // hiba lehetőség! { ++p; } return p - s; }
Konstansokról • Javítsuk: intstrlen( constchar* s ) { constchar *p = s; // csak együtt lehetnek! while ( *p = '0' ) // így már szemantikai hiba! { ++p; } return p - s; }
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: • 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<iostream> int main() { charch; std::cin >> std::ios_base::noskipws; while( std::cin >> ch) { std::cout << ch; } return0; }
Kódelemzés • Megoldás:#include<iostream>usingnamespacestd;int main() {charch;while (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<iostream> int main() { charch; 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; } } return0; }
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<iostream> int main() { charch; std::cin >> std::ios_base::noskipws; while( std::cin >> ch ) { std::count << 'a' <= ch && ch <= 'z' ? ch - 'a' + 'A' : ch; } return0; }
Kódelemzés • Mi történt? • A kiértékelés miatt precedenciaproblémák vannak!
Kódelemzés #include<iostream> int main() { charch; std::cin >> std::ios_base::noskipws; while( std::cin >> ch ) { std::count << ('a' <= ch && ch <= 'z' ? ch - 'a' + 'A' : ch); } return0; }
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 opchar=> int
Kódelemzés • Promotionrules: • short, char => int • float => double • double => long double • Odafeléjólmentek a dolgok, maguktólmentek a konverziók! • Visszafelémárnem!
Kódelemzés • Megoldások: • char(i), ha i : integer, akkor i-t char-ra konvertáljuk. • static_cast<char>(i)(Később) • char ch = i;
Kódelemzés #include<iostream> int main() { charch; std::cin >> std::ios_base::noskipws; while( std::cin >> ch ) { std::count << char('a' <= ch && ch <= 'z' ? ch - 'a' + 'A' : ch); } return0; }
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<iostream> intmain(intargc; char *argv[]) { ... }
Kódelemzés #include<iostream> voidtoupper(std::istream&, std::ostream&); int main( intargc; 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 copyconstruktoraprivate, hogy ne lehessen másolni, így mindig referencia szerint adom át öket paraméternek.
Kódelemzés #include<fstream> #include<iostream> voidtoupper(std::istream&, std::ostream&); int main( intargc; char *argv[]) { if( argc < 2 ) { toupper(std::cin, std::cout); } else { // folyt. } return0; }
Kódelemzés for( int i=1; i < argc; ++i ) { // Meg kell nyitni a fájlt! ifstreaminp(argv[i]); if ( !inp ) { std::cerr << "Can't open" << argv[i] << std::endl; } else { toupper(inp, std::cout); } }
Kódelemzés • Kérdés: Kell-e close-tmondanom? • Amikor a zárójelet becsukom, akkor az ifstreamdestruktora 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<fstream> #include<iostream> voidlines(std::istream&, std::ostream&); intmain( intargc; char *argv[]) { if( argc < 2 ) { lines(std::cin, std::cout); } else { // folyt. } return0; }
Kódelemzés for( int i=1; i < argc; ++i ) { ifstreaminp(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 voidlines( std::istream&inp, std::ostream&outp ) { intcnt = 0; charprev = '\n'; charcurr; while ( std::cin.get(curr) ) { cnt = f(cnt, prev, curr); prev = curr; } }
Kódelemzés int f( intcnt, charprev, charcurr ) // warning! { if( '\n' == prev ) { ++cnt; } returncnt; }
Kódelemzés int f( intcnt, charprev, char) // így már nem! { if( '\n' == prev ) { ++cnt; } returncnt; }
Kódelemzés • Javítás: voidlines( std::istream&inp, std::ostream&outp ) { intcnt = 0; charprev = '\n'; charcurr; while ( std::cin.get(curr) ) { cnt += '\n' == prev; prev = curr; } }
Kódelemzés • Megoldás:#include<iostream>int main() {intls = 0;char c;while ( std::cin >> std::noskipws>> c) {if (c == ‘\n’) { ls += 1; } }std::cout<< ls << std::endl;return0;}
Kódelemzés • Megoldás: más út#include<iostream>int main() {intls = 0;char c;while(std::cin >> std::noskipws>> c) {ls = (c == ‘\n’ ? ls + 1 : ls); }std::cout<< ls << std::endl;return0;}
Kódelemzés • Kimenet:almaszilvactrl-Deredmény: 2almaszilva ctrl-Deredmé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 ( charprev, intls) {returnprev == ‘\n’ ? ls + 1 : ls;}char c, prev;while ( 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 (charprev, char c, intls) {return ( prev == ‘\n’ || prev == ‘\t’ || prev == ‘ ‘) && c != ‘\n’ && c != ‘\t’ && c != ‘ ’ ? ls + 1 : ls;}
Kódelemzés • Megoldás: Más útboolisWS(char c) { …}