Informatika2-2015/Eloadas 10 C-3 Mutatok
(Új oldal, tartalma: „= Preprocesszor = A C programok fordítása két részből áll. Először lefut az úgynevezett "preprocesszor", és utána fut le a rendes fordító. A preprocesszor…”)
Újabb szerkesztés →
A lap 2015. április 22., 08:11-kori változata
Tartalomjegyzék |
Preprocesszor
A C programok fordítása két részből áll. Először lefut az úgynevezett "preprocesszor", és utána fut le a rendes fordító. A preprocesszor olyan utasításokat kap, amiket a programon mint szövegen hajt végre, úgy, hogy még nem próbálja értelmezni hogy C-ben mit jelent az. Mindjárt meglátjuk hogy ennek milyen következményei vannak.
Persze általában nem kell tudnotok hogy egy fordító hogy működik belül, de mivel itt a preprocesszor eléggé mást és máshogy csinál mint a rendes fordítók, ezért külön tanuljuk azt ami hozzá tartozik.
A preprocesszornak a kettőskereszttel kezdődő sorok szólnak. Mivel ezek nem C parancsok egészen pontosan, más nevük van, preprocesszor direktíváknak hívjuk őket.
include
Az egyetlen példa amit láttunk eddig erre, az az "#include" parancs. Az #include az azt csinálja, hogy egy másik fájl teljes tartalmát beilleszti annak a sornak a helyére. tehát amikor azt írjuk, hogy
#include <stdio.h>
Akkor a fordító fog egy "stdio.h" nevű fájlt (ami a fordítón belül van), és annak a teljes tartalmát beilleszti ennek a sornak a helyére. Ez a fájl az, ami a különböző beépített függvények deklarációit tartalmazza, ezért használhatjuk őket, miután volt ilyen #include sor.
Ezzel lehet saját másik fájlokat is együtt felhasználni, akkor nem kacsacsőröket, hanem dupla idézőjeleket kell használni a fájlnévnél, így:
#include "masik_fajl.h"
Az a különbség a kettő között, hogy az idézőjellel megadott fájlokat először az aktuális könyvtárban keresi, míg a kacsacsőrrel megadottakat először a fordító könyvtárában keresi.
define
Vegyük ezt a korábbi példát:
// Dokumentaljuk is le, hogy max. 1000-el mukodik int fun(int n) { if(n > 1000) { return -1; // Ezzel a hibat jelezzuk } int tomb[1000]; // A tenyleges szamolasok... // Amik a tomb-nek csak az elso n elemet hasznaljak }
Itt az a probléma, hogy az "1000" mint limit, kétszer is le van írva. Ha meg akarjuk növelni a limitet 2000-re, könnyen elfelejthetjük, hogy két helyen is módosítani kell, és csak az egyiket írjuk át. Azonban, a szabvány szerint, nem használhatunk változót a tömb méretének megadására, ezért az sem működik, hogy eg változóba tároljuk el. Ehelyett a "#define" direktívát használhatjuk egy konstans meghatározására. Itt van ez jól megvalósítva:
#define TOMB_MAX_MERET 1000 // Dokumentaljuk is le, hogy max. 1000-el mukodik int fun(int n) { if(n > TOMB_MAX_MERET) { return -1; // Ezzel a hibat jelezzuk } int tomb[TOMB_MAX_MERET]; // A tenyleges szamolasok... // Amik a tomb-nek csak az elso n elemet hasznaljak }
Ezzel elértük hogy egy helyen elég módosítani a méretet. Azonban ezzel a #define-nal vigyázni kell. Ezt a preprocesszor csinálja, ami nem érti a C kódot, és annak különböző részeit, bárhol ahol azt a nevet látja amit megadtunk neki, oda behelyettesíti azt a másik betűsort amit megadtunk neki. Így pl. ha ezt írjuk:
#define a xxx int alap(int u) { int az = 0; // stb... }
Akkor ebben a kódban a preprocesszor a kis "a" betű minden előfordulását kicseréli, tehát "xxxlxxxp" nevű függvényt definiáltunk, és azon belül egy "xxxz" nevű változónk van. Ez még túlélhető lenne, de ha pl. az "i" betűt #define-olom, akkor már azt se írhatom le sikeresen hogy "int", így egész változókat nem tudok megadni.
Tehát a lényeg az, hogy olyan nevet adjak a #define-al megadott konstansnak, ami nem fordulhat elő máshol a kódban. Az általánosan elfogadott szokás az, hogy a #define-al megadott konstansoknak a neve csupa nagybetűből áll, ezt ajánlom követni.
Mutatók
A C-ben az ilyen mutable és immutable dolgok helyett van egy speciális külön típus, a mutató. Már az előző előadáson említettem a szintaxist, hogy hogy néz ki, a *-gal jelöljük. Tehát egy int típusú változóra mutató mutatót így definiálunk:
int *mutato;
Egyszerű változókra mutatók
A mutató típusú változók