• Nem Talált Eredményt

Az alaptípusok áttekintése

int osszeg, szorzat(1);

int main() {

int a, b=2012, c(2004);

double d=12.23, e(b);

}

A fenti példában két változó (osszeg és a) esetén nem szerepel kezdőérték, ami általában programhibához vezet.

Ennek ellenére az osszeg változó 0 kiindulási értékkel rendelkezik, mivel a globális változókat mindig inicializálja (nullázza) a fordító. A lokális a esetén azonban más a helyzet, mivel értékét a változóhoz rendelt memória aktuális tartalma adja, ami pedig bármi lehet! Ilyen esetekben a felhasználás előtti értékadással állíthatjuk be a változó értékét. Értékadás során az egyenlőségjel bal oldalán álló változó felveszi a jobb oldalon szereplő kifejezés értékét:

a = 1004;

C++ nyelven a kezdőértéket tetszőleges fordítás, illetve futás közben meghatározható kifejezéssel is megadhatjuk:

#include <cmath>

#include <cstdlib>

using namespace std;

double pi = 4.0*atan(1.0); // π int veleten(rand() % 1000);

int main() {

double ahatar = sin(pi/2);

}

Felhívjuk a figyelmet arra, hogy a definíciós és az értékadó utasításokat egyaránt pontosvessző zárja.

2.3. Az alaptípusok áttekintése

Az alaptípusokra úgy tekinthetünk, mint az emberi írott művekben a számjegyekre és a betűkre. Segítségükkel egy matematikai értékezés és a Micimackó egyaránt előállítható. Az alábbi áttekintésben az egész jellegű típusokat kisebb csoportokra osztjuk.

2.3.1. Karakter típusok

A char típus kettős szereppel rendelkezik. Egyrészről lehetővé teszi az ASCII (American Standard Code for Information Interchange) kódtábla (1. szakasz - Az ASCII kódtábla függelék) karaktereinek tárolását, másrészről pedig egybájtos előjeles egészként is használható.

char abetu = 'A';

cout << abetu << endl;

char valasz;

cout << "Igen vagy Nem? ";

cin>>valasz;

// vagy

valasz = cin.get();

A char típus kettős voltát jól mutatják a konstans értékek (literálok) megadási lehetőségei. Egyetlen karaktert egyaránt megadhatunk egyszeres idézőjelek (aposztrófok) között, illetve az egész értékű kódjával. Egész értékek esetén a decimális forma mellet - nullával kezdve - az oktális, illetve - 0x előtaggal - a hexadecimális alak is használható. Példaként tekintsük a nagy C betű megadását!

’C’ 67 0103 0x43

Bizonyos szabványos vezérlő és speciális karakterek megadására az ún. escape szekvenciákat használjuk. Az escape szekvenciában a fordított osztásjel (backslash - \) karaktert speciális karakterek, illetve számok követik, mint ahogy az 3. szakasz - Escape karakterek függelék táblázatában látható: ‟\n‟, ‟\t‟, ‟\‟‟, ‟\”‟, ‟\\‟.

Amennyiben a 8-bites ANSI kódtábla karaktereivel, illetve bájtos egész értékekkel kívánunk dolgozni, az unsigned char típust ajánlott használni.

Az Unicode kódtábla karaktereinek feldolgozásához a kétbájtos wchar_t típussal hozunk létre változót, a konstans karakterértékek előtt pedig a nagy L betűt szerepeltetjük. (Ezek írására olvasására az std névtér wcout és wcin objektumok szolgálnak.)

wchar_t uch1 = L'\u221E';

wchar_t uch2 = L'K';

wcout<<uch1;

wcin>>uch1;

uch1 = wcin.get();

