Programozás Mérnököknek (GKNB MSTM005)

Preview:

Citation preview

Programozás Mérnököknek(GKNB_MSTM005)

Takács Gábor<gtakacs@sze.hu>

Széchenyi István EgyetemMatematika és Számítástudomány Tanszék

1 / 94

A számítógép felépítése

I A számítógép legfontosabb logikai alkotóelemei a processzor,a memória és a perifériák.

I A processzor utasításokat és adatokat olvas be a memóriából,végrehajtja az utasításokat az adatokon, és esetenként azeredményt visszaírja a memóriába.

I A perifériák (pl. háttértár, billentyűzet, képernyő) kibővítik aszámítógép képességeit, és lehetővé teszik a külvilággal valókommunikációt.

2 / 94

A memória

I A számítógép memóriája címezhető memóriaelemekből(rekeszekből) tevődik össze. A memóriaelemek mérete alegtöbb mai számítógépben 1 bájt (= 8 bit).

I A memóriacímeket és a memóriatartalmat általábanhexadecimális formában szokás megadni (pl. mondhatunkolyat, hogy a 4b00 címen található érték 1f).

3 / 94

Milyen nyelven ért a számítógép?

1 ...2

3 8b 04 25 90 08 60 00 # másolás a 600890 memóriacímről4 # az eax regiszterbe5

6 8b 1c 25 94 08 60 00 # másolás a 600894 memóriacímről7 # az ebx regiszterbe8

9 01 c3 # eax és ebx értékének összeadása,10 # és az eredmény beírása ebx-be11

12 89 1c 25 98 08 60 00 # ebx tartalmának másolása13 # a 600898 memóriacímre14 ...

4 / 94

A teafőzés algoritmusa

I Bemenet: forraló, csésze, teafilter, cukorI Kimenet: egy csésze teaI Lépések:

1. Önts vizet a forralóba!2. Kapcsold be a forralót!3. Forr már a víz?

I Ha nem, akkor várj 1 percet, ésfolytasd a 3. lépéstől!

I Ha igen, akkor folytasd a 4. lépéstől!

4. Töltsd meg a csészét forró vízzel!5. Tedd bele a teafiltert!6. Kérsz hozzá cukrot?

I Ha igen, akkor tegyél bele!

5 / 94

Programozási alapfogalmak

I Algoritmus: Valamely probléma megoldására alkalmas végeshosszú lépéssorozat.

I Adatszerkezet: Adatelemek tárolására és hatékonyhasználatára szolgáló séma (példa: tömb).

I Programozási nyelv: Szigorú szabályokra épülő nyelv,melynek segítségével az ember képes a számítógép felékommunikálni az utasításait.

I Programozás: Algoritmusok és adatszerkezetek megtervezéseilletve megvalósításuk valamilyen programozási nyelven(kódolás).

6 / 94

vs.„keyboard monkey” „igazi programozó”

7 / 94

A C nyelv története

A kezdeti fejlesztések az AT&T Bell Laboratóriumában történtek.A nyelv története szorosan kapcsolódik a UNIX operációs rendszertörténetéhez.

I A C nyelv közvetlen elődje a BCPL (1966) és a B (1969).I 1969: Ritchie és Thompson elkezdenek dolgozni a nyelven.I 1973: A UNIX rendszermagját újraírják C-ben.I 1978: Megjelenik Kernighan és Ritchie „C bibliája”.

8 / 94

Dennis Ritchie (jobbra) és Ken Thompson,a C nyelv megalkotói.

9 / 94

A C nyelv jellemzői

I Általános célú programozási nyelv.I Kevés nyelvi elem és tömör utasításformák jellemzik.I Megtalálhatók benne a strukturált programozáshoz szükséges

vezérlési szerkezetek.I Alacsony szintű, ezért nagy hatékonyságú programok

készíthetők benne és hardverprogramozásra is alkalmas.I Nem korlátozza a programozó szabadságát.

„C is quirky, flawed, and an enormous success.”(Ritchie)

10 / 94

Prominens alkalmazások

I C:- operációs rendszer kernelek(pl. Windows, OS X, Linux, Android, iOS)

- rengeteg eszközmeghajtó és beágyazott szoftver- CPython, PostgreSQL- ...

I C/C++:- Chrome, Firefox, Internet Explorer- MS Office, Photoshop, Acrobat, VLC- HotSpot JVM, Oracle Database, MySQL- ...

11 / 94

C fordítók

I GCC: GNU Compiler Collection. Tartalmaz C, C++,Objective-C, Fortran, Java, Ada valamint Go fordítót.

I Clang: Az LLVM projekt C, C++, Objective-C és ObjectiveC++ fordítója. A GCC-nél kevésbé elterjedt, defelhasználóbarátabbak a hibaüzenetei.

I Visual C++: A Microsoft integrált fejlesztői környezete,amely C és C++ fordítót is tartalmaz.

I Intel C++: Az Intel C és C++ fordítója, amely Intelprocesszorokra optimalizált kódot készít.

I ...

A kurzus során Clanget fogunk használni.

12 / 94

Szabványos C

Kezdetben annyiféle C nyelv létezett, ahány C fordító. Idővelmegkezdődött a nyelv szabványosítása.

I K&R C (Kernighan és Ritchie 1978-as könyve alapján)I ANSI C (ANSI X3.159-1989 szabvány)I C90 (ISO/IEC 9899:1990 szabvány)I C99 (ISO/IEC 9899:1999 szabvány)I C11 (ISO/IEC 9899:2011 szabvány)

A kurzus során ANSI C-t fogunk használni,néhány C99 kiterjesztéssel.1

1Pl. egysoros komment, nem blokk eleji változódeklaráció.13 / 94

Fejlesztőkörnyezetek

I Nehézsúlyú:- Visual Studio- NetBeans- Eclipse- Code::Blocks- ...

I Könnyűsúlyú:- Emacs- Vim- SciTE- Notepad++- https://repl.it/- ...

A kurzus során a saját fejlesztésű https://cprog-ide.org/környezetet fogjuk használni.

