Mutatók. Programozás I. Hatwágner F. Miklós február 26. Széchenyi István Egyetem, Gy r

Hasonló dokumentumok
Programozás. (GKxB_INTM021) Dr. Hatwágner F. Miklós március 31. Széchenyi István Egyetem, Gy r

Függvények. Programozás I. Hatwágner F. Miklós november 16. Széchenyi István Egyetem, Gy r

Programozás. (GKxB_INTM021) Dr. Hatwágner F. Miklós április 4. Széchenyi István Egyetem, Gy r

Programozás C nyelven (10a. ELŐADÁS) Sapientia EMTE

Programozás I gyakorlat

Programozás C nyelven (10. ELŐADÁS) Sapientia EMTE

A C programozási nyelv III. Pointerek és tömbök.

Programozás alapjai. (GKxB_INTM023) Dr. Hatwágner F. Miklós augusztus 29. Széchenyi István Egyetem, Gy r

A C programozási nyelv III. Pointerek és tömbök.

Programozás I gyakorlat. 10. Stringek, mutatók

Járműfedélzeti rendszerek II. 3. előadás Dr. Bécsi Tamás

Programozás C- és Matlab nyelven C programozás kurzus BMEKOKAM603 Mutatók. Dr. Bécsi Tamás 7. Előadás

Objektumok tulajdonságai

Programozás alapjai. (GKxB_INTM023) Dr. Hatwágner F. Miklós szeptember 27. Széchenyi István Egyetem, Gy r

M veletek és kifejezések

Programozás alapjai. (GKxB_INTM023) Dr. Hatwágner F. Miklós október 15. Széchenyi István Egyetem, Gy r

Típusok és konstansok

Programozás alapjai. (GKxB_INTM023) Dr. Hatwágner F. Miklós október 11. Széchenyi István Egyetem, Gy r

Programozás 6. Dr. Iványi Péter

Programozás alapjai 9.Gy: Struktúra 2.

6. gyakorlat Egydimenziós numerikus tömbök kezelése, tömbi algoritmusok

C programozási nyelv Pointerek, tömbök, pointer aritmetika

A C programozási nyelv I. Bevezetés

A C programozási nyelv I. Bevezetés

Programozás alapjai gyakorlat. 4. gyakorlat Konstansok, tömbök, stringek

5. gyakorlat. Konstansok Tömbök Stringek

Programozás. (GKxB_INTM021) Dr. Hatwágner F. Miklós március 3. Széchenyi István Egyetem, Gy r

C programozás. 6 óra Függvények, függvényszerű makrók, globális és

1. Template (sablon) 1.1. Függvénysablon Függvénysablon példányosítás Osztálysablon

Programozás alapjai C nyelv 4. gyakorlat. Mit tudunk már? Feltételes operátor (?:) Típus fogalma char, int, float, double

7/8. gyakorlat Karaktertömbök és sztringkezelés

Programozás. (GKxB_INTM021) Dr. Hatwágner F. Miklós február 18. Széchenyi István Egyetem, Gy r

11. gyakorlat Sturktúrák használata. 1. Definiáljon dátum típust. Olvasson be két dátumot, és határozza meg melyik a régebbi.

1.1. A forrásprogramok felépítése Nevek és kulcsszavak Alapvető típusok. C programozás 3

Programozás alapjai C nyelv 7. gyakorlat. Függvények. Függvények(2)

Függvények. Programozás alapjai C nyelv 7. gyakorlat. LNKO függvény. Függvények(2) LNKO függvény (2) LNKO függvény (3)

Programozás I gyakorlat

A C programozási nyelv V. Struktúra Dinamikus memóriakezelés

10. gyakorlat Tömb, mint függvény argumentum

tétel: különböző típusú adatokat csoportosít, ezeket egyetlen adatként kezeli, de hozzáférhetünk az elemeihez is

Keresés és rendezés. A programozás alapjai I. Hálózati Rendszerek és Szolgáltatások Tanszék Farkas Balázs, Fiala Péter, Vitéz András, Zsóka Zoltán

Mit tudunk már? Programozás alapjai C nyelv 4. gyakorlat. Legnagyobb elem keresése. Feltételes operátor (?:) Legnagyobb elem keresése (3)

Tartalom Keresés és rendezés. Vektoralgoritmusok. 1. fejezet. Keresés adatvektorban. A programozás alapjai I.

Programozás I gyakorlat

/* Az iter függvény meghívása és a visszatérő érték átadása a gyok változóba */ gyok = iter( n, a, e ) ;

Megoldott programozási feladatok standard C-ben

C string műveletek (string.h alkalmazása)

Programozás II. 2. Dr. Iványi Péter

Programozás 5. Dr. Iványi Péter

C memóriakezelés. Mutató típusú változót egy típus és a változó neve elé írt csillag karakterrel hozhatjuk létre.

10. gyakorlat. Pointerek Tárolási osztályok

Programozas 1. Strukturak, mutatok

Programozás I. 3. gyakorlat. Szegedi Tudományegyetem Természettudományi és Informatikai Kar

Bevezetés a C programozási nyelvbe. Az Általános Informatikai Tanszék C nyelvi kódolási szabványa

Struktúrák (struct) A struktúra szerkezetét meghatározó deklaráció általános formája:

Programozás. (GKxB_INTM021) Dr. Hatwágner F. Miklós május 6. Széchenyi István Egyetem, Gy r

A C programozási nyelv II. Utasítások. A függvény.

Programozás alapjai 2.Gy: A C nyelv alapjai P R O

8. gyakorlat Pointerek, dinamikus memóriakezelés

C# nyelv alapjai. Krizsán Zoltán 1. Objektumorientált programozás C# alapokon tananyag. Általános Informatikai Tanszék Miskolci Egyetem

Függvény pointer. Feladat: Egy tömbben soroljunk fel függvényeket, és hívjuk meg valahányszor.

Programozás II. 4. Dr. Iványi Péter

Mutatók. Programozás II. Hatwágner F. Miklós március 4. Széchenyi István Egyetem, Gy r

