Programozás alapjai C nyelv 8. gyakorlat Szeberényi mre BME T <szebi@iit.bme.hu> Programozás alapjai. (C nyelv, gyakorlat) BME-T Sz.. 2005.11.07. -1- Mutatók és címek (ism.) Minden változó és függvény memóriában levő helye (címe) képezhető. (pl: &valtozo) Ez a cím ún. pointerben vagy mutatóban tárolható. A pointer egy olyan típus, amelynek az értékkészlete cím, és mindig egy meghatározott típusú objektumra mutat. int i, *ip; float f, *fp; int-re mutató pointer float-ra mutató pointer ip = &i; fp = &f; Programozás alapjai. (C nyelv, gyakorlat) BME-T Sz.. 2005.11.07. -2- ndirekció (ism) Néhány dolog érthetőbb (ism.) int *ip; ip = &i *ip = 13; 13 i cime Memória float f; float *fp; Scanf-nél az & jelentése? Miért nincs tömbök között értékadás. (t1 = t2)? Tömb, mint fv. paraméter. Miért nem hibás az if ( alma == alma ) utasítás, de mégsem működik? Miért hibás a... case alma : utasítás? Programozás alapjai. (C nyelv, gyakorlat) BME-T Sz.. 2005.11.07. -3- Programozás alapjai. (C nyelv, gyakorlat) BME-T Sz.. 2005.11.07. -4- Dinamikus adatszerkezet Az adatok száma nem ismert előre. Nem tudunk vagy nem akarunk feleslegesen helyet foglalni az adatoknak. A feladat dinamikusan változhat. Változók a memóriában float f; int *ip; float *fp; Halom (heap) Programozás alapjai. (C nyelv, gyakorlat) BME-T Sz.. 2005.11.07. -5- Programozás alapjai. (C nyelv, gyakorlat) BME-T Sz.. 2005.11.07. -6-
malloc() hatása float f; Allokált terület használata float f; int *ip; int *ip; float *fp; cím float *fp; cím fp = malloc(sizeof(float)); fp = malloc(sizeof(float)); 3.14 *fp = 3.14 Programozás alapjai. (C nyelv, gyakorlat) BME-T Sz.. 2005.11.07. -7- Programozás alapjai. (C nyelv, gyakorlat) BME-T Sz.. 2005.11.07. -8- malloc() standard függvény <stdlib.h> void *malloc(size_t size); void free(void *p); A malloc lefoglal a dinamikus területen egy, a paramétereként kapott méretű területet. Visszaadja a lefoglalt terület kezdőcímét, hiba eseten -t. Afreefelszabadítja a lefoglalt területet. Nincs ellenőrzés! Programozás alapjai. (C nyelv, gyakorlat) BME-T Sz.. 2005.11.07. -9- Ujabb malloc float f; int *ip; float *fp; cím fp = malloc(sizeof(float)); 3.14 Programozás alapjai. (C nyelv, gyakorlat) BME-T Sz.. 2005.11.07. -10- Elveszett!!! Van megoldás? Minden dinamikus változóhoz saját pointer kell, egyébként nem érhető el az adat! Mégis kell tudni előre az adatok számát? Hol van itt az ígért rugalmasság? Miért nem tárolhatom a pointert együtt az adattal? LÁNCOLT szerkezet! Programozás alapjai. (C nyelv, gyakorlat) BME-T Sz.. 2005.11.07. -11- Önhivatkozó struktúra struct elem struct elem *kov; e, *p; Miért kell a zárójel? e.i = 8; p = &e; (*p).i = ; p->i = ; Szemléletesebb Programozás alapjai. (C nyelv, gyakorlat) BME-T Sz.. 2005.11.07. --
Lánc kialakítása Láncolt adatszerkezet typedef struct elem struct elem *kov; elem_t; elem_t *kezd; kezd = malloc(sizeof(elem_t)); kezd->i = ; kezd->kov = malloc(sizeof(elem_t)); 88 kezd->kov->i = 88; Programozás alapjai. (C nyelv, gyakorlat) BME-T Sz.. 2005.11.07. -13- Programozás alapjai. (C nyelv, gyakorlat) BME-T Sz.. 2005.11.07. -14- Duplán láncolt adatszerkezet Rendezve építés 1 2 15 32 634 2 NL Programozás alapjai. (C nyelv, gyakorlat) BME-T Sz.. 2005.11.07. -15-8 Programozás alapjai. (C nyelv, gyakorlat) BME-T Sz.. 2005.11.07. -16- Feladat 1 Vázlat (adatszerkezet) Olvassunk be a standard inputról fájl végéig egész számokat, és írjuk ki azokat fordított sorrendben! A nem számjegy karaktereket tekintsük elválasztónak és dobjuk el! Tárolnunk kell, mert az utolsó adatot kell először kiírni. Mivel az input adatok számát előre nem ismerjük, dinamikus adatszerkezetet kell használnunk! typedef struct lanc_str struct lanc_str *kov; lanc_elem, *lanc_poi; struktúra típus pointer típus Programozás alapjai. (C nyelv, gyakorlat) BME-T Sz.. 2005.11.07. -17- Programozás alapjai. (C nyelv, gyakorlat) BME-T Sz.. 2005.11.07. -18-
Vázlat (algoritmus) Vázlat (algoritmus) kezdo = while olvas(i) kezdo = lancol(kezdo, i) kiir(kezdo) (olvas(i) beolvassa a következő egész értéket és hamis fv.értékkel jelzi, ha fájl vége volt. A nem számjegy karaktereket elválasztónak tekinti és eldobja.) Programozás alapjai. (C nyelv, gyakorlat) BME-T Sz.. 2005.11.07. -19- Programozás alapjai. (C nyelv, gyakorlat) BME-T Sz.. 2005.11.07. -20- Függvény spec. - beolvas int olvas(int *i); nt értékű függvény, beolvassa a következő egészet a standard inputról. A nem számjegy karaktereket eldobja. bemenet: standard input kimenet: függvényérték: hamis (0), ha fájl vége volt az olvasott egész (változó paraméter hiányában címet kell átadni) Programozás alapjai. (C nyelv, gyakorlat) BME-T Sz.. 2005.11.07. -21- Függvény spec. - lancol lanc_poi lancol(lanc_poi p, int i); A paraméterként kapott lánc elejére felvesz egy új elemet, amelybe az integer paraméterként kapott értéket teszi. bemenet: lánc elejére mutató pointer., ha üres felveendő érték kimenet: függvényérték: lánc elejére mutató pointer,, ha elfogyott a memória Programozás alapjai. (C nyelv, gyakorlat) BME-T Sz.. 2005.11.07. -22- Függvény spec. - kiir void kiir(lanc_poi p); Void függvény (eljárás) a paraméterként kapott láncot kiírja bemenet: lánc elejére mutató pointer., ha üres kimenet: standard output Programozás alapjai. (C nyelv, gyakorlat) BME-T Sz.. 2005.11.07. -23- mplementáció - lancol lanc_poi lancol(lanc_poi p, int i) lanc_poi uj; if (uj = malloc(sizeof(lanc_elem))) uj->i = i; /* érték beírása */ uj->kov = p; /* befűz az elejére */ return(uj); Programozás alapjai. (C nyelv, gyakorlat) BME-T Sz.. 2005.11.07. -24-
mplementáció - kiir void kiir(lanc_poi p) while (p!= ) printf( %6d, p->i); /* érték kiírása */ p = p->kov; /* következőre */ mplementáció - beolvas int olvas(int *i) int r ; while ((r = scanf( %d, i)) == 0) scanf( %*c ); return(r!= EOF); csillag jelentése a formátumlistán Programozás alapjai. (C nyelv, gyakorlat) BME-T Sz.. 2005.11.07. -- Programozás alapjai. (C nyelv, gyakorlat) BME-T Sz.. 2005.11.07. -26- mplementáció - program #include <stdio.h> #include <stdlib.h> typedef struct lanc_str struct lanc_str *kov; lanc_elem, *lanc_poi; alprogramok mplementáció - program main() int n; lanc_poi kezdo = ; while (olvas(&n)) kezdo = lancol(kezdo, n); kiir(kezdo); Meg kellene vizsgálni, hogy -e! Programozás alapjai. (C nyelv, gyakorlat) BME-T Sz.. 2005.11.07. -27- Programozás alapjai. (C nyelv, gyakorlat) BME-T Sz.. 2005.11.07. -28- Feladat 2 Olvassunk be a standard inputról file végéig egész számokat, és írjuk ki azokat nagyság szerint rendezve! (Az előző feladathoz hasonlóan a nem számjegy karaktereket tekintsük elválasztónak és dobjuk el!) Tárolnunk kell a rendezés miatt. Mivel az input adatok számát előre nem ismerjük, dinamikus adatszerkezetet kell használnunk! Programozás alapjai. (C nyelv, gyakorlat) BME-T Sz.. 2005.11.07. -29- Megoldási alternatívák Láncot építünk és utólag rendezzük. túl sok pointert kell egyszerre kezelni: 23 15 Nem okos megoldás! Programozás alapjai. (C nyelv, gyakorlat) BME-T Sz.. 2005.11.07. -30-
Megoldási alternatívák Vázlat (algoritmus) Rendezve építjük a láncot kezdo = while olvas(i) kezdo = beszur(kezdo, i) kiir(kezdo) 15 Programozás alapjai. (C nyelv, gyakorlat) BME-T Sz.. 2005.11.07. -31- Programozás alapjai. (C nyelv, gyakorlat) BME-T Sz.. 2005.11.07. -32- Alprogram spec. - beszur lanc_poi beszur(lanc_poi kp, int i); A paraméterként kapott láncba beszúr egy új elemet, amelybe az integer paraméterként kapott értéket teszi. bemenet: lánc elejére mutató pointer., ha üres felveendő érték kimenet: függvényérték: lánc elejére mutató pointer,, ha elfogyott a memória Programozás alapjai. (C nyelv, gyakorlat) BME-T Sz.. 2005.11.07. -33- Beszúrás a láncba Három különböző eset van: Új elem a lánc belsejébe kerül. Új elem a lánc elejére kerül. Új elem a lánc végére kerül. Programozás alapjai. (C nyelv, gyakorlat) BME-T Sz.. 2005.11.07. -34- Beszúrás a lánc belsejébe Beszúrás a lánc elejére 15 9 Programozás alapjai. (C nyelv, gyakorlat) BME-T Sz.. 2005.11.07. -- Programozás alapjai. (C nyelv, gyakorlat) BME-T Sz.. 2005.11.07. -36-
Beszúrás a lánc végére A megfelelő hely keresése Módosítani kell! 151 p = kezd; while (p!= && p->i < i) p = p->kov; 34 Programozás alapjai. (C nyelv, gyakorlat) BME-T Sz.. 2005.11.07. -37- Programozás alapjai. (C nyelv, gyakorlat) BME-T Sz.. 2005.11.07. -38- Lemaradó pointer pl = kezd; p = kezd; while (p!= && p->i < i) pl = p; p = p->kov; 34 Programozás alapjai. (C nyelv, gyakorlat) BME-T Sz.. 2005.11.07. -39- mplementáció - beszúr lanc_poi beszur(lanc_poi kp, int i) lanc_poi uj, p, pl; uj = malloc(sizeof(lanc_elem)); if (uj == ) return(); uj->i = i; p = kp; pl = p; while (p!= && p->i < i) pl = p; /* lemaradó poi. */ p = p->kov; /* futó poi. */ Programozás alapjai. (C nyelv, gyakorlat) BME-T Sz.. 2005.11.07. -40- mplementáció - beszúr if (p == kp) kp = uj; /* elejére kell */ else pl->kov = uj; /* nem az elejére */ uj->kov = p; /* új mögötti rész */ return(kp); mplementáció - program alprogramok main() Precedencia! int n; lanc_poi kezdo = ; while (olvas(&n)) if ((kezdo = beszur(kezdo, n)) == ) printf( Elfogyott a memória\n), exit(1); kiir(kezdo); Vessző op.! Programozás alapjai. (C nyelv, gyakorlat) BME-T Sz.. 2005.11.07. -- Programozás alapjai. (C nyelv, gyakorlat) BME-T Sz.. 2005.11.07. -42-
Miért kell figyelni az elejét? Láncolt lista strázsával Külön kezelést igényel, mert a kezdo nem dinamikus változó, de a többi pointer igen, azaz: kezdo = valami, de a többi esetben p->kov = valami Ötlet: Tegyünk a lánc elejére egy kamu elemet!????? Programozás alapjai. (C nyelv, gyakorlat) BME-T Sz.. 2005.11.07. -43- Programozás alapjai. (C nyelv, gyakorlat) BME-T Sz.. 2005.11.07. -44- mplementáció - beszúr2 lanc_poi beszur2(lanc_poi kp, int i) lanc_poi uj, p, pl; Elöl van strázsa! uj = malloc(sizeof(lanc_elem)); if (uj == ) return(); uj->i = i; pl = kp; p = kp->kov; while (p!= && p->i < i) pl = p; p = p->kov; Egyszerűbb! pl->kov = uj; uj->kov = p; return(uj); Programozás alapjai. (C nyelv, gyakorlat) BME-T Sz.. 2005.11.07. -45- mplementáció - kiir2 void kiir2(lanc_poi p) p = p->kov; /* strázsa átlépése */ while (p!= ) printf( %6d, p->i); /* érték kiírása */ p = p->kov; /* következőre */ Programozás alapjai. (C nyelv, gyakorlat) BME-T Sz.. 2005.11.07. -46- mplementáció - program2 alprogramok main() int n; lanc_poi kezdo = malloc(sizeof(lanc_elem)); kezdo->kov = ; /* strázsa létrehozása */ while (olvas(&n)) kezdo nem változik if (beszur2(kezdo, n) == ) printf( Elfogyott a memória\n), exit(1); kiir2(kezdo); Programozás alapjai. (C nyelv, gyakorlat) BME-T Sz.. 2005.11.07. -47- Miért kell a lemaradó pointer? A megtalált elem elé kell beszúrni. Ötlet: Szúrjuk be mögé az új elemet, és abba tegyük át a régi elemet! Ezután a régi elembe írhatjuk az új értéket! Programozás alapjai. (C nyelv, gyakorlat) BME-T Sz.. 2005.11.07. -48-
Hova kell strázsa? Beszúrás másolással Az elejére sohasem szúrunk be, mert ha az első elem elé kellene, akkor is az elem mögé vesszük fel az új struktúrát. Az elejére ezért nem kell strázsa. Csak egy pointert akarunk használni, és nem engedjük meg, hogy az értéket vegyen fel. A lánc végén ezért van strázsa. 15 beszúrása 15 ne fussunk le a láncról???? Programozás alapjai. (C nyelv, gyakorlat) BME-T Sz.. 2005.11.07. -49- Programozás alapjai. (C nyelv, gyakorlat) BME-T Sz.. 2005.11.07. -50- mplementáció - beszúr3 lanc_poi beszur3(lanc_poi p, int i) lanc_poi uj; uj = malloc(sizeof(lanc_elem)); if (uj == ) return(); while (p->kov!= && p->i < i) p = p->kov; *uj = *p; /* teljes struktúrát másolja */ p->i = i; /* beír a régibe */ p->kov = uj; /* beláncolja az újat */ return(p); strázsa hátul van Programozás alapjai. (C nyelv, gyakorlat) BME-T Sz.. 2005.11.07. -51- mplementáció - kiir3 void kiir3(lanc_poi p) while (p->kov!= ) /* hátul van a str. */ printf( %6d, p->i); /* érték kiírása */ p = p->kov; /* következőre */ Programozás alapjai. (C nyelv, gyakorlat) BME-T Sz.. 2005.11.07. -52- mplementáció - program3 alprogramok main() int n; lanc_poi kezdo = malloc(sizeof(lanc_elem)); kezdo->kov = ; /* strázsa létrehozása */ while (olvas(&n)) kezdo nem változik if (beszur3(kezdo, n) == ) printf( Elfogyott a memória\n), exit(1); kiir3(kezdo); a str. miatt másik kiíró kell Programozás alapjai. (C nyelv, gyakorlat) BME-T Sz.. 2005.11.07. -53- Mikor használható ez a trükk? Ha az adat nem nagy, ugyanis minden beszúráskor a teljes struktúrát lemásoljuk. Nagy méretű adat esetén (>2-3Kb) ez számottevő idő lehet. Programozás alapjai. (C nyelv, gyakorlat) BME-T Sz.. 2005.11.07. -54-
Összefoglalás Dinamikus területen tetszőleges számú adat hozható létre (malloc). Minden ilyen adat egy pointeren keresztül érhető el. Láncolt adatszerkezet ötlete a következő adat pointerét az előző adat mellett tároljuk Láncolt szerkezet tulajdonságai Előnyök: elvileg tetszőlegesen sok adat tárolható nem kell előre meghatározni az adatok számát rendezés egyszerű, többnyire az építés már rendezetten történik az adatkapcsolatok jól ábrázolhatók Hátrányok: az adat mellett még egy pointert is tárolni kell nem érhető el tetszőleges sorrendben az adat könnyű elszakítani a láncot (hibás kezelés) Programozás alapjai. (C nyelv, gyakorlat) BME-T Sz.. 2005.11.07. -55- Programozás alapjai. (C nyelv, gyakorlat) BME-T Sz.. 2005.11.07. -56-