14 / 94

Hello, World!

1 #include <stdio.h>2 int main() {3 printf("Hello, World!\n");4 return 0;5 }

hello.c

I #include <stdio.h>: Lehetővé teszi a printf kiíró függvényhasználatát.

I int main() {: A C nyelvű programok végrehajtása a mainfüggvény elejétől indul. Az int azt jelzi, hogy a függvény egészszámot ad vissza.

I printf("Hello, World!\n");: Kiírja a standard kimenetre a„Hello, World!” szöveget valamint egy újsor karaktert.

I return 0;: Kilép a programból, 0-ás kilépési kóddal.

15 / 94

Előfeldolgozás ⇒ Fordítás ⇒ Linkelés

1. Előfeldolgozás: Forráskódból forráskódot készít.

1 clang -E hello.c > hello_preprocessed.c

2. Fordítás: Forráskódból tárgykódot készít.

1 clang -c hello_preprocessed.c -o hello.o

3. Linkelés: Tárgykódokból futtatható állományt készít.

1 clang hello.o -o hello

I Az összes fázis futtatása:

1 clang hello.c -o hello

16 / 94

17 / 94

Nyelvtan

- Azt, hogy mi számít formailag helyes ANSI C programnak, aszabványban szereplő formális nyelvtan definiálja (lásd:https://www.lysator.liu.se/c/ANSI-C-grammar-y.html).

- A megjegyzéseket az előfeldolgozó törli a programból, így ezeknem szerepelnek a nyelvtanban.

1 /* többsoros2 megjegyzés */

1 // egysoros megjegyzés (nem része az ANSI C-nek)

- Ha a C program egy pontján állhat fehér karakter (szóköz,tabulátor, újsor, stb.), akkor tetszőleges számú állhat ott.

- Ha egy program nem felel meg a nyelvtannak, akkor szintaktikailaghibás. Ha egy program nem azt csinálja, amit várnánk tőle (hanemazt, amire utasítottuk), akkor szemantikailag hibás.

18 / 94

Azonosítók

I Az azonosítók (változók, függvények, adattípusok nevei)alfanumerikus karaktereket valamint aláhúzásttartalmazhatnak, és nem kezdődhetnek számjeggyel.

- Alfanumerikus karakternek az angol ABC kis és nagybetűivalamint a számjegyek számítanak.

- A kis- és nagybetűk különbözőnek számítanak!- Néhány érvényes azonosító: line1, _getFirst, MAX_SIZE.- Néhány érvénytelen: $foo, 7dwarfs, get-first.

I A nyelv kulcsszavai nem használhatók azonosítóként.- Az ANSI C kulcsszavak listája: auto, break, case, char,const, continue, default, do, double, else, enum,extern, float, for, goto, if, int, long, register,return, short, signed, sizeof, static, struct,switch, typedef, union, unsigned, void, volatile,while.

19 / 94

Egyszerű adattípusok

A C nyelv alapvető adattípusai:char Egyetlen bájt.int Egész szám (mérete architektúrafüggű).

float Egyszeres pontosságú lebegőpontos szám.double Kétszeres pontosságú lebegőpontos szám.

Típusminősítők:I signed, unsigned (egész típusokhoz)I short, long (egész típusokhoz)

20 / 94

Egyszerű adattípusok

Az adattípusok méretének feltérképezése:

1 #include <stdio.h>2 int main() {3 printf("char: %i\n", sizeof(char));4 printf("short: %i\n", sizeof(short));5 printf("int: %i\n", sizeof(int));6 printf("long: %i\n", sizeof(long));7 printf("float: %i\n", sizeof(float));8 printf("double: %i\n", sizeof(double));9 return 0;

10 }

21 / 94

Literálok

I Egész literálok:- decimális megadás: 42, 123, ...- oktális megadás: 052, 0173, ...- hexadecimális megadás: 0x2a, 0x7b, ...(0X előtag ill. A-F karakterek is megengedettek)

- unsigned (u vagy U) utótag: 42u, 123U, ...- long (l vagy L) utótag: 42l, 123L, ...

I Karakteres literálok:- ASCII karakterek: ’A’, ’b’, ’1’, ...- escape szekvenciák: ’\t’, ’\r’, ’\n’, ’\0’, ’\0x7b’, ...

I Lebegőpontos literálok:- double állandók: 1.2, 1E-6, 5.1e3, ...- float állandók: 1.2f, 1E-6f, 5.1e3F, ...- long double állandók: 1.2l, 1E-6l, 5.1e3L, ...

22 / 94

Deklarációk

I Változó: Névvel ellátott memóriaterület.I A felhasználása előtt minden változót deklarálni kell.

- A változódeklaráció formátuma:

1 TÍPUS NÉV1 = ÉRTÉK1, NÉV2 = ÉRTÉK2, ...

- A kezdeti értékadás opcionális. Példa:

1 char c;2 int i, j, counter = 0;3 double epsilon = 1e-6;

23 / 94

Tömbök

I Tömb: Azonos típusú elemek sorozata, ahol az elemeket asorszámukon (index) keresztül érhetjük el. A C nyelvben atömbök indexe nullától indul.

1 int a[3];2 a[0] = 10;3 a[1] = 20;4 a[2] = 30;

I A tömböt kezdeti értékekkel is fel lehet tölteni:

1 int a[] = {10, 20, 30};2 double b[10] = {1.1, 2.2};

I Ezután a tömbváltozónak nem adhatunk többé értéket!(A tömb elemeit természetesen megváltoztathatjuk.)

24 / 94

Sztringek

I Sztring (karakterlánc): ’\0’ karakterrel végződő karaktertömb.

1 char s[] = "hello";2 // s[0]: 'h'3 // s[1]: 'e'4 // s[2]: 'l'5 // s[3]: 'l'6 // s[4]: 'o'7 // s[5]: '\0'

I Kiírás a standard kimenetre:

1 printf("%s\n", s);

25 / 94

Operátorok

I Aritmetikai: + - * / %I Összehasonlító: > >= < <= == !=I Logikai: ! && ||I Inkrementáló és dekrementáló: ++ --I Bitenkénti logikai: & | « » ^ ~

I Értékadó: = += -= *= /= %= «= »= &= ?= |=

Kifejezés: Minden, ami operátorokból és operandusokbólfelépíthető (példa: 2 * 3 + 5). Egy kifejezés értékét a kifejezéskiértékelésével állíthatjuk elő.

26 / 94

Operátorok precedenciájaOperátor Kiértékelés iránya() [] -> balról jobbra! ? ++ -- + - * & (type) sizeof jobbról balra* / % balról jobbra+ - balról jobbra« » balról jobbra< <= > >= balról jobbra== != balról jobbra& balról jobbra? balról jobbra| balról jobbra&& balról jobbra|| balról jobbra?: jobbról balra= += -= *= /= %= &= ?= |= «= »= jobbról balra

I Az operátorok csökkenő precedencia szerint vannak felsorolva,azaz a táblázatban feljebb találhatók erősebben kötnek.

I Az egyoperandusú +, - és * operátorok nagyobbprecedenciájúak, mint a kétoperandusú operátorok.

27 / 94

Példák operátorokra

1 #include <stdio.h>2 int main() {3 printf("%f\n", 5.0 / 2.0); // => 2.54 printf("%i\n", 5 / 2); // => 25 printf("%i\n", 5 % 2); // => 16

7 printf("%i\n", 42 == 42); // => 18 printf("%i\n", 10 && 20 || 0); // => 19

10 int i = 10;11 printf("%i\n", ++i); // => 1112 printf("%i\n", i--); // => 1113 printf("%i\n", 0x07 & 0x1c); // => 414 printf("%i\n", 0x07 | 0x1c); // => 3115 return 0;16 }

28 / 94

Mohó és lusta kiértékelés

I Egy művelet elvégzéséhez általában szükséges az operandusokelőzetes kiértékelése (példa: 2 * 3 + 4 * 5).

I A logikai && és || művelet esetén a második operandus nemértékelődik ki, amennyiben nem befolyásolhatja az eredményt!

29 / 94

Típuskonverzió

I Automatikus:- Ha egy művelet operandusai nem azonos típusúak, akkor a„szélesebb” típuson értelmezett művelet hajtódik végre.

- Gyakori hiba: Lebegőpontos osztást szeretnénk, de egésztípusúak az operandusok.

1 double a = 1 / 2; // => 0.02 double b = 1.0 / 2; // => 0.5

I Kényszerített:

1 double c = (double) 1 / 2; // => 0.52 double d = (int) 0.5 / 2.0; // => 0.0

30 / 94

Példa: Celsius–Fahrenheit átalakítás1 #include <stdio.h>2 int main() {3 int c, f; // A hőmérsékleteket int-ben tároljuk.4 scanf("%i", &c);5 fahr = 9 * c / 5 + 32; // A törtrész elveszik!6 printf("%i\n", f);7 return 0;8 }

⇒1 #include <stdio.h>2 int main() {3 float c, f; // A hőmérsékleteket float-ban tároljuk.4 scanf("%f", &cels);5 fahr = 9 * c / 5 + 32; // A törtrész megmarad.6 printf("%f\n", f);7 return 0;8 }

31 / 94

Utasítások és blokkok

I Az utasítások a program alapvető építőelemei.I Egy utasítás lehet...

I egyszerű,

1 printf("Hello, World!\n");

I összetett (blokk).

1 {2 printf("Hello, ");3 printf("World!");4 printf("\n");5 }

I A pontosvessző része az egyszerű utasításnak.I Önmagában álló pontosvessző: ÜRES UTASÍTÁS!

32 / 94

Elágazás: if utasítás

1 if (KIFEJEZÉS)2 UTASÍTÁS13 else4 UTASÍTÁS2

Megjegyzés: Az else ág elhagyható.

33 / 94

Példa if utasításra

1 #include <stdio.h>2 int main() {3 // Kérünk a felhasználótól egy évszámot.4 int y;5 scanf("%i", &y);6

7 // Kiírjuk, hogy szökőév-e.8 if (y % 4 == 0 && y % 100 != 0 || y % 400 == 0) {9 printf("Szokoev!");

10 }11 else {12 printf("Nem szokoev.");13 }14 return 0;15 }