Szövegek C++ -ban, a string osztály

Mutatók és mutató-aritmetika C-ben március 19.

Programozás C nyelven FELÜLNÉZETBŐL elhullatott MORZSÁK. Sapientia EMTE

Miről lesz ma szó? A PROGAMOZÁS ALAPJAI 1. Dinamikus változók. Dinamikus változók. Dinamikus változók. Dinamikus változók. 7.

Programozás alapjai C nyelv 10. gyakorlat. Standard függvények. Union

Java II. I A Java programozási nyelv alapelemei

1. Alapok. Programozás II

Mérnöki programozás 7. Szerkesztette: dr. Vass Péter Tamás

Pénzügyi algoritmusok

Informatika terméktervezőknek

Programozás C nyelven (9. ELŐADÁS) Sapientia EMTE

Mintavételes szabályozás mikrovezérlő segítségével

Példák tematikus csoportosításban

Programozás C és C++ -ban

C++ referencia. Izsó Tamás február 17. A C++ nyelvben nagyon sok félreértés van a referenciával kapcsolatban. A Legyakoribb hibák:

INFORMATIKA tétel 2018

Programozás 1. Dr. Iványi Péter

Karakter- és sztringkezelő függvények, matematikai függvények

Programozási nyelvek I. 5. előadás (Gregorics Tibor anyagának felhasználásával)

Stack Vezérlés szerkezet Adat 2.

Programozás alapjai C nyelv 8. gyakorlat. Mutatók és címek (ism.) Indirekció (ism)

Bevezetés a programozásba I.

Járműfedélzeti rendszerek II. 4. előadás Dr. Bécsi Tamás

Programozás alapjai. 5. előadás

A C programozási nyelv VI. Parancssori argumentumok File kezelés

Programozás alapjai 8.Gy: Program struktúra

Alprogramok, paraméterátadás

Mutatók és címek (ism.) Programozás alapjai C nyelv 8. gyakorlat. Indirekció (ism) Néhány dolog érthetőbb (ism.) Változók a memóriában

Járműfedélzeti rendszerek II. 2. előadás Dr. Bécsi Tamás

