5. gyakorlat Konstansok Tömbök Stringek
Konstansok A C nyelvben a konstansok preprocesszor makrókkal vannak megvalósítva. Konstansdefiniálás alakja: #define NÉV érték Az érték bármi lehet, később a fordítás első menetében a preprocesszor a név összes előfordulását szövegesen a megadott értékkel helyettesíti, majd folytatódik a fordítás. Így a konstans értéke akár programrészlet is lehet.
Új sor másként #include <stdio.h> #define NL printf("\n") #define N 10 int main() { int i; for( i = 0; i <= N; i++ ) { printf("%d %d\n", i, N); NL; return 0;
F: Írj egy programot, ami 1-től 10-ig kiírja a számokat, majd minden második, majd minden negyedik számot. #include <stdio.h> int main() { int i; for(i=1; i<=10; i++) { printf(" %d", i); putchar('\n'); for(i=1; i<=10; i+=2) { printf(" %d", i); putchar('\n'); for(i=1; i<=10; i+=4) { printf(" %d", i); putchar('\n'); return 0; F: Módosítsuk úgy a programot, hogy 21-től 144-ig írjon ki. Hány helyen kellett átírnunk számokat?
F: Csináljuk meg ugyanezt konstansokkal. Így hány helyen kellene módosítani? #include <stdio.h> #define A 1 #define B 10 int main() { int i; for(i=a; i<=b; i++) { printf(" %d", i); putchar('\n'); for(i=a; i<=b; i+=2) { printf(" %d", i); putchar('\n'); for(i=a; i<=b; i+=4) { printf(" %d", i); putchar('\n'); return 0;
Preprocesszálás Az ilyen konstansokat a preprocesszor kezeli, ugyanaz, aki a #include -ot is. gcc -E konstans.c >konstans.i gcc konstans.i -o konstans Nézzük meg a konstans.i végét! Felismerjük a saját kódunkat? Ami előtte van, az az #include <stdio.h> -ból jön. A preprocesszor nem ismeri a C nyelvet, csupán egy sztringhelyettesítő program (mint a szőke nő minden konstans helyére csak bemásolja, amit mi oda írtunk neki ), tehát ha hülyeséget csinálunk, az nyelvi hibaként jelenik meg!
F: Hol jelez hibát a fordító? Miért ott? #define int 100.0 int main() { float f = int; printf("%f\n", f); Mi a preprocesszálás eredménye? F: mi lesz, ha elhagyjuk a main elől az int-et? return 0;
Tömbök Több azonos típusú adat egyben való tárolására és kezelésére alkalmazhatók a tömbök. Alakja: tipus nev[meret]; pl. int egeszek[5]; // 5 db egész szám tárolására
Tömbök A méretnek fordításkor ismertnek kell lennie csak konstans, vagy literál lehet. Egy tömb mérete a program futása során nem változtatható. A tömbök egyes elemeit az indexük segítségével érhetjük el. Az index az elem sorszáma a tömbön belül. A tömbök indexelése 0-tól indul, tehát a tömb első elemének az indexe 0, a másodiké 1, az n-ediké n-1. Így egy n méretű tömb utolsó elemének indexe n-1. Példák: egeszek[2] = 4; egeszek[3] += 5; int a = egeszek[4]; printf("%d", egeszek[a]); Látható, hogy a tömb indexelésekor már nincs korlátozás, változó és függvényhívás is megadható a szögletes zárójelek között.
F: Készíts egy 10 egész szám tárolására alkalmas tömböt. Töltsd fel az 1..10 értékekkel, majd írasd ki az elemeit. #include <stdio.h> #define N 10 #define M 10 F: Mi történik, ha M<N? És ha N<M? int main() { int tomb[n]; int i; for(i=0; i<m; i++) { // 0-tól indexelünk tomb[i]=i+1; // viszont 1-től számozunk for(i=0; i<m; i++) { printf(" %d", tomb[i]); return 0; Az N<M eset hibás lesz! Egyszerűen nincs elég memória foglalva a tömb elemeinek. Ezt hívjuk túlindexelésnek. Ha negatív indexet adunk meg, az az alulindexelés.
Mátrixok A tömbök felfoghatók mátrixokként. Egy dimenziós tömbök: 1D-s mátrix, azaz sorvagy oszlopvektor Több dimenziós tömböket is létrehozhatunk, pl. int egeszmatrix[3][3];, vagy int sakktabla[8][8];. Az egyes dimenziók mérete el is térhet.
Mátrixok int a[5][3]; Vizuálisan így ábrázolható: index 0 1 2 0 a[0][0] a[0][1] a[0][2] 1 a[1][0] a[1][1] a[1][2] 2 a[2][0] a[2][1] a[2][2] 3 a[3][0] a[3][1] a[3][2] 4 a[4][0] a[4][1] a[4][2] Tömbök mérete nem állapítható meg, ezért valahogy jelezni kell azt. Ez lehet egy külön változó, ami tárolja az elemszámot, vagy pedig valamilyen egyértelmű végjel a tömb utolsó eleme után. A végjel nem fordulhat elő máshol a tömbben, ezért ez a módszer nem mindig alkalmazható. A legismertebb példa erre a stringek tárolása, egy 0 ascii kódú végjellel zárt karaktertömbben.
Tömbök feldolgozása Tömbök feldolgozása többnyire for-ciklussal történik, ahol a ciklusváltozót használjuk indexelésre. Ha a méret külön változóban van: int tomb[n]; int meret = N; int i; for(i = 0; i < meret; i++) { dosomething(tomb[i]); Ha a méretet végjel jelzi: char tomb[n]; char vegjel = 0; int i; for(i = 0; tomb[i]!= vegjel; i++) { dosomething(tomb[i]); Többdimenziós tömböket egymásba ágyazott forciklusokkal szoktunk feldolgozni.
F: Készíts egy 3x3-as mátrixot, töltsd fel elemekkel, majd írasd ki az elemeit sor illetve oszlopfolytonosan is! #include <stdio.h> #define N 3 int main() { int tomb[n][n]; int i, j; for(i=0; i<n; i++) { for(j=0; j<n; j++) { scanf("%d", &(tomb[i][j])); for(i=0; i<n; i++) { for(j=0; j<n; j++) { printf("%d", tomb[i][j]); for(i=0; i<n; i++) { for(j=0; j<n; j++) { printf("%d", tomb[j][i]); return 0;
Tömbök, mint függvényparaméterek Ha tömböket függvényeknek paraméterként akarunk átadni, a függvény fejlécében jelezni kell, hogy a változó tömb, de a méretét nem kell tudni, pl. void tombfgv(int tomb[], int meret) {... Híváskor csak a tömb nevét kell aktuális paraméterként megadni: tombfgv(entombom, tombmeret);. A tömbök cím szerint adódnak át, így a függvényben módosíthatók és a módosítások a program többi részében is láthatóak lesznek. Többdimenziós tömbök formális paraméterként való megadásakor csak az első dimenzió mérete hagyható el, a többit meg kell adni: void tombfuggveny2d(int tomb[][100], int meret1, int meret2) {.... Ezért is célszerű a tömbök méretét konstansban tárolni, így mindenhova csak a megfelelő konstanst kell beírni: void tombfuggveny2d(int tomb[][meret2], int meret1, int meret2) {...
Szövegek A sztringeket C-ben karakterek tömbjével lehet reprezentálni, pl. char szoveg[meret];. A tömb minden eleme a szöveg egy-egy karaktere, a szöveg végét egy 0 ascii kódú karakter (a NUL karakter) jelzi. Ez a karakter a tömbön belül bárhol lehet, az utána levő tömbelemeket a sztringeket feldolgozó függvények figyelmen kívül hagyják, így egy tömbben bármilyen hosszúságú szöveg tárolható, ami rövidebb a tömb méreténél. A záró 0 karakternek mindenképpen szerepelnie kell, mivel a tömb mérete nem állapítható meg, így nem lehetne tudni meddig tart a szöveg a memóriában. Emiatt eggyel nagyobb méretű tömböt kell deklarálni szöveg tárolására, hogy a záró 0 elférjen.
Példa Az "alma" szó egy tömbben: char str[10]; A feltöltés után str tartalma: 'a' 'l' 'm' 'a' 0????? 0 1 2 3 4 5 6 7 8 9 Ahol a kérdőjelek definiálatlan, véletlenszerű adatot jelentenek.
F: Deklarálj egy megfelelő hosszúságú karaktertömböt, majd írd bele a "Hello Vilag!" szöveget! Írasd ki az str értékét kétféleképpen! #include <stdio.h> int main() { char str[20]; str="hello Vilag!"; printf("%s", str); return 0; Ez így fordítási hiba. A baj az, hogy str egy karaktertömb, tehát csak egyesével lehet feltölteni az elemeit. Vagy használhatjuk az strcpy() függvényt.
F: Módosítsd a programot úgy, hogy a következő sorba csak a "Hello" szöveget írja ki! #include <stdio.h> #include<string.h> int main() { char str[20]; strcpy(str, "Hello Vilag!"); printf("%s", str); str[5]=0; printf("%s", str); return 0; A sztring egy speciálisan kezelt karaktertömb, ahol a tárolt szöveg végét a 0 kódú karakter jelzi. Ezt a végjelet írtuk be itt a megfelelő helyre. Az idézőjeles megadásnál ennek a végjelnek a tárolása automatikus. HF: Mi történik, ha az előző végjelet visszacseréled ' ' karakterre? HF: Mi történik, ha az str méretét leveszed mondjuk 4-re?
F: Írasd ki a teljes str tömb karaktereit! #include <stdio.h> int main() { char str[20]="hello Vilag!"; // így lehet inicializálni egy stringet. int i; for(i=0; i<20; i++) { putchar(str[i]); // ez a függvény egy db ascii karaktert ír ki putchar('\n'); return 0;
Inicializálás, beolvasás, kiíratás Ha inicializálunk egy stringet, a méret el is hagyható, pl. char str[]="ez egy szöveg";. Ilyenkor a tömb pontosan akkora méretű lesz, hogy a string a lezáró 0-val beleférjen. Stringeket is használhatunk a scanf-ben és a printf-ben. Ehhez a %s helyettesítő karaktert kell használni. FONTOS, hogy stringek beolvasása esetén a scanf-ben NEM kell az & jelet kiírni, tehát pl. scanf("%d%s", &szam, string); formátumban kell megvalósítani. A printf ugyanúgy működik, mint más típusokkal.
Példa kiíratásra, beolvasásra #include <stdio.h> #define STRHOSSZ 20 int main() { char sztring[strhossz+1]; // +1 a záró 0 miatt printf("írjon be egy maximum %d karakteres szót!\n", STRHOSSZ); scanf("%s", sztring); printf("beolvasva: %s\n\n", sztring); return 0;
Feladatok Írj egy függvényt, ami egy egész tömböt kap paraméterül és lecseréli benne az elemeket az abszolútértékükre. A tömb kiírását szintén függvény végezze! Számold ki két vektor skalárszorzatát! Egy v1=(a1,...,an) és egy v2=(b1,...,bn) vektor skalárszorzata a c=(a1*b1)+...+(an*bn) szám. Adj hozzá egy N-dimenziós vektorhoz egy másik N-dimenziós vektort.
Feladatok Az alábbi feladatokat a string.h használata nélkül kell megoldanod! Készíts egy függvényt, ami összehasonlít két stringet! (strcmp) Készíts egy függvényt, ami megszámolja egy sztringben található kisbetűk számát. (strsmallcount) Készíts egy függvényt, ami visszaadja egy sztring hosszát. (strlen) Készíts egy függvényt, ami megmondja, hogy két sztring közül melyik a rövidebb. (strlencmp) Készíts egy függvényt, ami kisbetűsíti a sztringet. (strsmall) Készíts egy függvényt, ami törli a sztringből a számjegyeket. (strdelnum) Olvass be két legfeljebb 20 karakter hosszúságú szót, és fűzd őket egymás után egy harmadik sztringbe. A string.h függvényeit használd!
Feladatok Készíts egy programot, amely egy tetszőleges nagyságú (maximum 9999 jegyű) számról a jól ismert oszthatósági szabályok felhasználásával eldönti, hogy a szám osztható-e az alábbi számok bármelyikével. A számot olvasd be és tárold sztringként. 2, 3, 4, 5, 8, 9, 10 6, 7, 11, 12 Oszthatósági szabályok: 2,5,10 - utolsó számjegy oszthatósága; 4 - utolsó két számjegy oszthatósága; 8 - utolsó három számjegy oszthatósága; 3,9 - számjegyek összegének oszthatósága; 11 - számjegyek alternáló összegének oszthatósága; 7 - a (jobb szélről) három számjegyenként csoportosított számok alternáló összegének oszthatósága; 6/12-3-mal és 2/4-gyel való oszthatóság. Készíts egy programot, ami egy felhasználó által megadott stringben a mondatok kezdőbetűjét nagybetűre cseréli (.? és! utáni első [a-z] karaktert, ha addig nincs [A-Z] karakter, illetve számjegy), illetve a számjegyeket a szöveges írásmódjukra (1 -> egy, 2012 - > kettőnullaegykettő). Írd ki az eredményt!
Házi feladat Kérj be egész számokat a felhasználótól és tedd őket egy tömbbe, majd készítsd el az alábbi függvényeket és hívd meg őket a tömbre, az eredményüket pedig írd ki. Készíts egy függvényt, ami egy átadott tömb legkisebb elemét adja vissza Készíts egy függvényt, ami egy átadott tömb legnagyobb páros elemét adja vissza Készíts egy függvényt, ami egy tömb elemeinek az átlagát adja vissza. Ha lehet, valós átlagot számolj! Készíts egy függvényt, ami megszámolja, hogy a paraméterként átadott tömbnek hány eleme osztható egy szintén paraméterként átadott számmal! Olvass be egy stringet és minden magánhangzót cserélj le benne egy * karakterre, majd írd ki!
Puzzle #include<stdio.h> #define A 100; int main(){ Miért 99 lesz b értéke? int a=15, b=2; b = A+a+b--; printf("%d", b); printf("\n"); return 0;