Felhívjuk a figyelmet arra, hogy nem szabad összekeverni az aposztrófot (‟) az idézőjellel ("). Kettős idézőjelek között szöveg konstansokat (sztring literálokat) adunk meg a programban.

"Ez egy ANSI sztring konstans!"

illetve

L"Ez egy Unicode sztring konstans!"

2.3.2. A logikai bool típus

A bool típusú változók két értéket vehetnek fel. A false (0) a logikai hamis, míg a true (1) a logikai igaz értéknek felel meg. Input/Output (I/O) műveletekben a logikai értékeket a 0 és az 1 egész számok reprezentálják.

bool start=true, vege(false);

cout << start;

cin >>vege;

Ezt az alapértelmezés szerinti működést felülbírálhatjuk a boolalpha és a noboolalpha I/O manipulátorok segítségével:

bool start=true, vege(false);

cout << boolalpha << start << noboolalpha; // true cout << start; // 1 cin >> boolalpha>> vege; // false cout << vege; // 0

2.3.3. Az egész típusok

Valószínűleg a C++ nyelv leggyakrabban használt alaptípusa az int a hozzá tartozó típusmódosítókkal. Amikor a programban megadunk egy egész értéket, akkor a fordító automatikusan az int típust próbálja hozzárendelni.

Amennyiben az érték kívül esik az int típus értékkészletén, akkor a fordító valamelyik nagyobb értékkészletű egész típust alkalmazza, illetve hibajelzést ad túl nagy konstans esetén.

A konstans egész értékek típusát U és L utótagokkal mi is meghatározhatjuk. Az U betű az unsigned, míg az L a long típusmódosítók kezdőbetűje:

2012 int

2012U unsigned int

2012L long int

2012UL unsigned long int

2012LL long long int

2012ULL unsigned long long int

Természetesen az egész értékeket a decimális (2012) forma mellett oktális (03724) és hexadecimális (0x7DC) számrendszerben egyaránt megadhatjuk. Ezeket a számrendszereket az I/O műveletekben is előírhatjuk a

„kapcsoló” manipulátorok (dec, oct, hex) felhasználásával, melyek hatása a következő manipulátorig tart:

#include <iostream>

using namespace std;

int main() {

int x=20121004;

cout << hex << x << endl;

cout << oct << x << endl;

cout << dec << x << endl;

cin>> hex >> x;

}

Adatbevitel esetén a számrendszert jelző előtagok használata nem kötelező. Más manipulátorok egyszerű formázási lehetőséget biztosítanak. A setw() paraméteres manipulátorral a megjelenítéshez használt mező szélességét állíthatjuk be, melyen belül balra (left) és az alapértelmezés szerint jobbra (right) is igazíthatunk. A setw() manipulátor hatása csak a következő adatelemre terjed ki, míg a kiigazítás manipulátorainak hatása a következő kiigazítás manipulátorig tart.

#include <iostream>

#include <iomanip>

using namespace std;

int main() {

unsigned int szam = 123456;

cout << '|' << setw(10) << szam << '|' << endl;

cout << '|' << right << setw(10) << szam << '|' << endl;

cout << '|' << left << setw(10) << szam << '|' << endl;

cout << '|' << setw(10) << szam << '|' << endl;

}

A program futásának eredménye jól tükrözi a manipulátorok hatását:

| 123456|

| 123456|

|123456 |

|123456 |

2.3.4. A lebegőpontos típusok

Matematikai és műszaki számításokhoz az egészek mellett elengedhetetlen a törtrészeket is tartalmazó számok használata. Mivel ezekben a tizedespont helye nem rögzített, az ilyen számok tárolását segítő típusok a lebegőpontos típusok: float, double, long double. Az egyes típusok a szükséges memória mérete, a számok nagyságrendje és a pontos jegyek számában különböznek egymástól (lásd 4. szakasz - C++ adattípusok és értékkészletük függelék). (A Visual C++ a szabvány ajánlásától eltérően double típusként kezeli a long double típust.)

Már az ismerkedés legelején le kell szögeznünk, hogy a lebegőpontos típusok alkalmazásával le kell mondanunk a törtrészek pontos ábrázolásáról. Ennek oka, hogy a számok kitevős alakban (mantissza, kitevő), méghozzá 2-es számrendszerben tárolódnak.

double d =0.01;

float f = d;

cout<<setprecision(12)<<d*d<< endl; // 0.0001

cout<<setprecision(12)<<f*f<< endl; // 9.99999974738e-005

Egyetlen garantáltan egzakt érték a 0, tehát a lebegőpontos változók nullázása után értékük: 0.0.

A lebegőpontos konstansokat kétféleképpen is megadhatjuk. Kisebb számok esetén általában a tizedes tört alakot használjuk, ahol a törtrészt tizedespont választja el az egész résztől: 3.141592653, 100., 3.0. Nagyobb számok esetén a matematikából ismert kitevős forma számítógépes változatát alkalmazzuk, ahol az e, E betűk 10 hatványát jelölik: 12.34E-4, 1e6.

A lebegőpontos konstans értékek alapértelmezés szerint double típusúak. Az F utótaggal float típusú, míg L utótaggal long double típusú értékeket adhatunk meg: 12.3F, 1.2345E-10L. (Gyakori programhiba, hogy szándékaink szerint lebegőpontos konstans érték megadásakor sem tizedespontot, sem pedig kitevőt nem adunk meg, így a konstans egész típusú lesz.)

A lebegőpontos változók értékének megjelenítése során a már megismert mezőszélesség (setw()) mellet a tizedes jegyek számát is megadhatjuk – setprecision() (lásd 10. szakasz - Input/Output (I/O) manipulátorok függelék). Amennyiben az érték nem jeleníthető meg a formátum alapján, az alapértelmezés szerinti megjelenítés érvényesül. A tizedes tört és a kitevős forma közül választhatunk a fixed és scientific manipulátorokkal.

#include <iostream>

#include <iomanip>

using namespace std;

int main() {

double a = 2E2, b=12.345, c=1.;

cout << fixed;

cout << setw(10)<< setprecision(4) << a << endl;

cout << setw(10)<< setprecision(4) << b << endl;

cout << setw(10)<< setprecision(4) << c << endl;

}

A program futásának eredménye:

200.0000 12.3450 1.0000

Mielőtt továbblépnénk érdemes elidőzni a C++ nyelv aritmetikai típusai között végzett automatikus típus-átalakításnál. Könnyen belátható, hogy egy kisebb értékkészletű típus bármely nagyobb értékkészletű típussá adatvesztés nélkül átalakítható. Fordított helyzetben azonban általában adatvesztéssel jár az átalakítás, amire nem figyelmeztet a futtató rendszer, és a nagyobb szám egy része megjelenhet a „kisebb” típusú változóban.

short int s;

double d;

float f;

unsigned char b;

s = 0x1234;

b = s; // 0x34 ↯

// --- f = 1234567.0F;

b = f; // 135 ↯ s = f; // -10617 ↯

// --- d = 123456789012345.0;

b = d; // 0 ↯ s = d; // 0 ↯

f = d; // f=1.23457e+014 - pontosságvesztés ↯

2.3.5. Az enum típus

A programokban gyakran használunk olyan egész típusú konstans értékeket, amelyek logikailag összetartoznak.

A programunk olvashatóságát nagyban növeli, ha ezeket az értékeket nevekkel helyettesítjük. Ennek módja egy új típus a felsorolás (enum) definiálása az értékkészletének megadásával:

enum 〈 típusazonosító〉 { felsorolás };

A típusazonosító elhagyásával a típus nem jön létre, csak a konstansok születnek meg. Példaként tekintsük a hét munkanapjait tartalmazó felsorolást!

enum munkanapok {hetfo, kedd, szerda, csutorok, pentek};

A felsorolásban szereplő nevek mindegyike egy-egy egész számot képvisel. Alapértelmezés szerint az első elem (hetfo) értéke 0, a rákövetkező elemé (kedd) pedig 1, és így tovább (a pentek értéke 4 lesz).

A felsorolásban az elemekhez közvetlenül értéket is rendelhetünk. Ilyenkor az automatikus növelés a megadott értéktől folytatódik. Az sem okoz gondot, ha azonos értékek ismétlődnek, vagy ha negatív értéket adunk értékül.

Arra azonban ügyelnünk kell, hogy egy adott láthatósági körön (névtéren) belül nem szerepelhet két azonos nevű enum elem a definíciókban.

enum konzolszinek {fekete,kek,zold,piros=4,sarga=14,feher};

Az konzolszinek felsorolásban a feher elem értéke 15.

A közvetlen értékbeállítást nem tartalmazó felsorolásban az elemek számát megkaphatjuk egy további elem megadásával:

enum halmazallapot { jeg, viz, goz, allapotszam};

Az allapotszam elem értéke az állapotok száma, vagyis 3.

Az alábbi példában az enum típus és az enum konstansok felhasználását szemléltetjük:

#include <iostream>

using namespace std;

int main() {

enum kartya { treff, karo, kor, pikk };

enum kartya lapszin1 = karo;

kartya lapszin2 = treff;

cout << lapszin2 << endl;

int szin = treff;

cin >> szin;

lapszin1 = kartya(szin);

}

Felsorolás típusú változót a C nyelv és a C++ nyelv szabályai szerint egyaránt definiálhatunk. A C nyelv szerint az enum kulcsszó és a típusazonosító együtt alkotják az enum típust. A C++ nyelvben a típusazonosító önállóan is képviseli az enum típust.

Felsorolás típusú változó vagy felsorolási konstans kiírásakor az elemnek megfelelő egész érték jelenik meg.

Beolvasással azonban egészen más a helyzet. Mivel az enum nem előre definiált típusa a C++ nyelvnek - ellentétben a fent ismertetett típusokkal -, a cin nem ismeri azt. A beolvasás – a példában látható módon – egy int típusú változó felhasználásával megoldható. Itt azonban gondot jelent a C++ nyelv típusossága, ami bizonyos átalakításokat csak akkor végez el, ha erre külön „megkérjük” a típus-átalakítás (cast) műveletének kijelölésével: típusnév(érték). (A megfelelő értéke ellenőrzéséről magunknak kell gondoskodni, a C++ nem foglalkozik vele.)