How to Work with Variables, Data Types, and Arithmetic Expressions in the C Programming Language

A C a matematikai operátorok gazdag választékával rendelkezik, amelyeket az adatok manipulálására használhatunk. Stephen G. Kochan a Programming in C, 4. kiadásból ebben a fejezetben az int, float, double, char és _Bool adattípusokat, az adattípusok módosítását a short, long és long long long típusokkal, a változók elnevezésének szabályait, az alapvető matematikai operátorokat és aritmetikai kifejezéseket, valamint a típusváltást tárgyalja.

A létrehozott programok valódi ereje az adatok manipulálásában rejlik. Ahhoz, hogy ezt a hatalmat valóban kihasználhassa, jobban meg kell ismernie a különböző használható adattípusokat, valamint a változók létrehozásának és elnevezésének módját. A C a matematikai operátorok gazdag választékával rendelkezik, amelyeket az adatok manipulálására használhat. Ebben a fejezetben a következőkkel fogsz foglalkozni:

  • Az int, float, double, char és _Bool adattípusok
  • Az adattípusok módosítása a short, long, és long long
  • A változók elnevezésének szabályai
  • A matematikai alapoperátorok és aritmetikai kifejezések
  • Típusváltoztatás

Adattípusok és konstansok megértése

A C alapadattípusával, az int-tel már megismerkedett. Mint emlékszik, egy int típusúnak deklarált változó csak egészértékű – azaz tizedesjegyeket nem tartalmazó – értékek tárolására használható.

A C programozási nyelv négy másik alapvető adattípust biztosít: float, double, char és _Bool. A float típusúnak deklarált változó használható lebegőpontos számok (tizedesjegyeket tartalmazó értékek) tárolására. A double típus ugyanaz, mint a float típus, csak nagyjából kétszeres pontossággal. A char adattípus egyetlen karakter, például az “a” betű, a “6” számjegy vagy a pontosvessző (“;”) tárolására használható (erről később). Végül a _Bool adattípus csak a 0 vagy 1 értékek tárolására használható. Az ilyen típusú változókat a be/ki, igen/nem vagy igaz/hamis helyzetek jelzésére használják. Ezeket az egy-vagy-vagy-választásokat bináris választásoknak is nevezik.

A C-ben bármely számot, egyetlen karaktert vagy karakterláncot konstansnak nevezünk. Például az 58-as szám egy konstans egész értéket képvisel. A “C-ben programozni jó móka.\n” karakterlánc egy példa a konstans karakterláncra. A kizárólag konstans értékekből álló kifejezéseket konstans kifejezéseknek nevezzük. Tehát a

128 + 7 - 17

kifejezés konstans kifejezés, mert a kifejezés minden egyes tagja egy-egy konstans érték. Ha azonban i-t egész szám változónak deklarálnánk, a kifejezés

128 + 7 – i

nem képviselne konstans kifejezést, mert értéke az i értékétől függően változna. Ha i értéke 10, a kifejezés értéke 125, de ha i értéke 200, a kifejezés értéke -65.

Az egész szám típus int

A C nyelvben az egész konstans egy vagy több számjegyből álló sorozatból áll. A sorozatot megelőző mínuszjel jelzi, hogy az érték negatív. A 158, -10 és 0 értékek mind érvényes példák az egészértékű konstansokra. A számjegyek között nem engedélyezett a beágyazott szóköz, és a 999-nél nagyobb értékek nem fejezhetők ki vesszővel. (Tehát a 12,000 érték nem érvényes egészértékű konstans, és 12000-ként kell írni.)

A C-ben két speciális formátum teszi lehetővé, hogy az egészértékű konstansokat a decimális bázistól (10-es bázis) eltérő bázisban fejezzük ki. Ha az egész szám értékének első számjegye 0, akkor az egész számot oktális jelölésben – azaz 8-as bázison – kifejezve kell értelmezni. Ebben az esetben az érték fennmaradó számjegyeinek érvényes 8-as bázisú számjegyeknek kell lenniük, tehát 0-7-nek kell lenniük. Tehát az 50 érték 8-as bázison történő kifejezésére C-ben, amely a 40-es értéknek felel meg tizedesjegyben, a 050 jelölést használjuk. Hasonlóképpen, a 0177 oktális konstans a 127-es decimális értéket (1 × 64 + 7 × 8 + 7) jelenti. Egy egész számértéket a terminálon oktális jelöléssel lehet megjeleníteni, ha a printf() utasítás formázó karaktereit a printf() utasítás formázó karakterláncában a %o karakterek használatával használjuk. Ebben az esetben az érték oktálisan jelenik meg, vezető nulla nélkül. A %#o formátumkarakter hatására az oktális érték előtt egy vezető nulla jelenik meg.

