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

Report
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 *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' )
{
++p;
}
return p - s;
}
// hiba lehetőség!
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.
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 <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:
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 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)
{
…
}

similar documents