34 / 94

Többirányú elágazás if utasításokkalI A többirányú elágazás megvalósítható több kétirányúval:

1 if (KIFEJEZÉS1)2 UTASÍTÁS13 else4 if (KIFEJEZÉS2)5 UTASÍTÁS26 else7 UTASÍTÁS3

I Ugyanez más írásmóddal:

1 if (KIFEJEZÉS1)2 UTASÍTÁS13 else if (KIFEJEZÉS2)4 UTASÍTÁS25 else6 UTASÍTÁS3

35 / 94

Többirányú elágazás if utasításokkal

I Példa többirányú elágazásra:

1 #include <stdio.h>2 int main() {3 float t;4 scanf("%f", &t);5 if (t < 0) { printf("Jeg.\n"); }6 else if (t < 100) { printf("Viz.\n"); }7 else { printf("Goz.\n"); }8 return 0;9 }

I Az else ág a közvetlenül megelőző if utasításhoz tartozik!

1 if (n < 10)2 if (n > 5) printf("5 es 10 kozotti.\n");3 else printf("Legalabb 10.\n"); // HIBÁS!!!

36 / 94

Többirányú elágazás switch utasítással

1 switch (KIFEJEZÉS) {2 case KONSTANS1:3 UTASÍTÁSOK14 case KONSTANS2:5 UTASÍTÁSOK26 ...7 default:8 UTASÍTÁSOK9 }

37 / 94

Többirányú elágazás switch utasítással

38 / 94

Példa switch utasításra

1 #include <stdio.h>2 int main() {3 char answer;4 printf("Szeretnel-e jelest programozasbol? ");5 scanf("%c", &answer);6 switch (answer) {7 case 'i':8 case 'I':9 printf("Akkor gyakorolj!\n");