Ha egy egészértékű konstans előtt egy nulla és az x betű (kis- vagy nagybetűs) szerepel, akkor az értéket hexadecimális (16-os bázisú) jelölésként kell értelmezni. Az x betű után közvetlenül a hexadecimális érték számjegyei következnek, amelyek a 0-9 számjegyekből és az a-f (vagy A-F) betűkből állhatnak. A betűk a 10-15 értékeket jelölik. Tehát az FFEF0D hexadecimális érték rgbColor nevű egészértékű változóhoz való hozzárendeléséhez a

rgbColor = 0xFFEF0D;

utasítás használható. A %x formátumjelek egy értéket hexadecimális formátumban jelenítenek meg a vezető 0x nélkül, és kisbetűs a-f betűket használnak a hexadecimális számjegyek helyett. Az értéknek a vezető 0x-szel történő megjelenítéséhez a %#x formátumkaraktereket használja, mint a következőkben:

printf ("Color is %#x\n", rgbColor);

A nagybetűs x, mint a %X vagy %#X, használható a vezető x és az azt követő hexadecimális számjegyek nagybetűkkel történő megjelenítéséhez.

Tárolási méretek és tartományok

Minden értékhez, legyen az karakter, egész szám vagy lebegőpontos szám, tartozik egy értéktartomány. Ennek a tartománynak köze van az adott adattípus tárolására elkülönített tárhely mennyiségéhez. Általában ez a mennyiség nincs meghatározva a nyelvben. Általában a használt számítógéptől függ, ezért implementáció- vagy gépfüggőnek nevezik. Egy egész szám például 32 bitet foglalhat el a számítógépen, de az is lehet, hogy 64-ben tárolják. Soha ne írjon olyan programokat, amelyek feltételezésekkel élnek az adattípusok méretét illetően. Azt azonban garantáljuk, hogy minden egyes alap adattípus számára minimális mennyiségű tárolóhelyet különítünk el. Például garantált, hogy egy egész szám értéket legalább 32 bitnyi tárolóhelyen tárolnak, ami sok számítógépen egy “szó” mérete.

A lebegő számok típusa float

A float típusúnak deklarált változó tizedesjegyeket tartalmazó értékek tárolására használható. A lebegőpontos konstansokat a tizedespont jelenléte különbözteti meg. A tizedespont előtti vagy a tizedespont utáni számjegyek elhagyhatók, de nyilvánvalóan mindkettő nem hagyható ki. A 3., 125.8 és -.0001 értékek mind érvényes példák a lebegőpontos konstansokra. A lebegőpontos értékek terminálon való megjelenítéséhez a printf konverziós karaktereket %f használjuk.

A lebegőpontos konstansok tudományos jelöléssel is kifejezhetők. Az 1.7e4 érték egy ilyen jelöléssel kifejezett lebegőpontos érték, amely az 1.7 × 104 értéket jelenti. Az e betű előtti értéket mantisszának, az utána következő értéket pedig exponensnek nevezzük. Ez az exponens, amelyet egy opcionális plusz- vagy mínuszjel előzhet meg, azt a tízes hatványt jelöli, amellyel a mantisszát meg kell szorozni. Tehát a 2,25e-3 konstansban a 2,25 a mantissza értéke, a -3 pedig az exponens értéke. Ez a konstans a 2,25 × 10-3, azaz 0,00225 értéket jelenti. Egyébként az e betű, amely elválasztja a mantisszát az exponensétől, kis- és nagybetűvel is írható.

Az érték tudományos jelöléssel való megjelenítéséhez a printf() formázó karakterláncban meg kell adni a %e formátumkaraktereket. A printf() formázási karakterek %g segítségével a printf() eldöntheti, hogy a lebegőpontos értéket normál lebegőpontos jelöléssel vagy tudományos jelöléssel jelenítse meg. Ez a döntés az exponens értékén alapul: Ha az kisebb, mint -4 vagy nagyobb, mint 5, akkor a %e (tudományos jelölés) formátumot használja, ellenkező esetben a %f formátumot.