C változók. Feladat: Deklaralj egy valos, egy karakter es ket egesz tipusu valtozot! int main() {

Java II. I A Java programozási nyelv alapelemei

Programozás I gyakorlat

Járműfedélzeti rendszerek II. 1. előadás Dr. Bécsi Tamás

Programozási Nyelvek: C++

A helyi információ és az id kezelése

Pénzügyi algoritmusok

Pénzügyi algoritmusok

Átírás:

Mutatók Programozás I. Széchenyi István Egyetem, Gy r 2014. február 26.

Mutatók (pointer) Áttekintés Memóriacím tárolására szolgáló adattípus Címezhet függvényt (kódot) és adatot (objektumot) is Mutató típusa megcímzett objektum típusa Technikailag: unsigned int, különféle korlátozásokkal Mutatódeklarációk Mint más típusoknál: azonosító + (mutatott obj.) típus meghatározása Általánosan: típus* azonosító; (fehér karakterek használata tetsz leges a * körül) Speciális eset: void* meghatározatlan típusra mutat (bármilyen cím hozzárendelhet explicit típuskényszerítés nélkül, és fordítva)

Mutatódeklarációk Példa int* pi; /* egészet címz mutató */ /* hozzáf zi src-t a dest végéhez, és annak címével tér vissza (string.h) Visszatérési érték: char*, karaktert címz mutató Paraméterek: karaktert címz mutatók, utóbbinál a mutatott érték konstans, azaz az src értékét nem tudja módosítani */ char *strcat(char *dest, const char *src); Statikus élettartam: tiszta zérus kezd érték, lokális: memóriaszemét stdio.h NULL Ezen a címen semmit nem helyeznek el különleges esetek, pl. hibák jelzésére Ugyanúgy használható cím, mint a többi (összehasonlítás, hozzárendelés,... )

Cím operátor (&) Példa Általános alak: &el tag-kifejezés, ahol az el tag-kifejezés lehet függvény nem register tárolási osztályú objektumot elér balérték de nem lehet bitmez (ld. struktúrák), ált. kifejezés, konstans tipikusan: egyszer változók, tömbelemek cím tárolása: hozzárendeléssel, inicializációval int i, *pi=&i; int j=3, *pj=&j; /* int* k, l=k; warning: initialization makes integer from pointer without a cast */ char c='a'; char* pc; /* pc = &'A'; error: lvalue required as unary `&' operand */ pc = &c; pi = pj; /* pc = pi; warning: assignment from incompatible pointer type */ pc = (char*)pi; /* függvény és adatmutatók között nincs konv.! */

Indirekció operátor (*) Feladata: adott címen lév érték elérése Általános alak: *el tag-kifejezés Eredménye balérték Nem használható, ha el tag-kifejezés nem értékelhet ki címmé void* típusú (címzett objektum mérete ismeretlen) Meghatározatlan az eredménye, ha a mutató NULL épp nem látható lokális objektum címe program által nem használható címet tartalmaz

Indirekció operátor (*) Forrás #include<stdio.h> #include<math.h> int main(void) { double d=0.; double* pd=&d; void* pv=pd; printf("'d' értéke: %f, címe: %p, 'pv' értéke: %p\n" "'pd' értéke: %p\n", d, (void*)&d, pv, (void*)pd); d = *(double*)pv + M_PI_2; printf("'d' szinusza: %f\n", sin(d)); *pd += M_PI; printf("'*pd' szinusza: %f\n", sin(*pd)); return 0; } Kimenet 'd' értéke: 0.000000, címe: 0xbfce7f90, 'pv' értéke: 0xbfce7f90 'pd' értéke: 0xbfce7f90 'd' szinusza: 1.000000 '*pd' szinusza: -1.000000

Mutatók inicializálása Statikus mutató nem inicializálható automatikus objektum címével, mert annak címe minden végrehajtáskor más és más lehet. Példa #include<stdio.h> int gi; int main(void) { int li; int* pli=&li; int* pgi=&gi; /* static int* spli=&li; error: initializer element is not constant */ static int* spgi=&gi; return 0; }

Konstans mutatók Mutató deklarálás ált. alakja: <deklaráció-specikátorok> típus * <típusmódosító-lista> deklarátor ahol a <típusmódosító-lista> tartalmazhatja: const volatile Ne keverjük össze a konstanst címz nem konstans mutatót a nem konstanst címz konstans mutatóval! Konstans objektumot címz konstans mutató is létrehozható Konstans objektumot csak olyan mutató címezhet, melynek cél típusa is konstans min sít nem hatástalanítható

Konstans mutatók Példa #include<stdio.h> int main(void) { int i; int* pi=&i; int* const cpi=&i; const int ci = 1; /* int* pci=&ci; warning: initialization discards `const' qualifier from pointer target type */ const int* pci=&ci; const int* const cpci=&ci; i=12; *pi<<=3; pi=0; *cpi = 5; /* cpi=null; error: assignment of read-only variable `cpi' */ /* ci = 6; error: assignment of read-only variable `ci' */ /* *pci = 7; error: assignment of read-only location `*pci' */ pci = NULL; printf("'ci' értéke: %d\n", *cpci); /* 'ci' értéke: 1 */ return 0; }

Mutatók és függvényparaméterek A paraméterátadás alapvet en érték szerint történik, vermen keresztül. #include<stdio.h> void fv(int j) { printf("'j' címe: %p, értéke: %d\n", (void*)&j, j); } void fvp(int* pi) { printf("'pi' címe: %p, értéke: %p, " "mutatott érték: %d\n", (void*)&pi, (void*)pi, *pi); } int main(void) { int i=5; printf("'i' címe: %p, értéke: %d\n", (void*)&i, i); fv(i); fvp(&i); return 0; } Kimenet 'i' címe: 0xbfe0fc2c, értéke: 5 'j' címe: 0xbfe0fc10, értéke: 5 'pi' címe: 0xbfe0fc10, értéke: 0xbfe0fc2c, mutatott érték: 5

Mutatók és függvényparaméterek Adatok felcserélése, 1. rész #include<stdio.h> void csere1(int i, int j) { int cs; printf("(i==%d, j==%d)\n", i, j); cs = i; i = j; j = cs; printf("(i==%d, j==%d)\n", i, j); } void csere2(int* i, int* j) { int cs; printf("(*i==%d, *j==%d)\n", *i, *j); cs = *i; *i = *j; *j = cs; printf("(*i==%d, *j==%d)\n", *i, *j); }

Mutatók és függvényparaméterek Adatok felcserélése, 2. rész int main(void) { int a=2, b=5; printf("'a' értéke: %d, 'b' értéke: %d\n", a, b); csere1(a, b); printf("'a' értéke: %d, 'b' értéke: %d\n", a, b); csere2(&a, &b); printf("'a' értéke: %d, 'b' értéke: %d\n", a, b); return 0; } Kimenet 'a' értéke: 2, 'b' értéke: 5 (i==2, j==5) (i==5, j==2) 'a' értéke: 2, 'b' értéke: 5 (*i==2, *j==5) (*i==5, *j==2) 'a' értéke: 5, 'b' értéke: 2

Mutatók és tömbök Ha (rész)kifejezés típus tömbje, akkor a (rész)kifejezés értékét a fordító a tömb els elemét címz konstans mutatóvá (típus * const) alakítja Kivételek: (rész)kifejezés cím operátor (&), ++,,. (struktúratag-kiválasztás), sizeof operandusa, hozzár. bal oldalán áll Tömbök címe, elemeik, azok címzése... #include<stdio.h> #define MERET 5 int main(void) { int ai[meret] = {1, 2, 3, 4, 5}; char ac[meret] = "Gyor"; int i; char* pc; for(i=0; i<meret; i++) { printf("ai[%d] értéke: %d, címe: %p\n", i, ai[i], (void*)&ai[i]); } for(pc=ac; pc-ac<meret; pc++) { printf("ac[%d] értéke: '%c', kódja: %d, címe: %p\n", pc-ac, *pc, *pc, pc); } return 0; }

Mutatók és tömbök Kimenet ai[0] értéke: 1, címe: 0xbfaf9ab8 ai[1] értéke: 2, címe: 0xbfaf9abc ai[2] értéke: 3, címe: 0xbfaf9ac0 ai[3] értéke: 4, címe: 0xbfaf9ac4 ai[4] értéke: 5, címe: 0xbfaf9ac8 ac[0] értéke: 'G', kódja: 71, címe: 0xbfaf9ad7 ac[1] értéke: 'y', kódja: 121, címe: 0xbfaf9ad8 ac[2] értéke: 'o', kódja: 111, címe: 0xbfaf9ad9 ac[3] értéke: 'r', kódja: 114, címe: 0xbfaf9ada ac[4] értéke: '', kódja: 0, címe: 0xbfaf9adb

Tömbök indexelése ([]) Tömbindexelés általános alakja: utótag-kifejezés[kifejezés] utótag-kifejezés és kifejezés közül az egyiknek mutatónak, a másiknak egésznek kell lennie Fordító átalakítja: *((utótag-kifejezés) + (kifejezés)) (konverziók) tömbelemcíme = tömbkezd címe + index*sizeof(tömbelemeinektípusa)

Tömbök indexelése ([]) Indexelés #include<stdio.h> int main(void) { char ac[] = {1, 2, 3, 4, 5}; char* pac = ac; /* pac = &ac; warning: assignment from incompatible pointer type */ /* ac = pac; error: incompatible types when assigning to type `char[5]' from type `char *' */ /* ac++; error: lvalue required as increment operand */ pac++; printf("%d\n", *pac); printf("ac[2] == %d\n", ac[2]); printf("ac[2] == %d\n", 2[ac]); printf("ac[2] == %d\n", *(ac+2)); printf("ac[0] címe: %p, ac[2] címe: %p\n", ac, ac+2); return 0; } Kimenet 2 ac[2] == 3 ac[2] == 3 ac[2] == 3 ac[0] címe: 0xbfe60ce7, ac[2] címe: 0xbfe60ce9

Néhány korábbi példa mutatókat használó változatai Példa #include<stdio.h> int hossz(const char* s) { const char* save = s; while(*s) s++; return s-save; } void fordit(char* s) { char* t = s+hossz(s)-1; while(s < t) { char cs = *s; *s++ = *t; *t-- = cs; } } int main(void) { char szo[] = "Irgumburgum"; printf("%s hossza: %d\n", szo, hossz(szo)); fordit(szo); printf("megfordítva: %s\n", szo); return 0; } Kimenet Irgumburgum hossza: 11 Megfordítva: mugrubmugri

Tömbök deklarálása Általános alak: típus deklarátor[<konstans-kifejezés>]<={inicializátorlista}> konstans-kifejezés: nemnegatív egész típusú konstans (vagy expliciten azzá alakított, ill. karakteres, felsorolás és sizeof) Méretet nem adják meg? Inicializátorlista elemeinek megszámolása, ha van. Inicializátorlista elemszáma nem egyezik a tömb elemszámával? Se elemszám, se inicializátorlista? (nem teljes típusú tömb) kés bbi deklarációban adják meg az elemszámot vagy az inicializátorlistát vagy mindkett t vagy másik forrásmodulban történik a deníció (extern) Függvény honnan tudhatja a paraméter tömb elemszámát? azt is átadjuk neki ismert, a tömb elemeire vonatkozó szabály alapján meghatározható (pl. lánczáró nulla)

Egészek tömbbe olvasása és visszaírása pelda24.c, 1. rész #include <stdio.h> #define SIZE 50 int getint(int *); void main(void) { int i, n, array[size]; printf("egészek tömbbe olvasása és visszaírása " "címeikkel együtt\nlegfeljebb %d egész van " "vagy végül EOF-ot megadva kevesebb!\nadja " "meg az egész számokat!\n\n", SIZE); for(n=0; n<size&&getint(&array[n])!=eof; n++); printf("\n\na tömbelemek címei rendre:\n\n"); for(i=0; i<n; i++) printf("%16p", &array[i]); printf("\n\na tömbelemek értékei rendre:\n\n"); for(i=0; i<n; i++) printf("%16d", array[i]); }

Egészek tömbbe olvasása és visszaírása pelda24.c, 2. rész int getch(void); int ungetch(int); /* A következ egész beolvasása a bemenetr l */ int getint(int *pn) { int c, sign=1; /* Az elöl lev üres karakterek átlépése */ while((c=getch())==' ' c=='\n' c=='\t'); /* Az el jel feljegyzése */ if(c=='+' c=='-') { sign=(c=='+')?1:-1; c=getch(); } /* A szám behozatala és konverziója */ for(*pn=0; c>='0' && c<='9'; c=getch()) *pn=10**pn+c-'0'; *pn*=sign; if(c!=eof) ungetch(c); return(c); }

Egészek tömbbe olvasása és visszaírása pelda24.c, 3. rész #define BUFSIZE 100 char buf[bufsize]; int bufp=0; int getch(void) { return((bufp>0)?buf[--bufp]:getchar()); } int ungetch(int c) { if(bufp>=bufsize){ printf("\n\t\tungetch: Túl sok karakter!\n"); return EOF; } else return buf[bufp++]=c; }

Egészek tömbbe olvasása és visszaírása Kimenet Egészek tömbbe olvasása és visszaírása címeikkel együtt Legfeljebb 50 egész van vagy végül EOF-ot megadva kevesebb! Adja meg az egész számokat! 1 32-4 6 A tömbelemek címei rendre: 0xbfb38690 0xbfb38694 0xbfb38698 0xbfb3869c A tömbelemek értékei rendre: 1 32-4 6

Mutatóaritmetika (címaritmetika) Mutatók értékével végzett aritmetikai m veletek növelés/csökkentés, összeadás/kivonás, relációk Feltevés: ugyanannak az obj.-nak a részeit címzik a mutatók Figyelembe veszik a mutatott típus méretét Növelés/csökkentés és összeadás/kivonás tulajdonságai Cím változása: sizeof(típus) többszörösével típus tömbje esetén csak [0; elemszám] index elemek címezhet ek void* mutatóval nem végezhet Eredmény típusa: mutató Összeadás operandusainak típusai: mutató és egész Kivonásnál a kisebbítend : mutató, kivonandó: egész egyazon obj. másik részét címz mutató indexkülönbség ptrdiff_t típusban (ld. stdio.h, ált. signed int) Növelés/csökkentés: tömbök következ /el z elemének címét adja

Mutatóaritmetika (címaritmetika) Relációk Egyazon obj. részeit címz mutatók (címek) összehasonlítása Egyenl ségi relációknál: mutató hasonlítható a NULL értékhez is 0 érték egész kifejezéshez void* mutató más típusú mutatóhoz Feltételes kifejezés ha az operandusok mutatók, melyek közül legalább az egyik void*, az eredmény is az lesz mutató és 0 érték konstans kif. esetén az eredmény a mutató típusa az eredmény megörökli az operandusok módosítóit (const, volatile)

Mutatóaritmetika (címaritmetika) pelda24.c módosítása #define BUFSIZE 100 char buf[bufsize]; char* bufp=buf; int getch(void) { return((bufp>buf)?*--bufp:getchar()); } int ungetch(int c){ if(bufp>=buf+bufsize) { printf("\n\t\tungetch: Túl sok karakter!\n"); return EOF; } else return *bufp++=c; }

Mutatók átalakítása Explicit típuskonverzió: (típus*) A 0 érték konstans egész kif., és a NULL érték void* mutató bármilyen más típusú mutatóvá konvertálható Többi típus: potenciális tárillesztési, bájt határra igazítási problémák (pl. char* 1x, short* 2x, int* 4x) void* bármib l és bármivé alakítható mutató konvertálható elég nagy egésszé, pl. ha kisebb az egésznél, nagyobb egésszé alakítja majd unsigned-ként tekint rá lebeg pontos típusra nem lehet átalakítani egész mutató, pl. mutató méret egésszé alakítás, ha szükséges majd ismét unsigned-ként tekint rá

Karakterláncok kezelése Karakterlánc konstans konstans karaktertömb konstans karaktert címz mutató Karakterlánc konstansok #include<stdio.h> int main(void) { const char s1[] = "Karakterlánc konstans.\n"; const char* s2 = "Karakterlánc konstans.\n"; const char* s3 = s1; /* Mi a címe ennek a karakterláncnak? */ printf("karakterlánc konstans.\n"); printf(s1); printf(s2); printf(s3); return 0; }

Karakterláncok kezelése Karakterlánc kezel függvények string.h str...() paraméter és vt. érték típusa: char* mem...() paraméter és vt. érték típusa: void*, nem várnak el '\0'-t Az eredmény címét adják vissza Egymást átfed memóriaterületek deniálatlan viselkedés, kivéve memmove()

Karakterláncok összef zése char *strcat(char *dest, const char *src); char *strncat(char *dest, const char *src, size_t n); Hozzáf zi src-t dest végéhez, lezáró '\0'-t megfelel en elhelyezi size_t ált. unsigned int, strncat() legfeljebb n karaktert f z hozzá dest-hez Elegend helynek (azaz strlen(dest)+strlen(src)+1, ill. strlen(dest)+n+1) kell lennie dest-t l kezd d en! Egy lehetséges strncat() megvalósítás char *strncat(char *dest, const char *src, size_t n) { char *save = dest; /* Pozícionálás dest lezáró '\0' karakterére: */ while(*dest) ++dest; /* src dest végére másolása a záró '\0'-ig, vagy legfeljebb n karakterig: */ while(n-- && (*dest++ = *src++)); /* Vissza az egyesített karakterlánc kezd címe: */ return save; }

Karakterek keresése char *strchr(const char *s, int c); c-nek s-en belüli els elfordulásának címével tér vissza, vagy NULL-lal, ha nem találja Akkor is m ködik, ha c=='\0' void *memchr(const void *s, int c, size_t n); Mint strchr(), de csak az els n bájtban keres char *strrchr(const char *s, int c); void *memrchr(const void *s, int c, size_t n); Mint strchr() és memchr(), de az utolsó elfordulás címét adják vissza

Karakterek keresése Egy lehetséges strchr() megvalósítás #include<stdio.h> const char *strchr(const char *s, int c) { while(*s!=c && *s) s++; if(*s) return s; else return NULL; } int main(void) { char* str = "ABC"; char c = 'B'; printf("\"%s\" címe: %p, '%c' címe: %p\n", str, str, c, strchr(str, c)); c = 'X'; printf("'%c' el fordul benne? %s\n", c, strchr(str, c)?"igen":"nem"); return 0; } Kimenet "ABC" címe: 0x80485a0, 'B' címe: 0x80485a1 'X' el fordul benne? Nem

Karakterek keresése Megállapítjuk, hogy egy szöveg mely karakterei magánhangzók, mássalhangzók és egyéb karakterek #include<stdio.h> #include<ctype.h> #include<string.h> int main(void) { char* szoveg = "Commodore 64 Basic V2"; char* magan = "euioa"; printf("magánhangzók (G), mássalhangzók (S) és egyéb " "jelek (-) keresése\n%s\n", szoveg); for(; *szoveg; szoveg++) { if(isalpha(*szoveg)) { /* Bináris <--> soros keresés? */ if(strchr(magan, tolower(*szoveg))) putchar('g'); else putchar('s'); } else putchar('-'); } putchar('\n'); return 0; } Kimenet Magánhangzók (G), mássalhangzók (S) és egyéb jelek (-) keresése Commodore 64 Basic V2 SGSSGSGSG----SGSGS-S-

Karakterláncok összehasonlítása int strcmp(const char *s1, const char *s2); int strncmp(const char *s1, const char *s2, size_t n); int memcmp(const void *s1, const void *s2, size_t n); Összehasonlítják az unsigned char-ként értelmezett s1 és s2 paramétereket. Vt. érték negatív, ha s1 < s2, pozitív, ha s1 > s2, különben nulla. strncmp() és memcmp() legfeljebb az els n karakterig/bájtig végzik az összehasonlítást strcmp() egy lehetséges megvalósítása int strcmp(const char *s1, const char *s2 ) { for(; *s1 == *s2; ++s1, ++s2) if(!(*s1)) return 0; /* s1 == s2 */ return(*s1 - *s2); } /* s1 < s2 vagy s1 > s2 */

Karakterláncok másolása char *strcpy(char *dest, const char *src); char *strncpy(char *dest, const char *src, size_t n); void *memcpy(void *dest, const void *src, size_t n); void *memmove(void *dest, const void *src, size_t n); Karakterek/bájtok másolása src helyr l dest-re Az eredmény (dest) címével térnek vissza strncpy() legfeljebb n karaktert másol, és ha src rövidebb n-nél, akkor a lánczáró nullát is kiteszi, de különben nem. memcpy() és memmove() pontosan n bájtot másolnak át Nem ellen rzik, hogy el fog-e férni az eredmény a dest helyen Egymást átfed memóriaterületekkel csak a memmove() birkózik meg Hibát jelz visszatérési érték egyiknél sincs

Másolás, keresés, hossz strcpy() egy lehetséges megvalósítása char *strcpy(char *dest, const char *src) { char *save = dest; /* src dest-be másolása lezáró '\0' karakterével: */ while(*dest++ = *src++); /* Vissza a másolat karakterlánc kezd címe: */ return save; } char *strstr(const char *haystack, const char *needle); needle els el fordulásának címét adja meg haystack-en belül, vagy NULL értéket, ha nem található. Ha needle üres karakterlánc, akkor haystack-kel tér vissza. A keresésbe természetesen nem értend k bele a lánczáró karakterek. size_t strlen(const char *s); s hosszát adja (lánczáró nulla nélkül)

Keresés és csere (helyben) Feltesszük, hogy az eredmény el fog férni miben helyen! void kercsere(char* miben, const char* mit, const char* mire) { char* hely = miben; char* vege = miben + strlen(miben); int mithossz = strlen(mit); int mirehossz = strlen(mire); int eltolas = mirehossz - mithossz; while((hely=strstr(hely, mit))) { memmove(hely+mirehossz, hely+mithossz, vege-hely-mithossz+1); memcpy(hely, mire, mirehossz); vege+=eltolas; hely+=mirehossz; } }

Karakterhalmaz bármely elemének keresése char *strpbrk(const char *s, const char *accept); Az accept bármely karakterének els el fordulását keresi s-ben, és annak címével tér vissza, vagy NULL-lal, ha nincsenek közös karakterek. (Lánczáró nullákkal nem foglalkozik.) Szöveg mondatokra tördelése (minden szempontból helyes szöveget feltételezve). Elrontja a szöveget! #include<stdio.h> #include<string.h> int main(void) { char szoveg[] = "Szép volt. Jó volt. Köszönöm, ennyi."; char* eleje = szoveg; char* vege; while(vege=strpbrk(eleje, ".!?")) { if(!*++vege) break; *vege = '\0'; printf("%s\n", eleje); eleje = ++vege; } printf("%s\n", eleje); return 0; }

Memóriaterület feltöltése void *memset(void *s, int c, size_t n); s címt l kezdve n bájtot feltölt c értékével, majd visszaadja s-et Szöveg jobbra igazítása helyben #include<stdio.h> #include<string.h> char* jobbra(char* s, int szelesseg) { int hossz = strlen(s); int tol = szelesseg-hossz; if(tol>0) { *(s+szelesseg) = '\0'; memmove(s+tol, s, hossz); memset(s, ' ', tol); } return s; } #define SZ 20 int main(void) { int i; char szoveg[128] = "Kis patak"; /* printf(" %*s \n", SZ, szoveg); */ printf(" %s \n ", jobbra(szoveg, SZ)); for(i=0; i<sz; i++) putchar(i%10+'0'); printf(" \n"); return 0; }

Adott halmazba es karaktereket (nem) tartalmazó rész-karakterlánc hosszának megállapítása size_t strspn(const char *s, const char *accept); Meghatározza s azon kezd szegmensének hosszát, amely csak accept-beli karaktereket tartalmaz size_t strcspn(const char *s, const char *reject); Meghatározza s azon kezd szegmensének hosszát, amely csak reject-ben nem szerepl karaktereket tartalmaz Robot irányítása: csak a négy iránynak megfelel (J - jobbra, B - balra, F - fel, L - le) karaktereket engedjük meg a vezérl karakterláncban #include<stdio.h> #include<string.h> int main(void) { char irany[] = "JJJJFJFJFFJJFJJJLJLJLLJLLLJLLLBBB"; printf("%s ellen rzése: %s\n", irany, *(irany+strspn(irany, "JBFL"))?"hibás":"rendben"); return 0; }

Karakterlánc tokenekre bontása char *strtok(char *str, const char *delim); Egymást követ hívásokra a karakterláncban lév szimbólumok címeit adja vissza. Az els hívás alkalmával str a vizsgált karakterlánc kezdetét határozza meg, de minden további hívás alkalmával NULL érték adandó át. delim az (akár hívásonként eltér ) elválasztó karaktereket adja meg. Ha nem talál több szimbólumot, NULL értékkel tér vissza. Módosítja str tartalmát, '\0'-kat szúr be a szimbólumok mögé. A visszaadott területen egyetlen elválasztó karakter sem található.

Karakterlánc tokenekre bontása Lekérdez karakterlánc elemzése #include<stdio.h> #include<string.h> #define SEP "&" int main(void) { char url[] = "http://it.sze.hu/index.php?tart=hirek&old=2"; char* pk = strchr(url, '?'); char* pv; if(pk && (pk=strtok(pk+1, SEP))) { do { pv = strchr(pk, '='); if(pv) *pv = '\0'; else continue; printf("kulcs: %s, érték: %s\n", pk, pv+1); } while(pk=strtok(null, SEP)); } else { printf("az URL nem tartalmaz lekérdez karakterláncot.\n"); } return 0; }

Változó paraméterlista Legalább egy rögzített formális paraméter, majd... ezeket úgy kezeli a fordító, mintha nem adtak volna meg prototípust stdarg.h va_list típust (mutatót) és a következ függvényszer makrókat tartalmazza: void va_start(va_list ap, last); type va_arg(va_list ap, type); void va_end(va_list ap); Használat: 1 va_list típusú, pl. ap nev változó deklarálása. 2 va_start hívása ap-vel és az utolsó rögzített formális paraméter nevével (nem lehet register tárolási osztályú). Ez inicializálja ap-t. 3 Paraméterek értékének kinyerése annyi va_arg(ap, type); hívással, amennyi paramétert fogad a függvény. Ennek számát és a típusokat (type) a rögzített paraméter(ek)b l lehet tudni. ap-t automatikusan lépteti type-nak megfelel en. 4 Végül va_end(ap); hívása (ap-t is NULL-ra állítja).

Változó paraméterlista Paraméterek értékének összeadása és megjelenítése. Az utolsó aktuális paraméternek 0 érték nek kell lennie! #include <stdio.h> #include <stdarg.h> void sum(char *uzen,...) { int osszeg = 0, tag; va_list param; va_start(param, uzen); while(tag = va_arg(param, int)) osszeg += tag; va_end(param); printf(uzen, osszeg); } void main(void) { sum("1+2+3+4 = %d\n", 1, 2, 3, 4, 0); }

Változó paraméterlista Formátumsztring feldolgozása (Forrás: man 3 stdarg) #include <stdio.h> #include <stdarg.h> void foo(char *fmt,...) { va_list ap; int d; char c, *s; va_start(ap, fmt); while(*fmt) switch(*fmt++) { case 's': /* string */ s = va_arg(ap, char*); printf("string %s\n", s); break; case 'd': /* int */ d = va_arg(ap, int); printf("int %d\n", d); break; case 'c': /* char */ /*need a cast here since va_arg only takes fully promoted types*/ c = (char)va_arg(ap, int); printf("char %c\n", c); break; } va_end(ap); }

Néhány printf()-hez hasonló függvény int vprintf(const char *format, va_list ap); Hasonlóan m ködik printf()-hez, de a hívó függvény változó paraméterlistáját dolgozza fel, önállóan lépteti ap értékét va_arg hívásokkal. Egyszer példa vprintf() használatára #include<stdio.h> #include<stdarg.h> int nyomtat(const char* fmt,...) { int n; va_list ap; va_start(ap, fmt); n = vprintf(fmt, ap); va_end(ap); return n; } int main(void) { nyomtat("%s és a %d törpe\n", "Hófehérke", 7); return 0; }

Néhány printf()-hez hasonló függvény int fprintf(file *stream, const char *format,...); Mint printf(), de a szabványos kimenet helyett a stream folyamba ír. int vfprintf(file *stream, const char *format, va_list ap); Mint fprintf(), de maga dolgozza fel a hívó változó paraméterlistáját. Példa a szabványos kimenet és hibacsatorna használatára (kimenet.c) #include<stdio.h> int main(void) { printf("szabvány kimenetre.\n"); fprintf(stdout, "Szabvány kimenetre.\n"); fprintf(stderr, "Szabvány hibacsatornára.\n"); return 0; }

Néhány printf()-hez hasonló függvény kimenet-et elindítva: Szabvány kimenetre. Szabvány kimenetre. Szabvány hibacsatornára. Újabb indítás: kimenet >stdout.txt 2>stderr.txt A konzolon semmi nem jelenik meg! stdout.txt Szabvány kimenetre. Szabvány kimenetre. stderr.txt Szabvány hibacsatornára.

Néhány printf()-hez hasonló függvény int sprintf(char *str, const char *format,...); Mint printf(), de a szabvány kimenet helyett str címen helyezi el az eredményt. Az eredménynek el kell férnie ezen a helyen! int vsprintf(char *str, const char *format, va_list ap); Mint sprintf(), de maga dolgozza fel a hívó változó paraméterlistáját. A szabványos függvénykönyvtár nem tartalmaz pl. itoa() függvényt! #include<stdio.h> int main(void) { char s[128]; sprintf(s, "%d", 12345); printf("%s\n", s); return 0; }

Mutatótömbök Mutatókból álló tömbök típus* azonosító[<konstans-kifejezés>]<=inicializátorlista>; tehát az azonosító egy típus** típusú konstans mutató 0 1 2 0 1 2 3 4 5 6 7 8 9 10 11 'H' 'i' 'b' 'á' 's' ' ' 'é' 'r' 't' 'é' 'k' '\0'... 7... 0 1 2 3 4 5 6 7 8 'V' 'a' 's' 'á' 'r' 'n' 'a' 'p' '\0'

Mutatótömbök *napok napok[0] **napok *napok[0] 'H' Hét napjai #include<stdio.h> static char* napok[] = {"Hibás érték", "Hétf ", "Kedd", "Szerda", "Csütörtök", "Péntek", "Szombat", "Vasárnap"}; char* napnev(int i) { if(i<1 i>7) return *napok; return *(napok+i); } int main(void) { int i; for(i=1; i<9; i++) printf("%s\n", napnev(i)); return 0; }

Többdimenziós tömbök Tömbök tömbje, pl. mátrix: vektorokat tartalmazó vektor típus azonosító[<méret1>][méret2]...[méretn]<=inicializátorlista>; Elemek elérése: azonosító[index1][index2]...[indexn], ahol 0 <= index1 < méret1, 0 <= index2 < méret2,..., 0 <= indexn < méretn Elhelyezkedés a tárban: pl. int mtx[2][3]; esetén &mtx[0][0] < &mtx[0][1] < &mtx[0][2] < &mtx[1][0] <... < &mtx[1][2] matrix[1][2] 0 1 2 m 0 1 2 m 0 1 2 m............ matrix[0] matrix[1] matrix[n]

Többdimenziós tömbök mtx[i][j] *(mtx[i]+j) *(*(mtx+i)+j) Inicializálás: int mtx[4][3] = { { 1, 1, 1 }, { 2, 2, 2 }, { 3, 3, 3 }, { 4, 4, 4 } }; int mtx[4][3] = { 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4 }; int mtx[4][3] = { { 1, 1, 1 }, { 2, 2, 2 }, { 3, 3, 3 } }; /* mtx[3][0] == mtx[3][1] == mtx[3][2] == 0 */ int mtx[4][3] = { { 1 }, { 2 }, { 3 } } /* mtx[0][0] == 1, mtx[1][0] == 2, mtx[2][0] == 3 */ Az elemszámot csak az els dimenziónál tudja megállapítani! int mtx1[][] = { { 1, 1 }, { 2, 2 }, { 3, 3 } }; /* Hiba */ int mtx1[][2] = { { 1, 1 }, { 2, 2 }, { 3, 3 } }; /* OK */

Mátrixszorzás Mátrixszorzás: az A[a i,j ] m n és B[b i,j ] n p mátrixok szorzatán azt a C[c i,j ] m p mátrixot értjük, amelyre c i,j = a i,1 b1,j + a i,2 b2,j + + a i,n b n,j = n k=1 a i,k b k,j pelda25.c #include <stdio.h> int main(void) { int a[3][4] = { { 5, 3, -21, 42}, {44, 15, 0, 6}, {97, 6, 81, 2} }; int b[4][2] = { {22, 7}, {97, -53}, {45, 0}, {72, 1} }; int c[3][2], i, j, k; printf("mátrixok szorzása:\n\n"); for(i=0; i<3; i++) { for(j=0;j<2;j++) { c[i][j]=0; for(k=0; k<4; k++) c[i][j] += a[i][k]*b[k][j]; } } for(i=0; i<3; i++) { for(j=0; j<2; j++) printf("c[%d][%d] = %5d ", i, j, c[i][j]); printf("\n"); } return 0; }

Dátumból év napjának meghatározása és fordítva pelda26.c, 1. rész #include <stdio.h> int day_of_year(int ev, int ho, int nap); void month_day(int ev, int nap, int* pho, int* pnap); void main(void) { int ev=1992, ho=4, nap=30, evnap; evnap = day_of_year(ev, ho, nap); printf("\n%4d.%02d.%02d dátum az év %3d. napja\n", ev, ho, nap, evnap); evnap = 300; month_day(ev, evnap, &ho, &nap); printf("\n%4d év %3d. napja = %02d.%02d\n", ev, evnap, ho, nap); } static int day_tab[2][13] = { {0,31,28,31,30,31,30,31,31,30,31,30,31}, {0,31,29,31,30,31,30,31,31,30,31,30,31}};

Dátumból év napjának meghatározása és fordítva pelda26.c, 2. rész /* Éven belüli napsorszám meghatározása a dátumból */ int day_of_year(int year, int month, int day) { int i, leap; leap = year%4==0 && year%100!=0 year%400==0; for(i=1; i<month; i++) day += day_tab[leap][i]; return(day); } /* Hónap, nap meghatározása az éven belüli napsorszámból */ void month_day(int year, int yearday, int* pmonth, int* pday) { int i, leap; leap = year%4==0 && year%100!=0 year%400==0; for(i=1; yearday>day_tab[leap][i]; i++) yearday -= day_tab[leap][i]; *pmonth = i; *pday = yearday; }

B vös négyzet (magic square) Olyan (ált. 1 és n 2 közötti) egész számokat tartalmazó négyzetes mátrix, melynek minden sorösszege, minden oszlopösszege, f átlójában és mellékátlójában lév számok összege azonos. További érdekességek Albrecht Dürer: Melencolia I (részlet)

B vös négyzet (magic square) Páratlan rend b vös négyzetek konstrukciója 1 A mátrix els sorának középs oszlopába írjunk 1-et! 2 A mátrix minden további elemének értéke legyen eggyel nagyobb a korábbinál (2, 3,..., n 2 )! 3 A következ elemet úgy választjuk ki, hogy jobbra és felfelé lépünk egyet. Ha a meghatározott elem már korábban ki lett töltve, akkor az utoljára kitöltött elem alatti elemmel kell folytatni a m veletet. Ha az így meghatározott elem kívül esne a mátrixon, akkor a szemközti oldalon lév els elemet kell használni (pl. a legfels feletti sor esetén a legalsót). 1. lépés 1 6. lépés 1 6 3 5 4 2 2. lépés 1 2 7. lépés 1 6 3 5 7 4 2 3. lépés 1 3 2 8. lépés 8 1 6 3 5 7 4 2 4. lépés 1 3 4 2 9. lépés 8 1 6 3 5 7 4 9 2 5. lépés 1 3 5 4 2

B vös négyzet (magic square) Páratlan rend b vös négyzet el állítása és megjelenítése #include<stdio.h> #include<stdlib.h> #include<time.h> #define MERET 3 char varazs[meret][meret]; /* Csak páratlan rend nullmátrixszal m ködik! */ void eloallit(void) { int s=0, o=meret/2, n, i, j; for(n=1; n<=meret*meret; n++) { varazs[s][o] = n; i = s-1; if(i==-1) i=meret-1; j = o+1; if(j==meret) j=0; if(varazs[i][j]) s++; else { s = i; o = j; } } } void nyomtat(void) { int s, o; for(s=0; s<meret; s++) { for(o=0; o<meret; o++) printf("%d\t", *(*(varazs+s)+o)); putchar('\n'); } }

Véletlenszám generálás Álvéletlen számok (pseudo-random numbers) Szükséges fejfájl: stdlib.h Kezd érték: void srand(unsigned int seed);, ahol seed a kezd érték Véletlen számok: 0 int rand(void); RAND_MAX Pl. x = (double)rand()/rand_max ahol {x x R, 0 x 1} vagy x = MIN + rand()%(max-min+1) ahol {x x Z, MIN x MAX } Eltér számsorozatok el állítása eltér kezd érték pontos id! Szükséges fejfájl: time.h time_t time(time_t *t); V.t. érték: time_t (long) típusban az 1970-01-01 00:00:00 +0000 (UTC) óta eltelt másodpercek száma, amit t címen is eltárol, ha az nem NULL

B vös négyzet (magic square) Ellen rzés és véletlenszer el állítás int ellenoriz(void) { int sor[meret] = {0}, oszlop[meret] = {0}, fo=0, mellek=0, s, o; for(s=0; s<meret; s++) for(o=0; o<meret; o++) { int elem = *(*(varazs+s)+o); *(sor+s) += elem; *(oszlop+o) += elem; if(s==o) fo += elem; if(o==meret-s-1) mellek += elem; } for(s=1; s<meret; s++) { if(*sor!=*(sor+s)) return 0; if(*oszlop!=*(oszlop+s)) return 0; } return *sor==*oszlop&&*oszlop==fo&&fo==mellek; } void veletlen(void) { int s, o; for(s=0; s<meret; s++) for(o=0; o<meret; o++) *(*(varazs+s)+o) = rand()%128; }

B vös négyzet (magic square) Tesztprogram int main(void) { srand(time(null)); eloallit(); nyomtat(); printf("b vös mátrix? %s\n", ellenoriz()?"igen":"nem"); veletlen(); nyomtat(); printf("b vös mátrix? %s\n", ellenoriz()?"igen":"nem"); return 0; } Kimenet 8 1 6 3 5 7 4 9 2 B vös mátrix? Igen 104 0 61 89 102 94 40 40 6 B vös mátrix? Nem