10 break;11 case 'n':12 case 'N':13 printf("Helytelen a hozzaallasod.\n");14 break;15 default:16 printf("Ervenytelen valasz.\n");17 }18 return 0;19 }

39 / 94

Feltételes kifejezések

1 if (a > b)2 z = a;3 else4 z = b;

A fenti programrészlet hatására z az a és b értékek közül anagyobbikat veszi fel. Ilyen és hasonló szerkezetek egyszerűbben ismegvalósíthatók K1 ? K2 : K3 alakú feltételes kifejezéssel:

1 z = a > b ? a : b;

Először a K1 kifejezés értékelődik ki. Ha értéke nem nulla, akkorK2, egyébként K3 értékelődik ki, és lesz a feltételes kifejezés értéke.

40 / 94

Elöltesztelő ciklus: while utasítás

1 while (KIFEJEZÉS)2 UTASÍTÁS

41 / 94

Példa: Móricka a programozás vizsgán (while-lal)

1 #include <stdio.h>2 int main() {3 int p = -1; // A vizsgán elért pontszám.4 while (p < 16) { // Amíg a pontszám 16-nál kisebb...5 printf("\nMenj el a kovetkezo vizsgara!\n");6 printf("Hany pontot ertel el? ");7 scanf("%i", &p);8

9 if (p < 16) {10 printf("Ejnyebejnye, nem tanultal eleget.\n");11 }12 }13

14 printf("GRATULALOK, atmentel!\n");15 return 0;16 }

42 / 94

Elöltesztelő ciklus: for utasítás

1 for (KIFEJEZÉS1; KIFEJEZÉS2; KIFEJEZÉS3)2 UTASÍTÁS

43 / 94

Példa: Celsius–Fahrenheit táblázat for ciklussal

1 #include <stdio.h>2 int main() {3 printf("Celsius Fahrenheit\n"); // Fejléc kiírása.4 for (float c = -40; c <= 40; c += 5) {5 float f = 9 * c / 5 + 32; // Konvertálás.6 printf("%6.1f %6.1f\n", c, f); // Egy sor kiírása.7 }8 return 0;9 }

44 / 94

Hátultesztelő ciklus: do utasítás

1 do2 UTASÍTÁS3 while (KIFEJEZÉS);

45 / 94

Példa: Móricka a programozás vizsgán (do-val)

1 int main() {2 int p = -1; // A vizsgán elért pontszám.3 do {4 printf("\nMenj el a kovetkezo vizsgara!\n");5 printf("Hany pontot ertel el? ");6 scanf("%i", &p);7

8 if (p < 16) {9 printf("Ejnyebejnye, nem tanultal eleget.\n");

10 }11 } while (p < 16); // Amíg a pontszám 16-nál kisebb...12

13 printf("GRATULALOK, atmentel!\n");14 return 0;15 }

46 / 94

A break és continue utasítások

I break: Kilép az aktuális for, while, do vagy switch utasításból.

1 // Négyzetszámok kiírása while-lal és break-kel.2 // (Lehetne egyszerűbben is, a szemléltetés kedvéért csináljuk így.)3 int i = 1;4 while (1) {5 if (i > 10) { break; }6 printf("%i\n", i * i);7 i++;8 }

I continue: A következő iterációra lép az aktuális for, whilevagy do utasításban.

1 // Páros négyzetszámok kiírása continue-val.2 // (Lehetne egyszerűbben is, a szemléltetés kedvéért csináljuk így.)3 for (int i = 1; i <= 10; i++) {4 if (i % 2 == 1) { continue; }5 printf("%i\n", i * i);6 }

47 / 94

for, while vagy do?

I Bármely ciklus bármelyik utasítással megvalósítható.I for vagy while?

- Ha előre tudjuk az iterácók számát, akkor inkább for utasítástalkalmazzunk! Példa: az első 10 négyzetszám kiírása.

- Egyébként használjunk while utasítást! Példa: számkitalálósjáték - addig tart, amíg a felhasználó el nem találja a gép általkisorsolt számot.

I while vagy do?- A megvalósítandó algoritmus logikájától függ, hogy melyikeredményez tömörebb kódot...

- ...de a gyakorlatban a while utasítás sokkal elterjedtebb.

48 / 94

Standard adatfolyamok

Az operációs rendszer minden program számára létrehoz 3 standardadatfolyamot a külvilággal való kommunikációra:

I Standard bemenet (stdin): Bemeneti adatfolyam,alapértelmezés szerint a billentyűzettel van összekötve.

I Standard kimenet (stdout): Kimeneti adatfolyam,alapértelmezés szerint a képernyőre íródik.

I Standard hibakimenet (stderr): Alternatív kimenetiadatfolyam, alapértelmezés szerint a képernyőre íródik.

49 / 94

Standard adatfolyamok: Átirányítás

A standard adatfolyamok összekapcsolhatók fájlokkal...

1 program < in.txt // A bemenet az in.txt-ből érkezik.2 program > out.txt // A kimenet az out.txt-be íródik.3 program 2> err.txt // A hibakimenet az err.txt-be íródik.

1 program >> out.txt // A kimenet az out.txt végére íródik.2 program 2>> err.txt // Hibakimenet az err.txt végére íródik.

...illetve egyéb programokkal:

1 program1 | program2 > out.txt2 // Az 1. program kimenete lesz a 2. program bemenete.3 // A 2. program kimenete az out.txt-be íródik.

50 / 94

Standard adatfolyamok: Pufferelés

I Pufferelés nélküli adatfolyamoknál a beolvasott vagy kiírtbájtok azonnal továbbítódnak.

I Soronként pufferelt adatfolyamoknál a továbbítás sorvégekarakter beérkezése esetén történik meg.

I Teljesen pufferelt adatfolyamoknál a továbbítás adottmennyiségű bájt beérkezése esetén történik meg.

51 / 94

Standard adatfolyamok kezelése C-ben