A %g formátumkaraktereket használja a lebegőpontos számok megjelenítéséhez – ez adja a legesztétikusabb kimenetet.

A hexadecimális lebegőpontos konstans egy vezető 0x vagy 0X karakterből áll, amelyet egy vagy több decimális vagy hexadecimális számjegy követ, majd egy p vagy P, majd egy opcionálisan előjeles bináris exponens. Például a 0x0.3p10 a 3/16 × 210 = 0,5 értéket jelenti.

A kiterjesztett pontosságú típus double

A double típus nagyon hasonlít a float típushoz, de akkor használjuk, ha a float változó által biztosított tartomány nem elegendő. A double típusúnak deklarált változók nagyjából kétszer annyi szignifikáns számjegyet tárolhatnak, mint egy float típusú változó. A legtöbb számítógép a double értékeket 64 bittel ábrázolja.

Hacsak nem mondunk mást, a C fordító minden lebegőpontos konstansot double értéknek vesz. Egy float konstans kifejezett kifejezéséhez a szám végéhez vagy egy f vagy egy F karaktert kell csatolni, az alábbiak szerint:

12.5f

Kettős érték megjelenítéséhez a %f, %e vagy %g formátumkarakterek használhatók, amelyek ugyanazok a formátumkarakterek, mint a float értékek megjelenítéséhez.

Az egykarakteres típus char

A char változó egyetlen karakter tárolására használható.1 A karakterkonstans úgy képezhető, hogy a karaktert egy pár egyszerű idézőjelbe zárjuk. Így az ‘a’, a ‘;’ és a ‘0’ mind érvényes példák a karakterállandókra. Az első konstans az a betűt jelöli, a második egy pontosvessző, a harmadik pedig a nulla karakter – ami nem azonos a nulla számmal. Ne tévesszük össze a karakterállandót, amely egyetlen karaktert jelent egyszerű idézőjelek közé zárva, a karakterlánccal, amely bármilyen számú karaktert jelent kettős idézőjelek közé zárva.

A ‘\n’ karakterállandó – az újvonal karakter – érvényes karakterállandó, még akkor is, ha látszólag ellentmond a korábban idézett szabálynak. Ennek az az oka, hogy a backslash karakter a C rendszerben speciális karakter, és valójában nem számít karakternek. Más szóval a C fordító a ‘\n’ karaktert egyetlen karakterként kezeli, annak ellenére, hogy valójában két karakterből áll. Vannak más speciális karakterek is, amelyeket a backslash karakterrel indítanak. A teljes listát az A függelék “C nyelvi összefoglaló” című részében találja meg.

A %c formátumkarakterek a printf() hívásban használhatók egy char változó értékének a terminálon való megjelenítésére.

A Boolean adattípus _Bool

A _Bool változót a nyelv úgy definiálja, hogy elég nagy ahhoz, hogy csak a 0 és 1 értékeket tárolja. A felhasznált memória pontos mérete nincs meghatározva. Az _Bool változókat olyan programokban használják, amelyeknek Boole-állapotot kell jelezniük. Például egy ilyen típusú változót használhatunk annak jelzésére, hogy minden adatot beolvastunk-e egy fájlból.

Egyezmény szerint a 0 hamis értéket, az 1 pedig igaz értéket jelöl. Amikor értéket rendelünk egy _Bool változóhoz, a 0 értéket 0-ként tároljuk a változóban, míg minden nem nulla értéket 1-ként.

Az _Bool változókkal való munka megkönnyítése érdekében a programban a szabványos <stdbool.h> fejlécfájl definiálja a bool, true és false értékeket. Erre mutat példát az 5. fejezet “Döntések meghozatala” című fejezetének 5.10A programja.”

A 3.1. programban a C alap adattípusait használjuk.

3.1. program Az alap adattípusok használata

3.1. program Kimenet

integerVar = 100floatingVar = 331.790009doubleVar = 8.440000e+11doubleVar = 8.44e+11charVar = WboolVar = 0;

A 3. program első utasítása.1 az integerVar változót integer változónak deklarálja, és hozzá is rendel egy 100-as kezdeti értéket, mintha a következő két utasítást használtuk volna helyette:

int integerVar;integerVar = 100;

A program kimenetének második sorában figyeljük meg, hogy a floatingVar-hoz rendelt 331,79-es érték valójában 331,790009-ként jelenik meg. Valójában a ténylegesen megjelenített érték az Ön által használt számítógépes rendszertől függ. Ennek a pontatlanságnak az az oka, hogy a számokat a számítógépen belül sajátos módon ábrázolják. Valószínűleg Ön is találkozott már hasonló pontatlansággal, amikor zsebszámológépén számokkal dolgozott. Ha a számológépen elosztja 1-et 3-mal, akkor az eredmény 0,3333333333 lesz, esetleg a végén még néhány plusz 3-as számmal. A 3-asok sora a számológép egyharmadhoz való közelítése. Elméletileg végtelen számú 3-asnak kellene lennie. De a számológép csak ennyi számjegyet tud tárolni, ezért a gép eredendő pontatlansága. Ugyanez a fajta pontatlanság érvényes itt is: Bizonyos lebegőpontos értékek nem ábrázolhatók pontosan a számítógép memóriájában.

A lebegőpontos vagy kettős változók értékeinek megjelenítésekor háromféle formátum közül választhatunk. A %f karakterek az értékek szabványos módon történő megjelenítésére szolgálnak. Hacsak nincs más utasítás, a printf() mindig hat tizedesjegyre kerekítve jeleníti meg a float vagy double értéket. A fejezet későbbi részében láthatjuk, hogyan választhatjuk ki a megjelenített tizedesjegyek számát.

A %e karakterek egy lebegő- vagy kettős változó értékének tudományos jelöléssel történő megjelenítésére szolgálnak. Itt is hat tizedesjegyet jelenít meg automatikusan a rendszer.

A %g karakterekkel a printf() választ a %f és %e karakterek között, és automatikusan eltávolítja a megjelenítésből a hátul lévő nullákat is. Ha a tizedesvesszőt nem követi számjegy, akkor azt sem jeleníti meg.

Az utolsó előtti printf() utasításban a %c karakterek segítségével jeleníti meg azt az egyetlen ‘W’ karaktert, amelyet a változó deklarálásakor a charVar-hoz rendeltünk. Ne feledjük, hogy míg egy karakterláncot (például a printf() első argumentumát) kettős idézőjelek közé zárunk, addig egy karakterkonstansot mindig szimpla idézőjelek közé kell zárni.

Az utolsó printf() utasítás azt mutatja, hogy egy _Bool változó értékét a %i egész szám formátumú karakterekkel lehet megjeleníteni.

Típusmeghatározók: long, long long long, short, unsigned és signed

Ha a long meghatározó közvetlenül az int deklaráció elé kerül, akkor a deklarált egészértékű változó egyes számítógépes rendszereken kiterjesztett tartományú. A long int deklarációra példa lehet a következő

long int factorial;

Ez a factorial változót long egészértékű változónak deklarálja. A lebegőszámokhoz és a páros számokhoz hasonlóan a hosszú számváltozók konkrét pontossága az adott számítógépes rendszertől függ. Sok rendszeren az int és a long int tartománya megegyezik, és bármelyik használható akár 32 bit széles egész értékek tárolására (231 – 1, vagy 2,147,483,647).

A long int típusú konstans értéket úgy képezzük, hogy opcionálisan az L betűt (nagy- vagy kisbetűt) csatoljuk egy egészértékű konstans végére. A szám és az L között szóköz nem megengedett. Így a deklaráció

long int numberOfPoints = 131071100L;

a numberOfPoints változót long int típusúnak deklarálja, 131,071,100 kezdeti értékkel.

A long int értékének printf() segítségével történő megjelenítéséhez az l betűt módosítóként használjuk az i, o és x egész szám formátumú karakterek előtt. Ez azt jelenti, hogy a %li formátumkarakterekkel egy long int értékét decimális formátumban, a %lo karakterekkel oktális formátumban, a %lx karakterekkel pedig hexadecimális formátumban lehet megjeleníteni.

A long long long integer adattípus is létezik, így

long long int maxAllowedStorage;

