Programozás 5. Dr. Iványi Péter
1
Struktúra • Véges számú különböző típusú, logikailag összetartozó változó együttese, amelyeket az egyszerű kezelhetőség érdekében gyűjtünk össze. • Rekord-nak felel meg struct <struktura nev> {
; ... };
2
Struktúra deklarálása, definiálása struct { char int char };
szemely nev[100]; kora; cim[100];
int main() { struct szemely en; en.kora = 18; /* hivatkozas egy struktura elemre */ strcpy(en.nev, ”Kovacs Istvan”); ...
3
Egymásba ágyazás 1. struct datum { int ev; int honap; int nap; }; struct szemely { char nev[100]; struct datum szuletesi_ido; };
4
Egymásba ágyazás 2. int main() { struct szemely sz1; sz1.szuletesi_ido.ev = 1950; sz1.szuletesi_ido.honap = 1; sz1.szuletesi_ido.nap = 12; strcpy(sz1.nev, ”Kovacs Istvan”); ...
5
Struktúra tömb struct szemely { char nev[100]; int kora; double fizetes; }; int main() { struct szemely emberek[10]; /* 10 db deklarálása */ emberek[1].kora = 21; strcpy(emberek[1].nev, ”Kovacs Istvan”);
6
Mutatók • Tömbök és mutatók szorosan összetartoznak. • Mutató: egy másik objektum, vátozó címét tárolja típus
*név;
Példa: int *p;
Egész típusú változóra mutató pointer. 7
Példa 1 { int a=1; int b=2; int c=3; int *p; int *q;
a
1
xxx
p
b
2
xxx
q
c
3
8
Példa 2 { int a=1; int b=2; int c=3; int *p; int *q;
a
1
p
b
2
q
c
3
p=&a; q=&b ... 9
Példa 3 ... c = *p; ...
a
1
p
b
2
q
c
1
10
Példa 4 ... p = q; ...
a
1
p
b
2
q
c
1
11
Példa 5 ... *p = 13; ...
a
1
p
b
13
q
c
1
12
Példa 6 { int *p; /* HIBÁS */ *p = 45;
xxx
p
sehova sem mutat
13
Példa 7 { int *p, q; /* p : egy mutató */ /* q : NEM mutató, csak egész szám */
14
NULL • Speciális eset, amikor pointer 0 (nulla) értéket tartalmaz. • Ez a NULL pointer • Azt jelenti, hogy nem mutat érvényes adatra • stdio.h tárolja a NULL definícióját
15
Függvények és mutatók • Érték szerinti paraméter átadás – Az érték bemásolódik az argumentumba – Ha meg akarjuk változtatni az eredeti objektumot, csak a return-el tehetjük meg – Több változó esetén nem jó
• Cím szerinti paraméter átadás is lehetséges
16
Függvények és mutatók #include <stdio.h> int csere(int *a, int *b) { int c; c = *a; *a = *b; *b = c; } int main() { int x = 1; int y = 2; csere(&x, &y); printf(”%d-%d”, x, y); return 0; }
a
b
x
y
1
2
2-1 17
Függvények és mutatók #include <stdio.h> /* void csere(int *a) */ void csere(int a[]) /* ez is lehet vektor jeloles */ { int i; for(i = 0; i < 5; i++) printf(”%d ”, a[i]); } int main() { int a[5]; nyomtat(a); return 0; } 18
Tömbök és mutatók • Egy egydimenziós vektor neve megegyezik a vektor 0-dik elemének a címével, tehát a vektor kezdőcímével : vektor == &(vektor[0]);
0
1
2 …
vektor
19
Tömbök és mutatók • Példa: int v[10]; int *pv; pv = v;
• Van egy különbség, a tömb neve konstans nem változtatható, a mutató megváltoztatható: Érvényes Érvénytelen pv++;
v++; 20
Címaritmetika • Egy cím + egész kifejezésnek az az alapvető tulajdonsága, hogy mindig az illető cím típusának megfelelően a következő elemre mutató címet állítja elő. &(x[2]) == x+2; /* 3. elem címe */ x[2] == *(x+2); /* 3. elem értéke */
21
Címaritmetika • Ha két pointer ugyanannak a tömbnek az elemeire mutat, akkor értelmezettek a <, >, ==, != stb. relációs műveletek. • Ha két pointer ugyanannak a tömbnek az elemeire mutat, ( pl.: a és b ), akkor a - b az a és b közötti elemek darabszámát adja. • Pointerhez hozzáadhatunk, ill. levonhatunk egész számot. • Tilos : Pointerek szorzása, osztása, shiftelése, maszkolása, ill. float vagy double mennyiségek pointerekhez való hozzáadása vagy kivonása.
22
Memória kezelés • Dinamikus memória kezelés • Például: – Nem tudjuk előre mekkora vektor kell – Bemeneti adattól függ a vektor mérete
23
Memória foglalás void
*malloc( size_t
size );
– Byte-ban kell megadni a méretet – Ha nem sikerül NULL-t ad vissza – Cast-olni kell az adott típusra
Példa: void fvg(int n) { int *p p = (int *)malloc(n * sizeof(int)); ... 24
Memória foglalás void
– – – –
*calloc(size_t
nitems , size_t size );
Byte-ban kell megadni a méretet Ha nem sikerül NULL-t ad vissza Cast-olni kell az adott típusra Nullázza a területet
Példa: void fvg(int n) { int *p; p = (int *)calloc(n, sizeof(int)); ... 25
Memória felszabadítás void free( void *block );
• Felszabadítja a területet, de a területre mutató pointereket nem módosítja, pedig azok is érvénytelenek lesznek!!!
26
Példa /* nagyban hasonlít a statikus tömbökhöz */ #include <stdio.h> int main() { int n, i; int *p; printf(”Elemek szama”); scanf(”%d”, &n); p = (int *)calloc(n, sizeof(int)); for(i = 0; i < n i++) { scanf(”%d”, &(p[i])); } free(p); return 0; } 27
Többdimenziós tömb • Például: 3x3 matrix #include <stdio.h> int main() { double m[3][3]; int i, j; for(i = 0; i < 3; i++) { for(j = 0; j < 3 ; j++) { m[i][j] = i+j; } } return 0; }
0 1 2
0
1
2
0 1 2
1 2 3
2 3 4 28
Inicializálás 1. #include <stdio.h> int main() { double m[3][3] = {0, 1, 2, 3, 4, 5, 6, 7, 8}; double m[3][3] = { {0, 1, 2}, {3, 4, 5}, {6, 7, 8} }; ...
29
Inicializálás 2. char *honap_neve(int n) { static char *nevek[] = { ”ervenytelen”, ”januar”, ”februar”, ”marcius”, ”aprilis”, ”majus”, ”junius”, ”julius”, ”augusztus”, ”szeptember”, ”oktober”, ”november”, ”december”}; return ((n < 1 || n > 12) ? nev[0] : nev[n]); }
30
Inicializálás 3. char *honap_neve(int n) { static char *nevek[] = { {’e’, ’r’, ’v’, ’e’, ’n’, ’y’, ’t’, ’e’, ’l’, ’e’, ’n’}, {’j’, ’a’, ’n’, ’u’, ’a’, ’r’},
...
31
Dinamikus tömbök 1.
32
Dinamikus tömbök 1. /* két dimenziós tömb vagy mátrix, sorok darabokban */ int **alloc_tomb(int sor, int oszlop) { int **p; int j; p = (int **)calloc(sor, sizeof(int *)); for(j = 0; j < sor; j++) { p[j] = (int *)calloc(oszlop, sizeof(int)); } return p; }
33
Dinamikus tömbök 2.
34
Dinamikus tömbök 2. /* két dimenziós tömb vagy mátrix, sorok folytatólagosan */ int **alloc_tomb(int sor, int oszlop) { int **p; int j; p = (int **)calloc(sor, sizeof(int *)); p[0] = (int *)calloc(sor * oszlop, sizeof(int)); for(j = 1; j < sor; j++) { p[j] = p[j-1]+oszlop; } return p; } 35
Struktúrák és függvények • A C-ben a függvények csak struktúrára mutató pointereket kaphatnak bemenő paraméterként, és csak struktúrára mutató pointereket adhatnak vissza!!!! • Struktúra címe: & • Hozzáférés struktúra pointer eleméhez: ->
36
Struktúrák és függvények struct szemely { char nev[100]; int kora; }; void sajat_adat(struct szemely *p) { p->kora = 30; strcpy(p->nev, ”Kovacs Istvan”); } int main() { struct szemely en; struct szemely *pen; pen = &en; sajat_adat(pen); return 0; } 37
Dinamikus struktúra tömb 1 struct szemely { char nev[100]; int kora; double fizetes; }; int main() { struct szemely *emberek; /* deklarálás*/ emberek = (struct szemely *)calloc(10, sizeof(struct emberek)); strcpy(emberek[0].nev, ”Kovacs Istvan”); emberek[0].kora = 10; ...
38
Dinamikus struktúra tömb 2 struct szemely { char nev[100]; int kora; double fizetes; }; int main() { int i; struct szemely **emberek; emberek = (struct szemely **)calloc(10, sizeof(struct emberek *)); for(i = 0; i < 10; i++) { emberek[i] = (struct szemely *)calloc(1, sizeof(struct emberek)); } strcpy(emberek[0]->nev, ”Kovacs Istvan”); emberek[0]->kora = 10; ...
39
Típus definíció • Új típus is definiálható typedef regi_tipus uj_tipus;
• A típusdefiníció különösen hasznos akkor, ha többféle struktúrát használunk a programunkban. Szemléletesebb és könnyebb megérteni egy struktúra típus nevet, vagy egy pointer típus-nevet mint egy bonyolult struktúra nevét, vagy egy arra mutató pointer nevét. A típusnév definíció használatának másik oka a gépfüggőség kivédése. Ha a programunkban gépfüggő adattípusokat használunk, akkor egy másik gépre történő áthelyezésnél elég csupán a typedef-eket módosítani. 40
Típus definíció typedef struct _szemely { char nev[100]; int kora; char cim[100]; } /* eredeti típus */ szemely;
int main() { szemely en; en.kora = 18; /* hivatkozas egy struktura elemre */ strcpy(en.nev, ”Kovacs Istvan”); ... 41
Típus definíció typedef unsigned int BOOL; #define IGAZ 1 #define HAMIS 0 int main() { BOOL logikai; logikai = IGAZ; if(logikai) { printf(”Igaz”); } 42
Elolvasni, megtanulni • Kernighan-Ritchie: A C programozási nyelv – 5. Fejezet, kivéve 5.10, 5.11, 5.12 – 6. Fejezet, kivéve 6.8, 6.9
• Benkő Tiborné: Programozzunk C nyelven! – Teljes 3.6. Fejezet – 3.7. Fejezet, kivéve 3.7.6, 3.7.7 – 3.8.5, 3.8.6 Fejezet
43