Új dinamikus változó létesítése
p=malloc(sizeof(E));
A malloc(S) függvény lefoglal egy S méretű memóriaterületet a program számára. A sizeof(E) megadja, hogy egy E típusú változó mekkora helyet igényel a memóriában. A malloc(sizeof(E)) hatására tehát létrejön egy új E típusú érték tárolására (is) alkalmas változó, és ez a változó lesz a p értéke.
Pointer dereferencia
*p
A * művelet segítségével érhetjük el a p értékét vagyis a dinamikus változót. A *p változóhivatkozás a p értékére, vagyis a dinamikus változóra hivatkozik, tehát a *p értéke a dinamikus változó értéke lesz.
Dinamikus változó törlése
free(p);
A művelet hatására a p-hez tartozó memóriaterület felszabadul ezáltal a dinamikus változó megszűnik. A művelet végrehajtása után a p pointerhez nem tartozik érvényes változó, ezért a *p változóhivatkozás végrehajtása jobb esetben azonnali futási hibát eredményez. (Rosszabb esetben pedig olyan lappangó hibát, aminek az eredménye a program egy teljesen más pontján jelenik meg.)
A címképző művelet
p = &i;
A művelet meghatározza egy változóhoz tartozó memória mező címét. Ha egy p pointer típusú változó értéke az i változóhoz tartozó memória címe, akkor azt mondjuk, hogy a p i-re mutat. Ez a referencia szerinti értékátadás.
P: Nézzük meg, mi a különbség p, q, illetve *p és *q értéke között. ============================================================================== #include <stdio.h> #include <stdlib.h> int main() { int *p, *q; p = malloc(sizeof(int)); q = malloc(sizeof(int)); *p = 3; *q = 3; printf("p es q %s\n", p == q ? "megegyezik" : "nem egyezik meg"); printf("*p == %d, *q == %d\n", *p, *q); *p = 4; printf("*p == %d, *q == %d\n", *p, *q); free(p); p = q; printf("p es q %s\n", p == q ? "megegyezik" : "nem egyezik meg"); printf("*p == %d, *q == %d\n", *p, *q); *p = 4; printf("*p == %d, *q == %d\n", *p, *q); free(p); return 0; }
P: Futtassuk le a következő programot, és értelmezzük! Melyik érték melyik értékkel egyenlő, és miért ? ============================================================================== #include <stdio.h> int main() { int a = 10; int *pa; pa = &a; printf("%d %#x\n", a, (int)pa); printf("%#x %#x\n", (int)&a, (int)&pa); printf("%d\n", *pa); return 0; }
F: Írj egy csere() függvényt, ami megcseréli két int típusú változó értékét. ============================================================================== #include <stdio.h> void csere(int *x, int *y) { int tmp; tmp = *x; *x = *y; *y = tmp; } int main() { int x = 3, y = 4; printf("A fuggveny elott: x = %d, y = %d\n", x, y); csere(&x,&y); printf("A fuggveny utan: x = %d, y = %d\n", x, y); return 0; }
F: Deklarálj egy 20 elemű int tömböt, majd töltsd fel értékekkel az inputról. Deklarálj egy pointert, és a beolvasást azon keresztül valósítsd meg. ============================================================================== #include <stdio.h> #define N 20 int main() { int t[N], *p, i; for(i=0; i<N; i++) { p=&(t[i]); scanf("%d", p); } for(i=0; i<N; i++) { printf("%d\n", t[i]); } return 0; }
F: Először olvasd be a tömb méretét, és foglalj neki dinamikusan helyet! ============================================================================== #include <stdio.h> #include <stdlib.h> int main() { int *t, *p, i, N; scanf("%d", &N); t=(int*)malloc(N*sizeof(int)); for(i=0; i<N; i++) { p=&(t[i]); scanf("%d", p); } for(i=0; i<N; i++) { printf("%d\n", t[i]); } free(t); return 0; }
F: Olvass be 5 darab maximum 99 karakter hosszú szót úgy, hogy mindegyiknek pontosan annyi helyet foglalsz, amennyi kell! A sztringeket írasd ki, majd szabadítsd fel a lefoglalt területet! ============================================================================== #include <stdio.h> #include <stdlib.h> #include <string.h> int main() { char buff[100]; char *ptr_tomb[5]; int i; for(i=0; i<5; i++) { scanf("%s", buff); ptr_tomb[i] = (char*)malloc(strlen(buff)+1); strcpy(ptr_tomb[i], buff); } for(i=0; i<5; i++) { puts(ptr_tomb[i]); } for(i=0; i<5; i++) { free(ptr_tomb[i]); } return 0; }
char Honap[][20]
![]()
char *honap[]
![]()
F: Olvasd be egy tömb méretét, foglalj neki dinamikusan helyet, majd olvasd be az elemeit! ============================================================================== #include <stdio.h> #include <stdlib.h> int main() { int *t, *p, i, N; scanf("%d", &N); t=(int*)malloc(N*sizeof(int)); for(i=0, p=t; i<N; i++, p++) { scanf("%d", p); } for(i=0, p=t; i<N; i++) { printf("%d\n", *(p++)); } free(t); return 0; }
F: Adott egy kétdimenziós tömb. Pointer segítségével járjuk be az összes elemét. ============================================================================== #include <stdio.h> #define SIZE 3 int main() { int tomb[SIZE][SIZE] = {{0, 1, 2 }, {3, 4, 5 }, {6, 7, 8 } }; int i,j; int *pa = NULL; pa = tomb; /* pa = &tomb[0][0] */ for(i = 0; i< SIZE*SIZE; i++) printf("%2d ", pa[i]); printf("\n"); for(i = 0; i< SIZE*SIZE; i++) printf("%2d ", *(pa+i)); printf("\n"); for(i = 0; i< SIZE*SIZE; i++, pa++) printf("%2d ", *pa); printf("\n"); /* vigyázat! mivel pa-t növeltük a for ciklusban, ezért a ciklus után már * nem a tömb legelső elemére fog mutatni! */ return 0; }
F: Dinamikus kétdimenziós tömb létrehozása ============================================================================== #include <stdio.h> #include <stdlib.h> int main() { int *p, **t; int N=3, M=4; int i, j, v=0; /* V1: egydimenziós tömb */ p=malloc(N*M*sizeof(int)); for(i=0; i<N; i++) { for(j=0; j<M; j++) { p[i*M+j]=v++; } } free(p); /* V2: sorokat külön-külön */ t=malloc(N*sizeof(int*)); for(i=0; i<N; i++) { t[i]=malloc(M*sizeof(int)); } for(i=0; i<N; i++) { for(j=0; j<M; j++) { t[i][j]=v++; } } for(i=0; i<N; i++) { free(t[i]); } free(t); return 0; }
#include <stdio.h> #include <stdlib.h> int main() { int i; const int maxsize = 100; /* Kétdimenziós tömbök */ float tomb_statikus[100][100]; float tomb_valtozo_meretu_de_a_gcc_nem_szereti[maxsize][maxsize]; /* * Mivel a program futása során tudjuk meg a maxsize -t (tegyük fel, hgoy így van) * dinamikusan kell (így a leghelyesebb, így ragaszkodunk a szabványhoz, és így lesz hordozható a kódunk ) * helyet foglalni a kétdimenziós tömbünknek. * * A kétdimenziós tömb olyan egydimenziós tömb, amelynek minden eleme egy egydimenziós tömb. * * egydimenziós tömböt tudunk dinamikus létrehozni : * float *tomb = (float*)calloc(meret, sizeof(float)); * -> tehát az első egydimenziós tömb elemeit (egydimenziós tömböket) létre tudjuk hozni. * azaz a deklarációnk nézhetne így is ki : float *tomb[meret] (hiszen ez egy pointerekból álló tömb.) * Ezzel nem kerültük ki a meret kiírását -> * csináljunk egy pointert erre a tömbre : float **tomb. * * És KÉSZ! * * */ /* Egy olyan pointer, amely egy pointerre mutat, amely egy float tipusú változó címét tudja tárolni. */ float **tomb_dinamikus; /* Foglaljuk le a helyet a külső tömbnek, azaz hozzunk létre egy olyan egydimenziós tömböt, * amelynek az elemei olyan pointerek, melyek float változók címeit tudják tárolni*/ tomb_dinamikus = (float**)calloc(maxsize, sizeof(float*)); /* Magyarázat : (float**) : mivel calloc egy void* -al tér vissza, helyes, ha típuskonverziót hajtunk végre. * mi a típusa tomb_dinamikus -nak? float**. * sizeof(float*) : minden egyes indexén a tomb_dinamikus tömbnek egy * float-ra mutató pointert akarunk tárolni. * Ezért az alaptípusának a mérete float*, tehát ennek a méretét kell megadnunk. * */ /* Foglaljunk helyet a most létrehozott tömb elemeinek (hiszen azok is pointerek) */ for(i = 0; i< maxsize; i++) tomb_dinamikus[i] = (float*)calloc(maxsize, sizeof(float)); /* Magyarázat : (float*) : mivel calloc egy void* -al tér vissza, helyes, ha típuskonverziót hajtunk végre. * mi a típusa tomb_dinamikus[i] -nek? float* . * sizeof(float) : minden tomb_dinamikus[i] egy float-ra mutató pointer. * Ezért az alaptípusának a mérete float, tehát ennek a méretét kell megadnunk. * */ tomb_dinamikus[2][5] = 12.45; printf("%f\n",tomb_dinamikus[2][5]); /* Ha már nem használjuk a tömbünket, fel kell szabadítani az általunk lefoglalt memóriaterületet. * * Először a pointereket tartalmazó tömbben lévő pointereket kell felszabadítanunk, majd utána a tömbnek lefoglalt memóriaterületet. * */ for(i = 0; i< maxsize; i++) free(tomb_dinamikus[i]); free(tomb_dinamikus); return 0; }
F: Készíts egy pointert, ami egy konstans értékre mutat. F: Készíts egy konstans pointert, ami egy nem konstans értékre mutat. F: Készíts egy pointert, ami egy tömbre mutat. ============================================================================== #include <stdio.h> int main() { const int *p=NULL; int * const c=NULL; int (*t)[20]; p=malloc(sizeof(int)); *p=2007; /* HIBÁS */ free(p); c=malloc(sizeof(int)); /* HIBÁS */ *c=2007; free(c); return 0; }
Tárolási osztályokat bemutató program ============================================================================== #include <stdio.h> #define MAX_NUM 5 /* A static tárolási osztály azt jelenti, hogy az adott változó megmarad a * blokkból kilépés után is, és a következő belépéskor elérhető lesz a * legutóbbi tartalom. * * Használhatjuk arra, hogy megszámoljuk, hányszor hívtuk az adott függvényt. */ int* counter() { static int count = 0; count++; printf("Count : %d\n",count); return &count; } int* kell() { return counter(); } int main() { /* Az auto tárolási osztály az alapértelmezett, ki sem szükséges tenni. */ auto int valami = 10; /* A register tárolási osztály arra szolgál, hogy jelezzük a fordítónak, * hogy olyan gépi kódot PRÓBÁLJON meg csinálni, amely során ez a változó * folyamatosan a CPU egy regiszterében van. -> Gyorsabb elérésű, mint a * memória, de sokkal kevesebb ilyen változó létezhet. Gyakran változó * változót érdemes. * * A fordító figyelmen kívül hagyhatja! */ register int i; /* A volatile módosító azt mondja a fordítónak, hogy: * "Vigyázat, ez a változó értéke úgy is módosulhat, hogy a kódban nincsen * annak módosítására szolgáló utasítás!" * Pl. a változó egy porthoz csatlakozik, ahová az adott eszköz írhat! */ volatile unsigned short int device = (unsigned short int)0; /* A const módosító azt mondja a fordítónak, hogy az érték nem * megváltoztatható. Ez viszont csak annyit jelent, hogy az adott * változóhivatkozás nem szerepelhet értékadás bal oldalán. */ const long int nemvaltozo = 2007; int *p; p=&i; /* EZ HIBÁS */ p=counter(); printf("*%p = %d\n", p, *p); p=kell(); printf("*%p = %d\n", p, *p); *p = 100; counter(); return 0; }
Megvalósítandó program: Piramis és rombusz kirajzolása képernyőre karakterek segítségével.
Kiírás: Írjunk egy olyan programot, mely bekér egy egyész számot, ez legyen a piramis magassága, majd pl. 'a' betűkből rajzoljon ki egy piramist. Két lehetséges futási eredmény:
Add meg milyen magas legyen a piramis: 6 a aaa aaaaa aaaaaaa aaaaaaaaa aaaaaaaaaaa
Add meg milyen magas legyen a piramis: 10 a aaa aaaaa aaaaaaa aaaaaaaaa aaaaaaaaaaa aaaaaaaaaaaaa aaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaa
Fejlesszük tovább a programot, hogy rombuszt rajzoljon ki. Természetesen ez nem más, mint a már meglévő piramisunk tükörképe. Vegyük figyelembe, hogy egy sorral kevesebbet rajzoltunk ki alul, hogy szép középvonalat kapjunk. Egy lehetséges futási eredmény:
Add meg milyen magas legyen a piramis: 10 a aaa aaaaa aaaaaaa aaaaaaaaa aaaaaaaaaaa aaaaaaaaaaaaa aaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaa aaaaaaaaaaaaa aaaaaaaaaaa aaaaaaaaa aaaaaaa aaaaa aaa a
Elég csak a rombusz forma megvalósítását elküldeni, abból látni fogom, hogy megy a felső és alsó rész generálása is.
Megoldások beküldésének határideje: 2014.11.09., vasárnap éjfél.
Egy lehetséges megoldás letöltése .
A házi feladatot megoldani nem kötelező és bemutatni sem kell, viszont a következő gyakorlaton visszakérhető (kikérdezés, táblához hívás, stb. formájában)! Ha a hallgató megoldása ötletes, szép kivitelezésű, plusz pont adható. Amennyiben viszont nem tudja megoldani gyakorlaton a házi feladatban szereplő példákat vagy nem tud válaszolni az azzal kapcsolatban feltett kérdésekre, mínusz pont adható. Plusz és mínusz pontból is egyaránt maximum 10 pontot gyűjthet össze egy-egy hallgató.
Házi feladat 01-hazi.txt , 02-hazi.txt .
Téma:
3. - 10. gyakorlat anyaga.
Gyakorlásra:
A honlapomon a 3. - 10. gyakorlathoz tartozó anyag, magyarázatokkal, példákkal.
A gyakorlatok végén lévő házi feladat és gyakorló feladatok megoldása.
A honlapom mellet további feladatok találhatóak a PUB-ban. (/n/pub/ProgramozasAlapjai/Gyakorlat/ - erős átfedés van az "itt" és "ott" található feladatok között).
Egyéb infó:
A gyakorlat 8:10-kor kezdődik és a ZH-t 8:15-kor kezdhetitek írni. Előreláthatóan 75 percetek lesz a feladat megoldására és beadására (tehát 9:30-ig). A feladatot a bíró rendszeren keresztül fogjátok megkapni és beadni is, és az értékelést is a bíró fogja csinálni ott helyben. Tehát egyből látni fogjátok a pontszámokat amiket a bíró adott. Aki késik, az is csak a fenti időintervallum alatt írhatja a ZH-t (a bíró rendszer nyit, majd automatikusan zár is). Hiányozni csak igazolással lehet, de a ZH akkor sem pótolható!
Vissza a lap tetejére.