820 likes | 1.02k Views
C/C++ a Pascal. Ing . Peter Pi štek , C E ng. Obsah. Opakovanie z minulého stretnutia Ukazovatele (Pointre) Jednorozmerné polia Viacrozmerné polia Reťazce Dynamické štruktúry. Opakovanie. Základné konštrukcie jazyka Základné údajové šruktúry Funkcie Cykly a rekurzia
E N D
C/C++ a Pascal Ing. Peter Pištek, CEng.
Obsah • Opakovanie z minulého stretnutia • Ukazovatele (Pointre) • Jednorozmerné polia • Viacrozmerné polia • Reťazce • Dynamické štruktúry
Opakovanie • Základné konštrukcie jazyka • Základné údajové šruktúry • Funkcie • Cykly a rekurzia • Práca so súbormi • Struct
Opakovanie • C je casesensitive jazyk • Prototypovanie funkcií • Pri načítavaní scanf (“parametre“, &premenna) • Rovný (==), rôzny (!=), AND ( &&), OR (||), NOT (!) • Zátvorkovanie podmienok • Vo vetvách switchu treba používať príkaz break • Cyklus for môže byť nekonečný • Práca so súbormi (princípe sa pridáva pred názov funkcie „f“ a do argumentov sa pridáva súbor)
Opakovanie • Príkaz fflush okamžite uloží obsah buffra do súboru • Radšej používať feof() ako konštantu EOF • EOLN nie je, treba hľadať \n • stdin, stdout, stderr • Definovanie konštánt - #define MAX 100 • typedef – definovanie vlastných typov • Record == struct
Mini opakovanie switch(getchar()) { case 'a' : putchar('a'); case 'b' : putchar('b'); case 'c' : putchar('c'); default : putchar('x'); } x, y: double; printf("Zadajte2realnecisla: "); scanf("%lf %lf", x, y); printf("%.2lf\n", (x > y) ? x : y); for (i = 1,i <= n,i++) { for (j = 2, j <=i,j++) printf("%d ", &j); putchar('\n'); }
Pointre • Ukazovatele na premenné • Ich obsahom je adresa pamäte • Štandardne premenné sú premenné v zásobníku, pointre ukazujú do haldy • p: ukazovateľ, *p: hodnota, na ktorú ukazuje • V deklarácií je definovaný pomocou “*“ (int*p) • Treba vždy inicializovať (implicitne-explicitne) • int*p1=1, *p2; • p2=p1; p2=2;
Pointre – adresácie a hodnoty • Klasická premenná int i, pointer int *p • &i – adresapremennej p – adresapointra • i – hodnotapremennej *p – hodnota pointra • *p=iint*p=&i (deklarovanie inicializacia) • Pri debuggingu môžete používať %p (printf,...) • NIL Pascal == NULL C (v stdio.h) • Nepoužívajte konverziu ukazovateľov • char*p_cint *p_i • p_c=p_ip_c=(char *)p_i
Pointre – práca v pamäti pamäť pamäť 7 7 i: 28 i: 28 *p_i: 30 25 30 25 p_i: 73 30 73 28 30
Pointre - inicializácia - správne p_i = &i; -chyba: (i + 3) nie je premenná p_i = &(i + 3); -chyba: konštanta nemá adresu p_i = &15; p_i = 15; - chyba: priraďovanie absolútnej adresy -chyba: do i priradíme obsah p_i i = p_i; -chyba: priraďovanie adresy i = & p_i; -správne, p_i bol inicializovaný p_i = &i;*p_i = 4; *p_i = 4; Najčastejšia chyba, neinicializovaný smerník!
Pointre a parametre funkcií • Pri viacerých návratových hodnotách z funkcie voidvymen(int*p_x, int*p_y) { intpom; pom = *p_x; *p_x = *p_y; *p_y = pom; } • volanie funkcie:vymen(&i, &j) • vymen(i,j); • vymen(*i, *j);
Generický pointer • void*p • Neukazuje na žiadny konkrétny typ • Nezabúdať na pretypovanie voidvymen(void**p_x, void**p_y) { void *p; p = *p_x; *p_x = *p_y; *p_y = p; } inti; float f; void*p_void = &i; *(int *) p_void = 2; p_void = &f; *(float *) p_void = 3.5; char c = 'a', *p_c = &c, d = 'b', *p_d = &d; vymen((void *) &p_c, (void *) &p_d);
Pointre - Príklady definícií -i je typu int int i; -y je ukazovateľ na typ float float *y; -z je funkcia vracajúca ukazovateľ na double double *z(); -v je ukazovateľ na funkciu vracajúcu int int (*v)(); -v je ukazovateľ na funkciu vracajúcu ukazovateľ na int int *(*v)();
Pointre – čítanie definícií Nájdeme identifikátor, od neho čítame doprava pokým nenarazíme na samotnú pravú zátvorku ")". Vraciame sa k zodpovedajúcej ľavej zátvorke. Potom pokračujeme doprava (preskakujeme prečítané) Ak narazíme na ";" , vraciame sa na najľavejšie spracované miesto v čítame doľava pointer na funkciu vracajúcu - v je * int * (*v) () int *(*v)(); pointer na int
Pointre – použitie typedef • Vhodné najmä pri zložitejších typov • int*p_i, **p_p_i; • typedefint *P_INT; • typedef P_INT *P_P_INT • P_INT p_i; P_P_INT p_p_i;
Pointre – sizeof() • Vracia veľkosť dátového typu v Bytoch (napr. zistenie rozsahu pre int) • Pri určovaní veľkostí polí • int*p = 10 p+1=12 (sizeof (int)==2) • Porovnanie ukazovateľov – ako pri bežných premenných. • Len keď sú rovnakého typu, ukazujú na ten istý úsek pamäte • Aritmetika – súčet/rozdiel ukazovateľa a celého čísla
Pointre – dynamické alokovanie • Životnosť od alokovania až po uvoľnenie z pamäte • stdlib.h (občas alloc.h) • void*malloc (unsigned int) – vracia adresu prvého alokovaného prvku a parameter je počet Bytov. Chybový návrat - NULL int* p_i; if((p_i = (int *) malloc(1000)) == NULL) { printf("Nepodarilosapridelitpamat\n"); exit; }
Pointre – uvoľnenie pamäte • Nepotrebnú pamäť je vhodnú okamžite uvoľnovať • voidfree (void*) • po uvoľnení pamäte priradiť pointru NULL
Pointre – calloc • void*calloc(unsignedint) • To isté čo malloc, len automaticky inicializuje Byty na 0 int *alokuj(int n) { return ((int *) malloc(n * sizeof(int))); } voidsucin(int *p, int n, intsucin) { inti; for (i = 0; i < n; i++) sucin *= *(p + i); }
Jednorozmerné polia Pascal X: array[0..9] of integer; #defineN 10 int x[N], y[N+1], z[N*2]; • x má 10 prvkov (0..9), y má 11 prvkov (0..10), z má 20 prvkov (0..19) • Inicializácia v definícií – int x [3]={1,2,3}; • Pole ako parameter funkcie – void funkcia (int pole[]) • Viacrozmerné polia – int x [5][4][5][7]; • Prístup k prvkom poľa ?
Polia a pointre • TYP x[N]; definícia statického poľa • TYP *p_x; definícia smerníka • xa p_x sú smerníky na typ TYP • x jekonštantný smerník jeho hodnota sa nedá meniť • x je adresa začiatku bloku pamäti alokovaného pre statické pole. • p_xje premenná s neurčenou počiatočnou hodnotou, alokuje pamäť iba pre seba
Polia a pointre int*p; p = (int *) malloc(4 * sizeof(int)); *pje smerník nablokpamätialokovanej pomocou funkcie malloc() p je dynamické pole, ktoré vzniká za behu programu • platí: • p[0] == *p • p[1] == *(p + 1) • p[2] == *(p + 2) • p[3] == *(p + 3) int x[4] x + i == &x[i] *(x + i) == x[i] • &x[0] == &*(x + 0) == x • &x[i] == &*(x + i) == (x + i)
Polia a pointre • int x[1], *p_x • p_x=x (OK) x=p_x (ZLE) • void *realloc (void *pole, unsignetint size) • Zväčší alebo vytvorí nové pole a skopíruje tam hodnoty z pôvodného poľa
Pole ako parameter funkcie • int maximum(int pole[], int n) – n reprezentuje veľkosť poľa, vo funkcií nevieme aká je veľkosť poľa • int pole[] je ekvivalentné int*pole int x[10]; max = maximum(&x[2], 5); voidinit(double **p_f) { double *a; inti; a = (double *) malloc(5 *sizeof(double); *p_f = a; } voidmain() { double *p_d; init(&p_d); }
Pole ukazovateľov na funkcie • typedefvoid (* P_FNC)(); • P_FNC funkcie[5] = {file, edit, search, compile, run}; • funkcia[1]();
Viacrozmerné polia • Základné deklarácie • int x[5][4] • typedefint DVA[5][4]; • DVA d • typedefint JEDEN [5] • typedef JEDEN DVA[4] • DVA d • x[i][j] i-riadok, j-stĺpec, x-ukazovateľ na dvojrozmerné pole, x[i] – ukazovateľ na riadok
Viacrozmerné polia • x a x[0] – tá istá adresa len iného typu • Plno fínt s adresáciami – pristupujte k tomu ako v Pascale a všetko bude dobre • &x[i][j] == x[i] + j == *(x + i) + j • adresapremennej • x[i][j] == *(x[i] + j) == *(*(x + i) + j) • hodnotapremennej
Viacrozmerné polia - definície • Statické dvojrozmerné pole intxa[2][3] • Pole ukazovateľov int*xb[2] • Ukazovateľ na pole int (*xc)[3] • Ukazovateľ na ukazovateľint **xd • Najskôr sa alokujú riadky potom jednotlivé stĺpce
Viacrozmerné polia - výhody • xa (intxa[2][3]): pamäťovo najvýhodnejšie • xb(int *xb[2]): naviac pamäť pre 2 ukazovatele (počet riadkov xb[0], xb[1]) • xc(int (*xc)[3]): naviacpamäť pre 1 ukazovateľ na typ int: xc • xd(int **xd): naviac 1 ukazovateľ pre xd a 2 ukazovatele na riadky (xd[0], xd[1]) • xa a xc – pravouhlé polia • xb a xd – nepravidelené polia
Viacrozmerné polia • Podobné ako jednorozmerné polia • Odlišnosť – prvá dimenzia musí byť prázdna, druhá musí byť uvedená • Len pravouhlé polia • Inicializácia • double f[3] = {1.5, 3.0, 7.6 }; • double f[] = {1.5, 3.0, 7.6 }; • double f[3] = {1.5, 3.0 }; • double f[3] = {1.5, 3.0, 7.6, 3.8 }; ZLE • pri dvojrozmerných – musí byť uvedený počet stĺpcov
Reťazce • Poliatypu char • Ukončené sú vždy \0 – ukončovací znak • Ak by chýbal tak číta reťazec až kým nenarazí naň niekde v pamäti char c [4]=“ahoj” – chyba char c [5]=“ahoj” – ok scanf (“%s”,c) – tunemusí byť & %10s – načíta 10 znakov char s[11]; for(i = 0; i < 11-1; i++) s[i] = '*'; s[10-1] = '\0';
Reťazce • char s[] = "abrakadabra"; • char*s; • s = (char *) malloc(6); • char s[10]; • s = "ahoj"; • Dynamický reťazec sa nedá inicializovať (scanf,strcpy)
Reťazce • Dynamický reťazec sa nedá inicializovať (scanf,strcpy) • Nulový reťazec • NULL – neukazuje na žiadne miesto v pamäti • \0 – má na nultom znaku \0 • “x” a ‘x’ je rozdiel • “x” – reťazec s jedným znakom a je ukončený \0 • ‘x’ – je jeden znak
Reťazce – čítanie z klávesnice • scanf vynecháva biele znaky a číta po prvý biely znak (“ ahoj Eva“ -> “ahoj”) • scanf (“%c”,s) by tú medzeru zvládlo – iné správanie ako scanf(“%1s”,s) • scanf (“%s”,s); • Reťazec = pole -> práca s reťazcom je rovnaká ako práca s poľom • Pri práci so statickým reťazcom nezabúdať na \0
Práca s reťazcami • <string.h> • intstrlen(char *s); • char *strcpy(char *s1, char *s2); • char *strcat(char *s1, char *s2); • char *strchr(char *s, char c); • intstrcmp(char *s1, char *s2); • char *strstr(char *s1, char *s2); • char *strncpy(char *s1, char *s2, int max); • char *strrchr(char *s, char c); • intatoi(char *s); • longatol(char *s); • floatatof(char *s);
Práca s reťazcami • char *gets(char *s); (fgets) • intputs(char *s); (fputs) • sprintf – vypisuje do reťazca (fprintf) • sscanf – číta z reťazca (fscanf) • char *p_text[4]; • p_text[0] = "prvy"; • p_text[1] = "druhy"; • p_text[2] = (char*) malloc(6); • strcpy(p_text[2], "treti"); • p_text[3] = "stvrty";
Štruktúry typedefstructmiery{ intvyska; float vaha; } MIERY; MIERY pavol, jan, peter; TBookRec = Record Title, Author, ISBN : String; Price : Real; End; Kniha: TBookRec typedefstruct { intvyska; float vaha; }MIERY; MIERY pavol,jan, peter; struct{ intvyska[20]; float vaha; } peter,pavol,jan; struct miery { intvyska; float vaha; }; struct mierypeter; structmiery{ intvyska; float vaha; } peter,pavol,jan; Prisupnapr. peter.vyska[1]=198;
Priradenie celého poľa naraz typedefstruct pole { int pole[10]; }STR_POLE; void main() { STR_POLE a, b; a.pole[0] = 5; b = a; }
Štruktúry a pointre typedefstruct { char meno[30]; introcnik; }STUDENT; STUDENT s, *p_s; p_s = (STUDENT *) malloc(sizeof(STUDENT)); p_s = &s; (*p_s).rocnik=4 p_s->rocnik=4
Dynamické štruktúry typedefstructpolozka { //ok int hodnota; structpolozka *p_dalsi; }POLOZKA; typedefstruct { //zle int hodnota; structPOLOZKA *p_dalsi; }POLOZKA;
Spájaný jednosmerný zoznam typedefstructpolozka { int hodnota; structpolozka *p_dalsi; }POLOZKA; • Je nutné si pamätať prvý prvok zoznamu (!) • Každý prvok ukazuje na nasledujúci prvok • Posledný prvok ukazuje na NULL
Spájaný jednosmerný zoznam typedefstructclovek { char meno[30]; introcnik; structclovek *dalsi; }CLOVEK; CLOVEK *prvy, *aktualny, *novy; novy = (CLOVEK *) malloc(sizeof(CLOVEK)); novy->meno = “Jurko”; novy->rocnik = 3; novy->dalsi = NULL; aktualny->dalsi = q; //aktualny->dalsi->dalsi = q;
Spájaný jednosmerný zoznam CLOVEK *prvy, *aktualny, *zmaz; //zmazatprvokaktualny zmaz=prvy; //zapredpokladuzenemazemeprvyprvok while (zmaz->dalsi==aktualny) zmaz=zmaz->dalsi zmaz->dalsi=aktualny->dalsi aktualny->dalsi=NULL free(aktualny) aktualny=NULL aktualny=zmaz Podobneaj pre pridanie prvku pred aktualny
Dynamické štruktúry – FIFO • FIFO = first in firstout = rad • Implementácia jednosmerného spájaného zoznamu • Pridávať je možné len na koniec zoznamu • Odoberať prvky sa dá len z konca zoznamu
Dynamické štruktúry – LIFO • LIFO = last in firstout = zásobnik • Implementácia jednosmerného spájaného zoznamu • Pridávať je možné len na začiatok (koniec) zoznamu • Odoberať prvky sa dá len zo začiatku (konca) zoznamu
Kruhový jednosmerný zoznam • Prvý prvok ukazuje na posledný
Spájaný obojsmerný zoznam typedefstructpolozka { int hodnota; structpolozka *p_dalsi; structpolozka *p_pred; }POLOZKA; • Každý prvok ukazuje na nasledujúci prvok a predchádzajúci prvok • Posledný prvok ukazuje ďalej na NULL • Prvý prvok ukazuje na predchádzajúci ako na NULL • Treba si pamätať prvý/posledný prvok