Programozás alapjai C nyelv 11. gyakorlat Szeberényi Imre BME IIT <szebi@iit.bme.hu> Programozás alapjai I. (C nyelv, gyakorlat) BME-IIT Sz.I. 2005.11.28. -1- Preprocesszor 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: 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 Programozás alapjai I. (C nyelv, gyakorlat) BME-IIT Sz.I. 2005.11.28. -2- Makrók (#define) #define azonosító token_sorozat #define N 52 /* elemek száma */ #define TRUE 1 /* igaz logikai konstans */ #define FALSE 0 int a[n]; for (i = 0; i < N; ) a[i++] = FALSE; int a[52]; for (i = 0; i < 52; ) a[i++] = 0; Makrók (2) #define azonosító token_sorozat #define azonosító ( azonosító_lista ) token_sorozat #define MAX(a, b) a > b? a : b int a = MAX(3, i); float f = MAX(3.12, f8); int a = 3 > i? 3 : i; float f = 3.12 > f8? 3.12 : f8; Tetszőleges típusú lehet, rugalmasabb mint a fv. Programozás alapjai I. (C nyelv, gyakorlat) BME-IIT Sz.I. 2005.11.28. -3- Programozás alapjai I. (C nyelv, gyakorlat) BME-IIT Sz.I. 2005.11.28. -4- Makrók (3) a = MAX(c & 7, d); 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!!! #define MAX(a, b) (a) > (b)? a : b a = (c & 7) > (d)? c & 7 : d; #include <fájlnév> #include fájlnév #include token_sorozat #include fájl #undef azonosító #undef MAX #undef TRUE 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. 2005.11.28. -6-
#if konstans_kifejezés... #elif konstans_kifejezés... #else... #endif Feltételes fordítás #if DEBUG... #else... #endif 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- #ifdef azonosító #else #endif Feltételes fordítás (2) #ifndef 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. Programozás alapjai I. (C nyelv, gyakorlat) BME-IIT Sz.I. 2005.11.28. -8- Állomány (Fájl) Állomány: Elvileg végtelen hosszúságú adatszerkezet rekord mező byte Tartalom szerint szöveg adat adatbázis Hozzáférés szerint soros véletlen Programozás alapjai I. (C nyelv, gyakorlat) BME-IIT Sz.I. 2005.11.28. -9- Állománykezelés 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 fopen, fscanf, fprintf, fgetc, fputc, ungetc, feof, fread, fwrite, fseek, ftell, fflush, fclose, remove, rename, tmpfile,... Programozás alapjai I. (C nyelv, gyakorlat) BME-IIT Sz.I. 2005.11.28. -10- FILE típus stdio.h-ban definiált struktúra, ami adminiszrációs területet, és a műveletek gyorsítására buffert tartalmaz 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. fopen() FILE *fopen(char *name, char *mod) megnyitás módja: r - csak olvasás w - írás és olvasás (létrehozza) a - hozzáfűzés (létrehozza) r+ - írás és olvasás w+ - írás és olvasás (létrehozza) a+ - 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. -11- Programozás alapjai I. (C nyelv, gyakorlat) BME-IIT Sz.I. 2005.11.28. -12-
fopen() példa #include <stdio.h> main() FILE *fp; char *nev = adat.txt ; int i; 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. -13- Feladat: mycopy Í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: 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. Programozás alapjai I. (C nyelv, gyakorlat) BME-IIT Sz.I. 2005.11.28. -14- A main paraméterei int main(int argc, char *argv[]) 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) Programozás alapjai I. (C nyelv, gyakorlat) BME-IIT Sz.I. 2005.11.28. -15- mycopy program #include <stdio.h> main(int argc, char *argv[]) program neve 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); Programozás alapjai I. (C nyelv, gyakorlat) BME-IIT Sz.I. 2005.11.28. -16- int függvény!! mycopy program (2) while ((ch = fgetc(fpin))!= EOF) fputc(ch, fpout); fclose(fpin); fclose(fpout); return (0); A main-ből való kilépes exit(n) hivást fog eredményezni. while (!feof(fpin) ch = fgetc(fpin); fputc(ch, fpout); feof() while (!feof(fpin) ch = fgetc(fpin); if (ch!= EOF) fputc(ch, fpout); 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. Programozás alapjai I. (C nyelv, gyakorlat) BME-IIT Sz.I. 2005.11.28. -17- Programozás alapjai I. (C nyelv, gyakorlat) BME-IIT Sz.I. 2005.11.28. -18-
stdin, stdout, stderr 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. Bináris és szöveg fájl Megnyitásnál t, vagy b (pl: rt, a+t ) 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) BME-IIT Sz.I. 2005.11.28. -19- Programozás alapjai I. (C nyelv, gyakorlat) BME-IIT Sz.I. 2005.11.28. -20- A probléma megoldása 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. fread(), frwite() Rekord szemlélet 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 Programozás alapjai I. (C nyelv, gyakorlat) BME-IIT Sz.I. 2005.11.28. -21- Programozás alapjai I. (C nyelv, gyakorlat) BME-IIT Sz.I. 2005.11.28. -22- Pozicionálás az állományban Író/olvasó pointer bájtot címez. int fseek(file *fp, long offset, int bazis); long ftell(file *fp); int fgetpos(file *fp, fpos_t *p); int fsetpos(file *fp, const fpos_t *p); Feladat 1 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 ismerjük nem ismerjük Válasszunk adatszerkezetet! Programozás alapjai I. (C nyelv, gyakorlat) BME-IIT Sz.I. 2005.11.28. -23- Programozás alapjai I. (C nyelv, gyakorlat) BME-IIT Sz.I. 2005.11.28. -24-
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- Programozás alapjai I. (C nyelv, gyakorlat) BME-IIT Sz.I. 2005.11.28. -26- Adatszerkezet typedef char nev_t[41]; typedef struct hallg_str nev_t nev; float atl; struct hallg_str *kov; hallg_t, *h_poi; h_poi tankorok[10]; Bonyolultabb adatszerkezet 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. Programozás alapjai I. (C nyelv, gyakorlat) BME-IIT Sz.I. 2005.11.28. -27- Programozás alapjai I. (C nyelv, gyakorlat) BME-IIT Sz.I. 2005.11.28. -28- Fésű adatszerkezet Feladat 1 (kiegészítés) FEJ LE FEJ LE FEJ LE LE 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: név 40 karakter tankörszám (egész) elválasztó szóköz átlag (valós szám) Írjuk a ki tankörönként a hallgatók névsorát és átlagát! Programozás alapjai I. (C nyelv, gyakorlat) BME-IIT Sz.I. 2005.11.28. -29- Programozás alapjai I. (C nyelv, gyakorlat) BME-IIT Sz.I. 2005.11.28. -30-
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; Vázlat (adatszerkezet) 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- Programozás alapjai I. (C nyelv, gyakorlat) BME-IIT Sz.I. 2005.11.28. -32- Vázlat (algoritmus) kezdo = inic() fp = fopen(argv[1], r ) while beolvas(fp, &adat) fesul(kezdo, adat) kiir(kezdo) 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. nincs 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- Programozás alapjai I. (C nyelv, gyakorlat) BME-IIT Sz.I. 2005.11.28. -34- Alprogram spec. - beolvas int beolvas(file *fp, 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. megnyitott állomány pointere pointer a kimenő adatra olvasott adat (pointer paraméter) függvényérték 1, ha sikerült az olvasás, egyébként 0 Alprogram spec. - fesul h_poi fesul(t_poi tp, inp_t r); 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. láncra mutató pointer felveendő adat a lánc épül függvényérték NULL, ha elfogyott a memória Programozás alapjai I. (C nyelv, gyakorlat) BME-IIT Sz.I. 2005.11.28. -35- Programozás alapjai I. (C nyelv, gyakorlat) BME-IIT Sz.I. 2005.11.28. -36-
Alprogram spec. - kiír void kiir(t_poi tp); A paraméterként kapott fésűs láncot végigjárja és kiírja az elemeket. láncra mutató pointer standard output Algoritmus - fesul tp = tankor_lanc(tp, tk) hallgato_lanc(tp->kovh, adat) Programozás alapjai I. (C nyelv, gyakorlat) BME-IIT Sz.I. 2005.11.28. -37- Programozás alapjai I. (C nyelv, gyakorlat) BME-IIT Sz.I. 2005.11.28. -38- Alprogram spec. - tankor_lancol t_poi tankor_lanc(t_poi tp, int tk); 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. láncra mutató pointer a keresett tankör száma függvényérték: a lánc megfelelő elemére mutató pointer. NULL, ha elfogyott a memória Alprogram sp. - hallgato_lancol h_poi hallgato_lanc(h_poi hp, inp_t r); 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. láncra mutató pointer a felveendő adat függvényérték NULL, ha elfogyott a memória Programozás alapjai I. (C nyelv, gyakorlat) BME-IIT Sz.I. 2005.11.28. -39- Programozás alapjai I. (C nyelv, gyakorlat) BME-IIT Sz.I. 2005.11.28. -40- A fésű Implementáció - tankor_lancol TK TK H TK TK H TK TK H TK H 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): NEV,ATL H H H NEV,ATL H H pointer változó tárolandó objektum típusa #define new(p, obj) \ if ((p = malloc(sizeof(obj))) == NULL) return(null) Programozás alapjai I. (C nyelv, gyakorlat) BME-IIT Sz.I. 2005.11.28. -41- Programozás alapjai I. (C nyelv, gyakorlat) BME-IIT Sz.I. 2005.11.28. -42-
Implementáció - tankor_lancol t_poi tankor_lanc(t_poi tp, int tk) t_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); Programozás alapjai I. (C nyelv, gyakorlat) BME-IIT Sz.I. 2005.11.28. -43- Implementáció - hallgato_lancol h_poi hallgato_lanc(h_poi hp, inp_t r) h_poi uj; stringek összehasonlítása 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. -44- Karakterfüzérek (stringek) 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). strcmp, strcpy, strncpy, strcat, strncat, strchr, strstr, strlen, strtok, stb. Implementáció - fesul 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)); Programozás alapjai I. (C nyelv, gyakorlat) BME-IIT Sz.I. 2005.11.28. -45- Programozás alapjai I. (C nyelv, gyakorlat) BME-IIT Sz.I. 2005.11.28. -46- void kiir(t_poi tp) while (tp->kovtk) h_poi hp; Implementáció - kiir a ciklusban érvényes 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) BME-IIT Sz.I. 2005.11.28. -47- Implementáció - beolvas int beolvas(file *fp, inp_t *r) char buf[nevh+20]; if (fgets(buf, sizeof(buf), fp) == NULL) return(0); strncpy(r->nev, buf, NEVH); lezárás r->nev[nevh] = 0; sscanf(&buf[nevh], %d%f, &r->tk, &r->atl); return(1); teljes sor beolvasása beolvasás után könyebben mazsolázunk benne Programozás alapjai I. (C nyelv, gyakorlat) BME-IIT Sz.I. 2005.11.28. -48-
Implementáció - inic Implementáció - program t_poi inic(void) t_poi tp; new(tp, tankor_t); tp->kovtk = NULL; return(tp); nincs paramétere #include <stdio.h> #include <stdlib.h> #include <string.h> #define new(p, obj) \ if ((p = malloc(sizeof(obj))) == NULL) \ return(null) #define NEVH 40 Programozás alapjai I. (C nyelv, gyakorlat) BME-IIT Sz.I. 2005.11.28. -49- Programozás alapjai I. (C nyelv, gyakorlat) BME-IIT Sz.I. 2005.11.28. -50- 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) BME-IIT Sz.I. 2005.11.28. -51- Implementáció - program typedef struct input_str nev_t nev; int tk; float atl; inp_t; main(int argc, char *argv[]) FILE *fp; t_poi kezdo; inp_t adat; Programozás alapjai I. (C nyelv, gyakorlat) 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); Programozás alapjai I. (C nyelv, gyakorlat) BME-IIT Sz.I. 2005.11.28. -53- Implementáció - program 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); Programozás alapjai I. (C nyelv, gyakorlat) BME-IIT Sz.I. 2005.11.28. -54-
Próba (input) Próba (output) Lancolt Jeno 3 3.56 Elsos Pista 1 3.43 Masodikos Joska 2 4.51 Nagy Dodo 1 4.63 Kiss Joco 2 3.53 Major Anna 1 2.33 Fellebeki Atmegel 2 3.91 Oszkar Uszkar 8 2.45 Gaz Geza 1 2.11 Okos Toni 2 5.00 Tankor: 1 Elsos Pista 3.43 Gaz Geza 2.11 Major Anna 2.33 Nagy Dodo 4.63 Tankor: 2 Fellebeki Atmegel 3.91 Kiss Joco 3.53 Masodikos Joska 4.51 Okos Toni 5.00 Tankor: 3 Lancolt Jeno 3.56 Tankor: 8 Oszkar Uszkar 2.45 Programozás alapjai I. (C nyelv, gyakorlat) BME-IIT Sz.I. 2005.11.28. -55- Programozás alapjai I. (C nyelv, gyakorlat) BME-IIT Sz.I. 2005.11.28. -56-