Preprocesszor
Programozás alapjai C nyelv 11. gyakorlat
• A forrás szöveges előfeldolgozását végzi. • # -kal kezdődő sorok • Bárhol megjelenhetnek, hatásuk a fordítási egység végéig tart. • Feldolgozás menete:
Szeberényi Imre BME IIT
– trigráf karakterek (ISO ANSI pl: ??[ = { ) – \sorvége – tokenizálás, kommentek eldobása – makrók és fordítási direktívák végrehajtása
<
[email protected]>
Programozás alapjai I. (C nyelv, gyakorlat)
© BME-IIT Sz.I.
2005.11.28.
-1-
Makrók (#define)
int a = MAX(3, i); float f = MAX(3.12, f8);
© BME-IIT Sz.I.
2005.11.28.
Tetszőleges típusú lehet, rugalmasabb mint a fv.
int a = 3 > i ? 3 : i; float f = 3.12 > f8 ? 3.12 : f8; -3-
Programozás alapjai I. (C nyelv, gyakorlat)
Makrók (3) a = MAX(c & 7, d);
-2-
#define MAX(a, b) a > b ? a : b
int a[52]; for (i = 0; i < 52; ) a[i++] = 0;
Programozás alapjai I. (C nyelv, gyakorlat)
2005.11.28.
#define azonosító token_sorozat #define azonosító ( azonosító_lista ) token_sorozat
52 /* elemek száma */ 1 /* igaz logikai konstans */ 0
int a[N]; for (i = 0; i < N; ) a[i++] = FALSE;
© BME-IIT Sz.I.
Makrók (2)
#define azonosító token_sorozat #define N #define TRUE #define FALSE
Programozás alapjai I. (C nyelv, gyakorlat)
© BME-IIT Sz.I.
2005.11.28.
-4-
2005.11.28.
-6-
#include #include
#include ” fájlnév” #include token_sorozat
a = c & 7 > d ? c & 7 : d;
A precedenciából adódó problémákat elfedi, nehéz az ilyen hibát megtalálni! Zárójelek !!!
fájl
#define MAX(a, b) (a) > (b) ? a : b a = (c & 7) > (d) ? c & 7 : d; #undef MAX #undef TRUE
#undef azonosító Programozás alapjai I. (C nyelv, gyakorlat)
© BME-IIT Sz.I.
2005.11.28.
-5-
Programozás alapjai I. (C nyelv, gyakorlat)
© BME-IIT Sz.I.
1
Feltételes fordítás #if konstans_kifejezés ... #elif konstans_kifejezés ... #else ... #endif
Feltételes fordítás (2)
#if DEBUG ... #else ... #endif
#ifdef azonosító #else #endif
A konstans kifejezésben használható a defined (azonosító) kifejezés, ami 1L, vagy 0L értékkel helyettesítődik. Így a #if defined(azonosíto) és a #ifdef azonosító valamint a #if !defined(azonosító) és a #ifndef azonosító direktívák egyenértékűek.
A makrók a fordításkor kívülről (pl. parancssorból) is definiálhatók, így a forráshoz hozzá sem kell nyúlni. Programozás alapjai I. (C nyelv, gyakorlat)
© BME-IIT Sz.I.
2005.11.28.
-7-
Programozás alapjai I. (C nyelv, gyakorlat)
Állomány (Fájl)
• Hozzáférés szerint
© BME-IIT Sz.I.
2005.11.28.
-9-
Programozás alapjai I. (C nyelv, gyakorlat)
FILE típus
2005.11.28.
- 10 -
FILE *fopen(char *name, char *mod) • megnyitás módja:
– adminiszrációs területet, és – a műveletek gyorsítására buffert tartalmaz
r w a r+ w+ a+
• A fájl megnyitásakor a fopen(...) egy ilyen területre mutató címmel (FILE *) tér vissza. • Minden további műveletkor erre kell hivatkozni.
© BME-IIT Sz.I.
© BME-IIT Sz.I.
fopen()
• stdio.h-ban definiált struktúra, ami
Programozás alapjai I. (C nyelv, gyakorlat)
-8-
– fopen, fscanf, fprintf, fgetc, fputc, ungetc, feof, fread, fwrite, fseek, ftell, fflush, fclose, remove, rename, tmpfile, ...
– soros – véletlen
Programozás alapjai I. (C nyelv, gyakorlat)
2005.11.28.
• C nyelv kialakulásakor kezdetben az operációs rendszer (UNIX) fájlkezelését támogatta a nyelv. Ez ma is elérhető, de nem ANSI szabvány (alacsony szintű I/O, nem árt ismerni /open, read, write, .../) • ANSI C stream szemlélete
– rekord – mező – byte
– szöveg – adat – adatbázis
© BME-IIT Sz.I.
Állománykezelés
Állomány: • Elvileg végtelen hosszúságú adatszerkezet
• Tartalom szerint
#ifndef azonosító #else #endif
2005.11.28.
- 11 -
-
csak olvasás írás és olvasás (létrehozza) hozzáfűzés (létrehozza) írás és olvasás írás és olvasás (létrehozza) hozzáfűzés (írás és olvasás, létrehozza)
Programozás alapjai I. (C nyelv, gyakorlat)
© BME-IIT Sz.I.
2005.11.28.
- 12 -
2
fopen() példa
Feladat: mycopy
#include <stdio.h> main() { FILE *fp; char *nev = ”adat.txt”; int i;
• Írjuk programot, ami lemásol egy állományt! A program paraméterként kapja a forrás ill. cél állományok neveit. mycopy file_1 file_2
• Indítási paraméter v. parancsnyelvi argumentum:
if ((fp = fopen(nev, ”r”)) == NULL) { printf(”A %s fájl nem nyitható\n”, nev); exit(-1); } fscanf(fp, ”%d”, &i);
......
Programozás alapjai I. (C nyelv, gyakorlat)
© BME-IIT Sz.I.
2005.11.28.
– Az operációs rendszer által a program indításakor átadott adat. – Rendszerint szóközökkel határolt karaktersorozat. A pontos szintaxis az op.rendszertől függ. - 13 -
A main paraméterei
argc - Megadja a paraméterek számát (a program neve is egy paraméter, tehát argc >= 1). argv - Paraméterekre, mint karaktersorozatokra mutató pointerek tömbje (argv[0] a program nevére mutat). A karaktersorozatokat \0 határolja (string)
© BME-IIT Sz.I.
2005.11.28.
- 15 -
Programozás alapjai I. (C nyelv, gyakorlat)
while (!feof(fpin) { ch = fgetc(fpin); fputc(ch, fpout); }
while ((ch = fgetc(fpin)) != EOF) fputc(ch, fpout); fclose(fpin); fclose(fpout); return (0);
© BME-IIT Sz.I.
2005.11.28.
- 16 -
2005.11.28.
while (!feof(fpin) { ch = fgetc(fpin); if (ch != EOF) fputc(ch, fpout); }
9
• Eltérően a Pascal EOF-tól, nem jós, hanem utólag okos függvény. • Így használata nem jár különös előnyökkel.
A main-ből való kilépes exit(n) hivást fog eredményezni.
© BME-IIT Sz.I.
- 14 -
feof()
int függvény !!
Programozás alapjai I. (C nyelv, gyakorlat)
2005.11.28.
#include <stdio.h> program neve main(int argc, char *argv[]) { FILE *fpin, *fpout; int ch; if (argc != 3) { printf(”Használat: %s forrás cél\n”, argv[0]); return(1); } if ((fpin = fopen(argv[1], ”r”)) == NULL) { printf(”A %s fájl nem nyitható\n”, argv[1]); return(2); } if ((fpout = fopen(argv[2], ”w”)) == NULL) { printf(”A %s fájl nem hozható létre\n”, argv[2]); return(3); }
mycopy program (2)
}
© BME-IIT Sz.I.
mycopy program
int main(int argc, char *argv[])
Programozás alapjai I. (C nyelv, gyakorlat)
Programozás alapjai I. (C nyelv, gyakorlat)
- 17 -
Programozás alapjai I. (C nyelv, gyakorlat)
© BME-IIT Sz.I.
2005.11.28.
- 18 -
3
stdin, stdout, stderr
Bináris és szöveg fájl
• Egy program indulásakor automatikusan megnyílnak (szabványos bemenet, kimenet és hiba kimenet). • scanf, printf, perror ezeket használja • perror(s) ≡ fprintf(stderr, ”%s: %s\n”, s, ”hiba”) • getchar() ≡ getc(stdin) ≡ fgetc(stdin) • putchar(c) ≡ putc(c, stdout) ≡ fputc(c, stdout) • stb. Programozás alapjai I. (C nyelv, gyakorlat)
© BME-IIT Sz.I.
2005.11.28.
- 19 -
A probléma megoldása
© BME-IIT Sz.I.
2005.11.28.
• Miért kell? – A UNIX rendszerben a szöveges állományok sorait csak egyetlen karakter határolja a ’\n’. – A nem UNIX rendszerekben - hagyományi okok miatt - többnyire két karaktert tárolnak minden sor végén. (’\r’,’\n’) – A C programok nagy része csak a ’\n’-t várja ill. írja ki. Programozás alapjai I. (C nyelv, gyakorlat)
- 20 -
size_t fread(void *p, size_t m, size_t n, FILE *fp); size_t fwrite(void *p, size_t m, size_t n, FILE *fp);
n darab m méretű rekord olvasása ill. írása Hibakezelés: •feof(), ferror(), •int errno - 21 -
Programozás alapjai I. (C nyelv, gyakorlat)
© BME-IIT Sz.I.
2005.11.28.
- 22 -
Feladat 1
Író/olvasó pointer bájtot címez.
• Tároljuk el a hallgatók adatait (név, átlag) tankörönként, azon belül névsorba rendezve. • A tankörök számát
int fseek(FILE *fp, long offset, int bazis); long ftell(FILE *fp);
– ismerjük – nem ismerjük
int fgetpos(FILE *fp, fpos_t *p);
• Válasszunk adatszerkezetet!
int fsetpos(FILE *fp, const fpos_t *p);
© BME-IIT Sz.I.
2005.11.28.
Rekord szemlélet
Pozicionálás az állományban
Programozás alapjai I. (C nyelv, gyakorlat)
© BME-IIT Sz.I.
fread(), frwite()
• Beolvasáskor minden \r\n sorozatból \n-t csinálunk. • Kiíráskor minden \n-t \r\n sorozattal helyettesítünk. • CSAK SZÖVEG esetén kell konvertálni! • Más esetben KÁROS! • Általában a text az alapértelmezett (_fmode). • Fontos a helyes beállítás. Programozás alapjai I. (C nyelv, gyakorlat)
• Megnyitásnál t, vagy b (pl: ”rt”, ”a+t”)
2005.11.28.
- 23 -
Programozás alapjai I. (C nyelv, gyakorlat)
© BME-IIT Sz.I.
2005.11.28.
- 24 -
4
Adatszerkezet
Adatszerkezet
• Tankörönként építünk láncot. • A láncok névsor szerint rendezettek, és a végükön van strázsa. • Ha a tankörök száma ismert, akkor láncok kezdőpointerét egy a tankörszámmal indexelt tömbbe tehetjük.
Programozás alapjai I. (C nyelv, gyakorlat)
© BME-IIT Sz.I.
2005.11.28.
- 25 -
2005.11.28.
- 27 -
„Fésű” adatszerkezet
ADAT KOV
FEJ KOV LE
FEJ KOV LE
????? KOV
????? KOV Programozás alapjai I. (C nyelv, gyakorlat)
ADAT KOV
ADAT KOV
ADAT KOV
????? KOV
Programozás alapjai I. (C nyelv, gyakorlat)
© BME-IIT Sz.I.
2005.11.28.
- 26 -
Programozás alapjai I. (C nyelv, gyakorlat)
© BME-IIT Sz.I.
2005.11.28.
- 28 -
Feladat 1 (kiegészítés) • Olvassuk be a hallgatók adatait az indítási paraméterkén megadott állományból! Ebben soronként vannak a hallgatók adatai:
????? KOV LE
– név 40 karakter – tankörszám (egész) – elválasztó szóköz – átlag (valós szám)
ADAT KOV
• Írjuk a ki tankörönként a hallgatók névsorát és átlagát!
????? KOV © BME-IIT Sz.I.
????? KOV
• Gyakran több szempont (kulcs) szerint kell rendezni, pl. tankörönként, azon belül névsorban. • Ha egyik szempont szerint sem ismert a bemenő adatok száma, akkor több, vagy többszörösen láncolt listát célszerű építeni. • Megfelelő pointerláncok kialakításával biztosítható, hogy az adatok csak egyszeresen legyenek tárolva.
h_poi tankorok[10];
FEJ KOV LE
ADAT KOV
Bonyolultabb adatszerkezet
typedef char nev_t[41]; typedef struct hallg_str { nev_t nev; float atl; struct hallg_str *kov; } hallg_t, *h_poi;
© BME-IIT Sz.I.
ADAT KOV
...
Adatszerkezet
Programozás alapjai I. (C nyelv, gyakorlat)
ADAT KOV
2005.11.28.
- 29 -
Programozás alapjai I. (C nyelv, gyakorlat)
© BME-IIT Sz.I.
2005.11.28.
- 30 -
5
Vázlat (adatszerkezet)
Vázlat (adatszerkezet)
typedef char nev_t[NEVH+1]; typedef struct hallg_str { nev_t nev; float atl; struct hallg_str *kovh; } hallg_t, *h_poi;
typedef struct input_str { nev_t nev; int tk; float atl; } inp_t;
typedef struct tankor_str { int tk; struct tankor_str *kovtk; struct hallg_str *kovh; } tankor_t, *t_poi; Programozás alapjai I. (C nyelv, gyakorlat)
© BME-IIT Sz.I.
2005.11.28.
- 31 -
Vázlat (algoritmus)
Programozás alapjai I. (C nyelv, gyakorlat)
© BME-IIT Sz.I.
2005.11.28.
- 32 -
Alprogram spec. - inic t_poi inic(void); – t_poi értékű függvény, amely beállítja a megfelelő kezdeti értékeket, létrehozza a strázsaelemet. – bemenet:
kezdo = inic() fp = fopen(argv[1], “r”) while beolvas(fp, &adat) fesul(kezdo, adat) kiir(kezdo)
• nincs
– kimenet: • függvényérték: strázsára mutató pointer
Programozás alapjai I. (C nyelv, gyakorlat)
© BME-IIT Sz.I.
2005.11.28.
- 33 -
Alprogram spec. - beolvas
© BME-IIT Sz.I.
2005.11.28.
- 34 -
Alprogram spec. - fesul
int beolvas(FILE *fp, inp_t *r);
h_poi fesul(t_poi tp, inp_t r);
– függvény, amely a paraméterként kapott állományból, beolvassa a következő hallgató adatait. Sikeres olvasás eseten 1 értékkel tér vissza. – bemenet:
– t_poi értékű üggvény, amely a paraméterként kapott fésűs láncra felveszi a szintén paraméterként kapott adatot. A láncot rendezve építi. A lánc végén van strázsa. – bemenet:
• megnyitott állomány pointere • pointer a kimenő adatra
• láncra mutató pointer • felveendő adat
– kimenet:
– kimenet:
• olvasott adat (pointer paraméter) • függvényérték 1, ha sikerült az olvasás, egyébként 0 Programozás alapjai I. (C nyelv, gyakorlat)
Programozás alapjai I. (C nyelv, gyakorlat)
© BME-IIT Sz.I.
2005.11.28.
• a lánc épül • függvényérték NULL, ha elfogyott a memória - 35 -
Programozás alapjai I. (C nyelv, gyakorlat)
© BME-IIT Sz.I.
2005.11.28.
- 36 -
6
Alprogram spec. - kiír
Algoritmus - fesul
void kiir(t_poi tp);
tp = tankor_lanc(tp, tk) hallgato_lanc(tp->kovh, adat)
– A paraméterként kapott fésűs láncot végigjárja és kiírja az elemeket. – bemenet: • láncra mutató pointer
– kimenet: • standard output
Programozás alapjai I. (C nyelv, gyakorlat)
© BME-IIT Sz.I.
2005.11.28.
- 37 -
Alprogram spec. - tankor_lancol
Programozás alapjai I. (C nyelv, gyakorlat)
© BME-IIT Sz.I.
2005.11.28.
- 38 -
Alprogram sp. - hallgato_lancol
t_poi tankor_lanc(t_poi tp, int tk);
h_poi hallgato_lanc(h_poi hp, inp_t r);
– Függvény, amely a paraméterként kapott tankörláncon megkeresi, ill. felveszi a szintén paraméterként kapott tankört. A láncot rendezve építi. A lánc végén van strázsa. – bemenet:
– A paraméterként kapott hallgatóláncra felveszi a szintén paraméterként kapott hallgatói adatot. A láncot rendezve építi. A lánc végén van strázsa. – bemenet: • láncra mutató pointer • a felveendő adat
• láncra mutató pointer • a keresett tankör száma
– kimenet:
– kimenet:
• függvényérték: a lánc megfelelő elemére mutató pointer. NULL, ha elfogyott a memória Programozás alapjai I. (C nyelv, gyakorlat)
© BME-IIT Sz.I.
2005.11.28.
- 39 -
A „fésű” TK KOVTK KOVH
TK KOVTK KOVH
NEV,ATL KOVH
????? KOVH
Programozás alapjai I. (C nyelv, gyakorlat)
© BME-IIT Sz.I.
2005.11.28.
- 40 -
• A tömörebb íráshoz vezessük be a new makrót, ami megfelelő méretű helyet foglal, és hibát is kezel (visszatér a NULL-lal):
????? KOVTK KOVH
pointer változó
NEV,ATL KOVH
tárolandó objektum típusa
#define new(p, obj) \ if ((p = malloc(sizeof(obj))) == NULL) return(NULL)
????? KOVH © BME-IIT Sz.I.
Programozás alapjai I. (C nyelv, gyakorlat)
Implementáció - tankor_lancol
TK KOVTK KOVH
????? KOVH
• függvényérték NULL, ha elfogyott a memória
2005.11.28.
- 41 -
Programozás alapjai I. (C nyelv, gyakorlat)
© BME-IIT Sz.I.
2005.11.28.
- 42 -
7
Implementáció - tankor_lancol
Implementáció - hallgato_lancol
t_poi tankor_lanc(t_poi tp, int tk) { t_poi uj;
h_poi hallgato_lanc(h_poi hp, inp_t r) { h_poi uj;
while (tp->kovtk && tp->tk < tk) tp = tp->kovtk; if (tp->kovtk == NULL || tp->tk != tk) { new(uj, tankor_t); *uj = *tp; tp->kovtk = uj; tp->tk = tk; new(tp->kovh, hallg_t); tp->kovh->kovh = NULL; } return(tp);
while (hp->kovh && strcmp(hp->nev, r.nev) < 0) hp = hp->kovh; new(uj, hallg_t); *uj = *hp; hp->kovh = uj; strcpy(hp->nev, r.nev); hp->atl = r.atl; string másolása return(hp); }
} Programozás alapjai I. (C nyelv, gyakorlat)
© BME-IIT Sz.I.
2005.11.28.
- 43 -
Programozás alapjai I. (C nyelv, gyakorlat)
Karakterfüzérek (stringek)
2005.11.28.
- 45 -
Programozás alapjai I. (C nyelv, gyakorlat)
Implementáció - kiir void kiir(t_poi tp) { while (tp->kovtk) { h_poi hp;
}
}
© BME-IIT Sz.I.
int beolvas(FILE *fp, inp_t *r) { char buf[NEVH+20];
a ciklusban érvényes
} © BME-IIT Sz.I.
- 44 -
2005.11.28.
- 46 -
Implementáció - beolvas
printf(”Tankör: %3d\n”, tp->tk); hp = tp->kovh; while (hp->kovh) { printf(” %50s%5.2f\n”, hp->nev, hp->atl); hp = hp->kovh; } tp = tp->kovtk;
Programozás alapjai I. (C nyelv, gyakorlat)
2005.11.28.
t_poi fesul(t_poi tp, inp_t r) { if ((tp = tankor_lancol(tp, r.tk)) == NULL) return(NULL); return(hallgato_lancol(tp->kovh, r)); }
– strcmp, strcpy, strncpy, strcat, strncat, strchr, strstr, strlen, strtok, stb.
© BME-IIT Sz.I.
© BME-IIT Sz.I.
Implementáció - fesul
• Nincs külön string változó, de konstans van. • A stringeket olyan karakter tömbben tároljuk, melynek végén egy \0 van. • Ezt figyelik a string-kezelő függvények (string.h).
Programozás alapjai I. (C nyelv, gyakorlat)
stringek összehasonlítása
2005.11.28.
- 47 -
teljes sor beolvasása
if (fgets(buf, sizeof(buf), fp) == NULL) return(0); lezárás strncpy(r->nev, buf, NEVH); r->nev[NEVH] = 0; sscanf(&buf[NEVH], ”%d%f”, &r->tk, &r->atl); return(1); beolvasás után könyebben
Programozás alapjai I. (C nyelv, gyakorlat)
„mazsolázunk” benne © BME-IIT Sz.I.
2005.11.28.
- 48 -
8
Implementáció - inic
Implementáció - program #include <stdio.h> #include <stdlib.h> #include <string.h>
t_poi inic(void) { t_poi tp;
#define new(p, obj) \ if ((p = malloc(sizeof(obj))) == NULL) \ return(NULL)
nincs paramétere
new(tp, tankor_t); tp->kovtk = NULL; return(tp); }
#define NEVH
Programozás alapjai I. (C nyelv, gyakorlat)
© BME-IIT Sz.I.
2005.11.28.
- 49 -
Programozás alapjai I. (C nyelv, gyakorlat)
Implementáció - program
© BME-IIT Sz.I.
- 50 -
main(int argc, char *argv[]) { FILE *fp; t_poi kezdo; inp_t adat; 2005.11.28.
- 51 -
Programozás alapjai I. (C nyelv, gyakorlat)
2005.11.28.
© BME-IIT Sz.I.
2005.11.28.
- 52 -
Implementáció - program
if (argc != 2) { printf("Használat: %s input_file\n", argv[0]); exit(1); } if ((kezdo = inic()) == NULL) { printf(”Nincs elég memória\n"); exit(2); } if ((fp = fopen(argv[1], "r")) == NULL) { printf("Nem lehet megnyitni a %s állományt\n", argv[1]); exit(3); } © BME-IIT Sz.I.
2005.11.28.
typedef struct input_str { nev_t nev; int tk; float atl; } inp_t;
Implementáció - program
Programozás alapjai I. (C nyelv, gyakorlat)
© BME-IIT Sz.I.
Implementáció - program
typedef char nev_t[NEVH+1]; typedef struct hallg_str { nev_t nev; float atl; struct hallg_str *kovh; } hallg_t, *h_poi; typedef struct tankor_str { int tk; struct tankor_str *kovtk; struct hallg_str *kovh; } tankor_t, *t_poi; Programozás alapjai I. (C nyelv, gyakorlat)
40
while (beolvas(fp, &adat)) { if (fesul(kezdo, adat) == NULL) { printf("Elfogyott a memória\n"); break; } while-ból lép ki } kiir(kezdo); return(0); } - 53 -
Programozás alapjai I. (C nyelv, gyakorlat)
© BME-IIT Sz.I.
2005.11.28.
- 54 -
9
Próba (input)
Próba (output) Tankor: 1
Lancolt Jeno Elsos Pista Masodikos Joska Nagy Dodo Kiss Joco Major Anna Fellebeki Atmegel Oszkar Uszkar Gaz Geza Okos Toni
3 1 2 1 2 1 2 8 1 2
3.56 3.43 4.51 4.63 3.53 2.33 3.91 2.45 2.11 5.00
Tankor: 2
Tankor: 3 Tankor: 8
Programozás alapjai I. (C nyelv, gyakorlat)
© BME-IIT Sz.I.
2005.11.28.
- 55 -
Elsos Pista Gaz Geza Major Anna Nagy Dodo
3.43 2.11 2.33 4.63
Fellebeki Atmegel Kiss Joco Masodikos Joska Okos Toni
3.91 3.53 4.51 5.00
Lancolt Jeno
3.56
Oszkar Uszkar
2.45
Programozás alapjai I. (C nyelv, gyakorlat)
© BME-IIT Sz.I.
2005.11.28.
- 56 -
10