1 #include <stdio.h>2 int main() {3 char c = getchar(); // 1 karakter beolvasása4 putchar(c); // 1 karakter kiírása5

6 char s[100];7 gets(s); // NE HASZNÁLJUK, VESZÉLYES!8 fgets(s, 100, stdin); // 1 sor beolvasása helyesen9

10 printf("hello"); // írás stdout-ra11 fprintf(stdout, "hello"); // ugyanez másképp12 fflush(stdout); // puffer ürítése13

14 fprintf(stderr, "ERROR!\n"); // írás stderr-re15 return 0;16 }

52 / 94

Printf formátumleírók2

I Felépítés: %[jelzők][szélesség][.pontosság][hossz]típusI A típus mező leggyakoribb értékei:

típus leírás példad, i előjeles decimális egész 124u előjel nélküli decimális egész 7235x, X előjel nélküli hexadecimális egész 7faf, F decimális lebegőpontos 392.65e, E tudományos írásmód 3.9265e+2g, G az előző kettő közül a rövidebb 392.65c karakter ’a’s sztring "sample"p memóriacím b8000000% ’%’ karakter

I pontosság: Hány tizedesjegyre kerekítsünk?I hossz: h (short) vagy l (long).

2További részletek: http://en.cppreference.com/w/c/io/fprintf53 / 94

Kilépési kód

A programok kilépéskor egy egész számot adnak vissza aszülőfolyamat számára. A hibamentes lefutást 0-val szokás jelezni.

1 #include <stdio.h>2 int main() { // <= a main visszatérési értéke int!3 printf("hello\n");4 return 0; // <= itt adjuk meg kilépési kódot5 }

A kilépési kódot más programok felhasználhatják:

1 ./hello && echo "rendben lefutott"2 ./hello || echo "hiba történt!"

54 / 94

Függvények

I Függvény: névvel ellátott alprogram, amely a program másrészeiből meghívható.

I Függvények használatával a számítási feladatok kisebbegységekre oszthatók. A gyakran használt függvények kódjátkönyvtárakba rendezhetjük (példa: standard C könyvtár).

I A matematikában egy függvénynek nincsenek mellékhatásai.Egy C nyelvű függvénynek lehetnek!

I C-ben a függvények egyetlen közös névtérben vannak.Függvénydefiníciók nem ágyazhatók egymásba.

55 / 94

Függvények: Mintapélda

1 #include <stdio.h>2 #include <math.h>34 /* Derékszögű háromszög átfogójának kiszámítása. */5 float hypotenuse(float a, float b) {6 float c = sqrt(a * a + b * b);7 return c;8 }9