a megadott változót a megadott kiterjesztett pontosságúnak nyilvánítja, amely garantáltan legalább 64 bit széles. A hosszú hosszú egész számok megjelenítéséhez egyetlen l betű helyett két l-t használunk a printf karakterláncban, mint például a “%lli”-ben.

A long specifikáló a double deklaráció előtt is megengedett, az alábbiak szerint:

long double US_deficit_2004;

A long double konstans lebegő konstansként íródik, közvetlenül utána l vagy L betűvel, például

1.234e+7L

A long double konstans megjelenítéséhez az L módosítót használjuk. Tehát a %Lf egy long double értéket lebegőpontos jelöléssel jelenít meg, a %Le ugyanezt az értéket tudományos jelöléssel, a %Lg pedig azt mondja a printf()-nek, hogy válasszon a %Lf és a %Le között.

A short specifikáló, amikor az int deklaráció elé kerül, azt mondja a C fordítónak, hogy az adott deklarált változót meglehetősen kis egész számértékek tárolására használják. A short változók használatának motivációja elsősorban a memóriaterület megóvása, ami olyan helyzetekben jelenthet problémát, amikor a programnak sok memóriára van szüksége, és a rendelkezésre álló memória mennyisége korlátozott.

Egy short int egyes gépeken feleannyi tárhelyet foglal el, mint egy hagyományos int változó. Mindenesetre garantált, hogy a short int számára kiosztott hely nem lesz kevesebb, mint 16 bit.

Nincs mód arra, hogy explicit módon írjunk short int típusú konstansokat a C-ben. Short int változó megjelenítéséhez a h betűt helyezzük a normál egész szám konverziós karakterek bármelyike elé: %hi, %ho vagy %hx. Alternatívaként a short ints megjelenítésére az integer konverziós karakterek bármelyikét is használhatjuk, köszönhetően annak, hogy a printf() rutinhoz argumentumként való átadáskor egész számokká konvertálhatók.

Az int változó elé helyezhető utolsó specifikálót akkor használjuk, ha az integer változót csak pozitív számok tárolására használjuk. A deklaráció

unsigned int counter;

deklarálja a fordítónak, hogy a változó számlálója csak pozitív értékek tárolására szolgál. Azzal, hogy az egészértékű változó használatát kizárólag pozitív egész számok tárolására korlátozzuk, az egészértékű változó pontossága kibővül.

Az előjel nélküli int konstans úgy képezhető, hogy a konstans után az u (vagy U) betűt helyezzük el, a következőképpen:

0x00ffU

Az u (vagy U) és az l (vagy L) betűket kombinálhatjuk, amikor egészértékű konstansokat írunk, így

20000UL

a fordítónak azt mondja, hogy a 20000-as állandót előjel nélküli hosszúként kezelje.

Egy olyan egészértékű konstanst, amelyet nem követ az u, U, l vagy L betűk egyike sem, és amely túl nagy ahhoz, hogy egy normál méretű int-be beférjen, a fordító előjel nélküli int-ként kezel. Ha túl kicsi ahhoz, hogy beleférjen egy unsigned int-be, a fordító long int-ként kezeli. Ha még mindig nem fér bele egy long int-be, a fordító előjel nélküli long int-té alakítja. Ha nem fér bele, akkor a fordító long long int-ként kezeli, ha befér, egyébként pedig előjel nélküli long long long int-ként.

Az int kulcsszó elhagyható, ha a változókat long long int, long int, short int vagy unsigned int típusúnak deklaráljuk. Ezért az előjel nélküli változó számlálót egyenértékűen a következőképpen is deklarálhattuk volna:

unsigned counter;

A char változókat is deklarálhatjuk előjel nélkülinek.

A signed minősítővel kifejezetten közölhetjük a fordítóval, hogy egy adott változó előjeles mennyiség. Használata elsősorban a char deklaráció előtt történik, és további tárgyalása elmarad a 13. fejezetig, “Bővebben az adattípusokról.”

Ne aggódjon, ha e specifikátorok tárgyalása ezen a ponton kissé ezoterikusnak tűnik önnek. A könyv későbbi fejezeteiben e különböző típusok közül sokat tényleges programpéldákkal illusztrálunk. A 13. fejezet részletesebben foglalkozik az adattípusokkal és a konverziókkal.

A 3.1. táblázat összefoglalja az alapvető adattípusokat és minősítőket.

3.1. táblázat Alapvető adattípusok