Upload
lew
View
49
Download
3
Embed Size (px)
DESCRIPTION
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. - PowerPoint PPT Presentation
Citation preview
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 *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.
}
4
Konstansokról
• Mi van akkor, ha:
int strlen( char* s ){
char *p = s;while ( *p = '0' ) // hiba lehetőség!{
++p;}return p - s;
}
5
Konstansokról
• Javítsuk:int strlen( const char* s ){
const char *p = s; // csak együtt lehetnek!while ( *p = '0' ) // í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. Elso lépésként megnézzük, hogy a stdinputot másolja át a stdoutputra!
2. Második lépésként nézzük meg, hogy felismerie a kisbetűt.
3. Majd harmadik lépésként alakítsuk a felismert kisbetűket nagybetűssé!
Kódelemzés
#include <iostream>
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 <iostream>using namespace std;
int main() {
char ch;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() {
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 <iostream>
int main() {
char ch;std::cin >> std::ios_base::noskipws;while ( std::cin >> ch ) {
std::count << 'a' <= ch && ch <= 'z' ? ch - 'a' + 'A' : ch;
}return 0;
}
Kódelemzés
• Mi történt?– A kiértékelés miatt precedenciaproblémák
vannak!
Kódelemzés#include <iostream>
int main() {
char ch;std::cin >> std::ios_base::noskipws;while ( std::cin >> ch ) {
std::count << ('a' <= ch && ch <= 'z' ? ch - 'a' + 'A' : ch);
}return 0;
}
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<char>(i) (Később)– char ch = i;
Kódelemzés#include <iostream>
int main() { char ch; std::cin >> std::ios_base::noskipws; while ( std::cin >> ch ) { std::count << char('a' <= ch && ch <= 'z' ? ch - 'a' + 'A' : ch); } return 0;}
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>
int main(int argc; char *argv[]){ ...}
Kódelemzés
#include <iostream>
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 <fstream>#include <iostream>
void toupper(std::istream&, std::ostream&);
int main( int argc; char *argv[]){ if ( argc < 2 )
{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" << argv[i] << std::endl;
}else{
toupper(inp, std::cout);}
}
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 <fstream>#include <iostream>
void lines(std::istream&, std::ostream&);
int main( int argc; char *argv[]){ if ( argc < 2 )
{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 cnt = 0;char prev = '\n';char curr; while ( std::cin.get(curr) ){
cnt = f(cnt, prev, curr); prev = curr;
}}
Kódelemzés
int f( int cnt, char prev, char curr ) // warning!{
if ( '\n' == prev ){
++cnt;}return cnt;
}
Kódelemzés
int f( int cnt, char prev, char ) // így már nem!{
if ( '\n' == prev ){
++cnt;}return cnt;
}
Kódelemzés
• Javítás:void lines( std::istream& inp, std::ostream& outp ){
int cnt = 0;char prev = '\n';char curr; while ( std::cin.get(curr) ){
cnt += '\n' == prev;prev = curr;
}}
Kódelemzés
•Megoldás:#include <iostream>
int main() {
int ls = 0;char c;while ( 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 <iostream>
int main() {
int ls = 0;char c;while (std::cin >> std::noskipws >> c) {
ls = (c == ‘\n’ ? ls + 1 : ls);}std::cout << ls << std::endl;return 0;
}
Kódelemzés
• Kimenet:
almaszilvactrl-Deredmény: 2
almaszilva 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 ( char prev, int ls) {
return prev == ‘\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 (char prev, char c, int ls) {
return ( prev == ‘\n’ || prev == ‘\t’ || prev == ‘ ‘)&& c != ‘\n’ && c != ‘\t’ && c != ‘ ’ ? ls + 1 :
ls;}
Kódelemzés
•Megoldás: Más út
bool isWS(char c) {
…}