10 int main() {11 // 1. teszteset12 printf("%f\n", hypotenuse(3, 4));1314 // 2. teszteset15 float a = 5, b = 6;16 printf("%f\n", hypotenuse(a, b));1718 return 0;19 }

56 / 94

Paraméterátadás, lokális változók

I Függvényhíváskor érték szerint paraméterátadás történik,azaz a paraméterben megadott kifejezés kiértékelődik, és akiértékelődés eredményét kapja csak meg a függvény.

I Egy függvény paraméterei és lokális változói nem érhetők ela többi függvény számára, és a függvényből való visszatéréskormegsemmisülnek (kivéve a static kulcsszóval deklaráltváltozókat).

57 / 94

Deklaráció és definíció

square.c

1 double square(double x) {2 return x * x;3 }

gravity.c

1 /* Két test között fellépő gravitációs erő kiszámítása. */2 double gravity(double m1, double m2, double r) {3 return 6.67428e-11 * m1 * m2 / square(r);4 }

I A C fordító egymástól függetlenül fordítja le a forrásfájlokat.I A gravity függvény fordításakor hogyan deríthető ki a

square függvény bemenetének és kimenetének típusa?

58 / 94

Deklaráció és definíció

square.c

1 double square(double x) { // <= függvénydefiníció2 return x * x;3 }

gravity.c

1 double square(double x); // <= függvénydeklaráció2

3 /* Két test között fellépő gravitációs erő kiszámítása. */4 double gravity(double m1, double m2, double r) {5 return 6.67428e-11 * m1 * m2 / square(r);6 }

I Nagyobb projektek esetén a függvénydeklarációkat header (.h)fájlokban szokás elhelyezni.

59 / 94

Deklaráció és definíció

square.h1 #ifndef _SQUARE_H2 #define _SQUARE_H3 double square(double x);4 #endif

square.c1 double square(double x) {2 return x * x;3 }

gravity.c1 #include "square.h"23 /* Két test között fellépő gravitációs erő kiszámítása. */4 double gravity(double m1, double m2, double r) {5 return 6.67428e-11 * m1 * m2 / square(r);6 }

60 / 94

Rekurzív függvények

1 #include <stdio.h>2

3 /* Az n. Fibonacci-szám kiszámítása. */4 int fibonacci(int n) {5 if (n <= 2) { return 1; }6 else {7 return fibonacci(n - 1) + fibonacci(n - 2);8 }9 }

10

11 int main() {12 printf("%i\n", fibonacci(1));13 printf("%i\n", fibonacci(3));14 printf("%i\n", fibonacci(5));15 return 0;16 }

61 / 94

MakróhelyettesítésI Legegyszerűbb formája:

1 #define NEV helyettesito szoveg

Az előfeldolgozó megadott név minden előfordulási helyérebeírja a helyettesítő szöveget.

I Ha a helyettesító szöveg egyetlen literál, akkor a makrószimbolikus állandót definiál. Példa:

1 #include <stdio.h>2

3 #define MAXLEN 1004

5 int main() {6 char s[MAXLEN];7 fgets(s, MAXLEN, stdin); // 1 sor beolvasása8 return 0;9 }

62 / 94

Paraméteres makrók

1 #include <stdio.h>2

3 #define square1(x) x * x /* HIBÁS! */4 #define square2(x) ((x) * (x))5

6 int main() {7 int y = 3;8 printf("%i\n", square1(y + 1)); // => 79 printf("%i\n", square2(y + 1)); // => 16

10 printf("%i\n", square2(y++)); // => ? (fordítófüggő)11 printf("%i\n", y); // => 5 (y kétszer növelődött!)12 return 0;13 }

63 / 94

C forrásfájlok szokásos felépítése

1 függvénydeklarációk // gyakran #include-dal2 ... // illesztődnek be3

4 adattípus deklarációk // gyakran #include-dal5 ... // illesztődnek be6

7 globális változók deklarációja8 ...9

10 függvénydefiníciók // ezek tartalmazzák11 ... // az utasításokat

64 / 94

C forrásfájlok szokásos felépítése

pelda.c1 // függvénydeklarációk2 float square(float z);34 // adattípusok deklarációja5 struct Point {6 float x;7 float y;8 };9

10 // globális változók deklarációja11 int a = 10;12 char b[] = "hello";1314 // függvénydefiníciók15 float square(float z) {16 return z * z;17 }

65 / 94

Mutatók

I Mutató: Memóriacím tárolására alkalmas speciális változó. Amutatóhoz a megcímzett memóriaterületen található adattípusa is hozzátartozik (kivétel: void *).

I A mutatók használata a címképzés (&) és az indirekció (*)operátoron keresztül történik.

1 int c; // int típusú változó2 int *pc; // int típusú adatot megcímző mutató3

4 c = 5;5 pc = &c; // pc mostantól c-re mutat6 *pc = 2; // c értéke 2 lesz

66 / 94

Mutatók

67 / 94

Mutatók és függvényargumentumok1 #include <stdio.h>23 /* Két int típusú változó értékének megcserélése HIBÁSAN. */4 void swap1(int a, int b) {5 int tmp = a;6 a = b;7 b = tmp;8 }9 /* Két int típusú változó értékének megcserélése helyesen. */

10 void swap2(int *a, int *b) {11 int tmp = *a;12 *a = *b;13 *b = tmp;14 }1516 int main() {17 int x = 1, y = 2;18 swap1(x, y); // <= Nincs csere az érték19 printf("x=%i, y=%i\n", x, y); // szerinti paraméterátadás miatt!20 swap2(&x, &y); // <= Megtörténik a csere.21 printf("x=%i, y=%i\n", x, y);22 return 0;23 }

68 / 94

Mutatók és tömbök

I Egy tömb neve a nulladik elemének a memóriacímét jelenti.I Minden művelet, ami tömbindexeléssel elvégezhető,

megvalósítható mutatók segítségével is.I A mutatót használó változat bizonyos esetekben gyorsabb

lehet, de általában nehezebben olvasható.

tömbváltozó mutatóváltozó

megcímzett területlefoglalása

automatikus malloc függvénnyel

megcímzett területfelszabadítása

automatikus free függvénnyel

értékadás nem lehetséges3 lehetséges

3A kezdeti értékadást kivéve.69 / 94

Mutatók és tömbök

1 char s1[] = "hello"; // tömbváltozó2 char *s2 = s1; // a tömbváltozóval (majdnem)3 // egyenértékű mutatóváltozó4

5 // Az indexelés s1-re és s2-re is működik.6 putchar(s1[2]); // => 'l'7 putchar(s2[2]); // => 'l'8

9 // A címaritmetika s1-re és s2-re is működik.10 putchar(*(s1 + 2)); // => 'l'11 putchar(*(s2 + 2)); // => 'l'12

13 // s2-nek adhatunk értéket, de s1-nek nem!14 s2 = 0;

70 / 94

Címaritmetika

1 int a[] = {10, 11, 12, 13, 14, 15, 16, 17};2 int *p = a;3

4 printf("%i\n", *p); // => 105 printf("%i\n", *(p + 3)); // => 136 p++; // p mutasson a következő elemre!7 printf("%i\n", *p); // => 118 p += 3; // p mutasson az aktuális elem utáni 3. elemre!9 printf("%i\n", *p); // => 14

10 printf("%i\n", p[1]); // => 15

71 / 94

Mutatók és sztringek

1 /* Az s sztring hosszának lemérése. */2 int mystrlen(char *s) {3 int n = 0;4 while (s[n] != '\0') { n++; }5 return n;6 }

1 /* A t sztring tartalmának másolása s-be. */2 void mystrcpy(char *s, char *t) {3 while ((*s = *t) != '\0') {4 s++;5 t++;6 }7 }

72 / 94

Mutatókat megcímző mutatók

1 char c0[] = "red";2 char c1[] = "green";3 char c2[] = "blue";4

5 char *colors1[] = { c0, c1, c2 };6 char **colors2 = colors1; // karaktert megcímző mutatót7 // megcímző mutató8

9 printf("%s\n", colors2[0]);10 printf("%s\n", colors2[1]);11 printf("%s\n", colors2[2]);12

13 colors2 = 0; // colors2-nek adhatunk értéket,14 // de colors1-nek nem!

73 / 94

Parancssori argumentumok

1 #include <stdio.h>2 int main(int argc, char **argv) {3 // Ha a programot argumentum nélkül futtatják,4 // akkor kiírunk egy használati utasítást.5 if (argc < 2) {6 printf("HASZNALAT: %s e|d|k|n\n", argv[0]);7 return 1;8 }9

10 // Vesszük az 1. argumentum 0. karakterét.11 char c = argv[1][0];12 // (A 0. argumentum a program neve, utána következnek13 // a felhasználói által megadott argumentumok.)1415 if (c == 'e') { printf("eszak\n"); }16 else if (c == 'd') { printf("del\n"); }17 else if (c == 'k') { printf("kelet\n"); }18 else if (c == 'n') { printf("nyugat\n"); }19 return 0;20 }

74 / 94

Többdimenziós tömbök1 #include <stdio.h>2 int main() {3 char world[4][5] = {4 {'#', '#', '#', '#', '#'},5 {'#', '.', '#', '.', '#'},6 {'#', '.', '#', '.', '#'},7 {'#', '@', '.', '.', '#'},8 };9

10 int row = 3, col = 1; // a játékos (@) pozíciója11 putchar(world[row][col - 1]); // => #12 putchar(world[row - 1][col]); // => .13

14 char* actrow = world[row];15 for (int c = 0; c < 5; c++) { putchar(actrow[c]); }16 // => #@..#17 return 0;18 }

75 / 94

Struktúrák

I Struktúra: Változók együttese, amelyet a kényelmeskezelhetőség céljából önálló névvel látunk el.

I A struktúrák lehetővé teszik, hogy az egymással kapcsolatbanlévő változók csoportját egyetlen egységként kezeljük.

I A változóknak (másnéven tagoknak) nem kell azonostípusúaknak lenniük.

1 struct Student {2 char name[100];3 char id[7];4 int birthyear;5 };

76 / 94

Struktúrák használata1 #include <stdio.h>2 #include <math.h>3

4 struct Vector { // 2 dimenziós vektor tárolására5 float x; // alkalmas adatszerkezet6 float y;7 };8

9 int main() {10 struct Vector v;11 printf("x: ");12 scanf("%f", &v.x); // x koordináta beolvasása13 printf("y: ");14 scanf("%f", &v.y); // y koordináta beolvasása15 float length = sqrt(v.x * v.x + v.y * v.y);16 printf("a vektor hossza: %f\n", length);17 return 0;18 }

77 / 94

Struktúrákat megcímző mutatók

1 #include <stdio.h>2 #include <math.h>34 struct Vector { // 2 dimenziós vektor tárolására5 float x; // alkalmas adatszerkezet6 float y;7 };89 float calclength(struct Vector *v) {

10 return sqrt(v->x * v->x + v->y * v->y);11 }1213 int main() {14 struct Vector v;15 printf("x: ");16 scanf("%f", &v.x); // x koordináta beolvasása17 printf("y: ");18 scanf("%f", &v.y); // y koordináta beolvasása19 printf("a vektor hossza: %f\n", calclength(&v));20 return 0;21 }

78 / 94

A typedef utasítás

I A C typedef utasításával új adattípus neveket hozhatunk létre.I Szintaxis: typedef adattípus név;I Példák:

1 typedef struct Vector Vector;2 // Mostantól a struct Vector adattípusra3 // Vector néven is hivatkozhatunk.4

5 typedef float scalar;6 // Mostantól a float adattípusra7 // scalar néven is hivatkozhatunk.

79 / 94

A standard C könyvtár elemei

<ctype.h> Karakterosztályozó függvények.<float.h> Lebegőpontos típusokkal kapcsolatos állandók.

<limits.h> Egész típusokkal kapcsolatos állandók.<stdio.h> Bemenettel és kimenettel kapcsolatos függvények.

<stdlib.h> Típuskonverziós, véletlenszám-generáló, rendező,kereső, memória-allokáló és egyéb függvények.

<math.h> Alapvető matematikai függvények.<string.h> Sztringkezelő függvények.

<time.h> Dátum- és időkezelő függvények....

80 / 94

<ctype.h>

I Függvényeket tartalmaz annak tesztelésére, hogy egy karakteralfanumerikus-e (isalnum), betű-e (isalpha),vezérlőkarakter-e (iscntrl), decimális számjegy-e(isdecimal), megjeleníthető-e (isgraph), kisbetű-e(islower), nyomtatható-e (isprint), központozás-e(ispunct), whitespace-e (isspace), nagybetű-e (isupper),hexadecimális számjegy-e (isxdigit).

I Emellett nagybetűről kisbetűre és kisbetűről nagybetűrealakító függvényt is tartalmaz (tolower, toupper).

1 printf("%i\n", isalpha('1')); // => 02 printf("%c\n", toupper('b')); // => B

81 / 94

<float.h>

I A lebegőpontos számok tárolásával kapcsolatos szimbolikusállandókat tartalmaz, mint például:

- FLT_MAX, DBL_MAX, LDBL_MAX: A legnagyobb float / double /long double érték.

- FLT_MIN, DBL_MIN, LDBL_MIN: A legkisebb 0-nál nagyobbfloat / double / long double érték.

- FLT_EPSILON, DBL_EPSILON, LDBL_EPSILON: A legkisebb1-nél nagyobb float / double / long double érték mínusz 1.

- FLT_DIG, DBL_DIG, LDBL_DIG: Legfeljebb ennyi decimálisszámjegyű egész számot lehet float / double / long doubletípusban pontosan tárolni.

- ...

1 printf("%i\n", 1 + FLT_EPSILON > 1); // => 12 printf("%i\n", 1 + FLT_MIN > 1); // => 0

82 / 94

<limits.h>

I Az egész számok tárolásával kapcsolatos szimbolikusállandókat tartalmaz, mint például:

- SHRT_MIN, INT_MIN, LONG_MIN:A legkisebb short / int / long érték.

- SHRT_MAX, INT_MAX, LONG_MAX:A legnagyobb short / int / long érték.

- USHRT_MAX, UINT_MAX, ULONG_MAX:A legnagyobb unsigned short / int / long érték.

- ...

1 printf("%i\n", SHRT_MAX);2 printf("%i\n", INT_MAX);3 printf("%ld\n", LONG_MAX);

83 / 94

<math.h>

I Alapvető matematikai függvényeket tartalmaz, mint például:- Hatványfüggvény: pow.- Exponenciális és logaritmusfüggvény: exp, log.- Trigonometrikus függvények: sin, cos, tan, ....- Inverz trigonometrikus függvények: asin, acos, atan, ...- Abszolút érték: fabs.- Kerekítés: round, floor, ceil.- ...

1 printf("%f\n", pow(2, 0.5)); // => 1.4142142 printf("%f\n", 4 * atan(1)); // => 3.141593

84 / 94

<stdio.h>

I Fájlmegnyitás (fopen), fájlbezárás (fclose).I Olvasás standard bemenetről (getchar, scanf), fájlból

(fgetc, fgets, fscanf, fread), sztringből (sscanf).I Írás standard kimenetre (putchar, printf), fájlba (fputc,

fputs, fprintf, fwrite), sztringbe (sprintf).I Pozícionálás (fseek, ftell), hibakezelés (feof, ferror).I Törlés (remove), átnevezés (rename), átmeneti fájlt megnyitás

(tmpfile).I ...

85 / 94

<stdio.h>: Fájlkezelés

I Egy fájl életciklusa:1. megnyitás2. olvasás, írás, pozícionálás, ...3. bezárás

I Példa:

1 FILE *f = fopen("numbers.txt", "r"); // megnyitás2 if (f == 0) { exit(1); }3 int a[10];4 for (int i = 0; i < 10; i++) {5 fscanf(f, "%i", &a[i]); // olvasás6 }7 fclose(f); // bezárás

86 / 94

<stdio.h>: Fájlkezelés

I Hiba esetén az fopen függvény NULL (0) értéket ad vissza.I Fájl hozzáférési módok:

- Olvasás ("r"), írás ("w"), hozzáfűzés ("a").- Olvasás és írás ("r+", "w+", "a+").- Bináris mód ("rb", "wb", "ab").

I Néhány gyakori használati eset:- Olvasás soronként fgets függvénnyel.- Szövegfájl olvasása / írása fscanf / fprintf függvénnyel.- Bináris fájlban lévő adatok olvasása fread / fwrite függvénnyel.- Ugrás a fájl elejére fseek függvénnyel.

87 / 94

<string.h>

I Sztringműveletek: hossz lemérése (strlen), másolás (strcpy,strncpy), konkatenálás (strcat), összehasonlítás (strcmp,strncmp), mintakeresés (strchr, strstr), tokenizálás(strtok).

1 char s1[] = "piros";2 char s2[] = "piros";3 if (!strcmp(s1, s2)) { puts("mindketto piros"); }

I Memóriaműveletek: konstans értékre állítás (memset), másolás(memcpy), mozgatás (memmove), összehasonlítás (memcmp).

1 int a[100];2 memset(a, 0, 100 * sizeof(int)); // feltöltés nullával

88 / 94

<string.h>: További példák

1 char s1[100] = "alma";2 char s2[100] = "korte";3 strcat(s1, s2);4 puts(s1); // => almakorte5 strcpy(s1, s2);6 puts(s1); // => korte

1 char data[] = "alma,korte,szilva,barack";2 char *tok = strtok(data, ",");3 puts(tok);4 while (tok = strtok(NULL, ",")) {5 puts(tok);6 }7 puts(data); // => alma

89 / 94

<time.h>

I time: Az 1970-01-01 00:00:00 óta eltelt időt adja visszamásodpercben mérve.

I clock: A program által felhasznált processzoridő közelítésétadja vissza, „tick” számban mérve.

I CLOCKS_PER_SEC: Ennyi „tick” tesz ki egy másodpercet.

1 // 1/1 + 1/2 + 1/3 ... 1/10^9 kiszámítása2 int t0 = clock();3 double s = 0;4 for (int k = 1; k <= 1000000000; k++) {5 s += 1.0 / k;6 }7 printf("az osszeg: %f\n", s);8 printf("szamitasido: %f mp\n",9 (double) (clock() - t0) / CLOCKS_PER_SEC);

90 / 94

<stdlib.h>: Véletlenszám generálás

1 srand(time(0)); // álvéletlenszám generátor2 // kezdőállapotának beállítása3

4 // kockadobások szimulálása5 for (int i = 0; i < 100; i++) {6 int x = rand() % 6 + 1;7 printf("%i\n", x);8 }9

10 // [0, 1] intervallumba eső álvéletlen számok sorsolása11 for (int i = 0; i < 10; i++) {12 double y = (double) rand() / RAND_MAX;13 printf("%f\n", y);14 }

91 / 94

<stdlib.h>: Rendezés és keresés

1 /* Két egész számot összehasonlító függvény. */2 int intcmp(const void *x, const void *y) {3 int x2 = *((int *) x);4 int y2 = *((int *) y);5 return x2 < y2 ? -1 : (x2 > y2 ? 1 : 0);6 }78 int main() {9 // tömb inicializálása

10 int n = 6;11 int a[] = {10, 5, 2, 13, 7, 3};1213 // tömb rendezése14 qsort(a, n, sizeof(int), intcmp);15 for (int i = 0; i < n; i++) { printf("%i\n", a[i]); }1617 // keresés a rendezett tömbben18 int z = 10;19 int *j = bsearch(&z, a, n, sizeof(int), intcmp);20 printf("%i\n", j - a); // => 4 (azaz a 10 a rendezett tömb 4. eleme)21 return 0;22 }

92 / 94

<stdlib.h>: Rendszerszolgáltatások, konverzió

1 int code = system("ls -la"); // parancs végrehajtása2 printf("%i\n", code); // a kilépési kód kiírása3

4 char *path = getenv("PATH"); // környezeti változó5 // értékének lekérdezése6 puts(path);7

8 exit(0); // azonnali kilépés 0 kóddal

1 int x = atoi("42"); // sztring => int konverzió2 double y = atof("1.23"); // sztring => double konverzió

93 / 94

<stdlib.h>: Dinamikus memóriakezelés

I Gyakori eset, hogy a program számára szükséges memóriamérete csak a futtatás során derül ki. Az ilyen feladatokdinamikus memóriakezelés segítségével oldhatók meghatékonyan.

I Stack memória:- Mérete előre rögzített.- „Lefelé” (azaz a kisebb címek felé) haladva töltődik fel.- Ebben tárolódnak a függvények paraméterei és lokális változói.

I Heap memória:- Mérete dinamikusan változhat.- A számítógép (szinte) teljes memóriájához hozzáférhetünk asegítségével.

1 int *a = malloc(1000000000); // memóriafoglalás2 if (a == 0) { exit(2); } // (primitív) hibakezelés3 free(a); // lefoglalt memória felszabadítása

94 / 94