700 likes | 893 Views
Procedur álne programovanie: 8 . prednáška. Gabriela Kosková. Obsah. Rie šenie časti testu Štruktúry a sp ájané zoznamy. Výpis po čtu slov na základe dĺžky. #include <stdio.h> #define SUBOR "beatles.txt" int main() { FILE *f; int akt_dlzka = 0, dlzka, pocet = 0; char c;
E N D
Procedurálne programovanie:8. prednáška Gabriela Kosková
Obsah • Riešenie časti testu • Štruktúry a spájané zoznamy
Výpis počtu slov na základe dĺžky #include <stdio.h> #define SUBOR "beatles.txt" int main() { FILE *f; int akt_dlzka = 0, dlzka, pocet = 0; char c; scanf("%d", &dlzka); if((f = fopen(SUBOR, "r")) == NULL) { printf("Subor %s sa nepodarilo otvorit.\n", SUBOR); return 1; } while((c = getc(f)) != EOF) { if((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) akt_dlzka++; else { if(akt_dlzka >= 1 && akt_dlzka <= dlzka) pocet++; akt_dlzka = 0; } }
Výpis slov zo zvolehého riadku if(akt_dlzka >= 1 && akt_dlzka <= dlzka) pocet++; printf("Pocet slov: %d", pocet); if(fclose(f) == EOF) printf("Subor %s sa nepodarilo zatvorit.\n", SUBOR); return 0; }
Hodnoty premenných int *Euro, *Dolar, *CZK, *pom; Euro = (int *) malloc(sizeof(int)); Dolar = (int *) malloc(sizeof(int)); CZK = (int *) malloc(sizeof(int)); *Euro = 100; *Dolar = 200; *CZK = 0; *CZK = *Dolar;*Euro = *CZK;*Dolar = *Dolar + 100;pom = Euro; Euro = Dolar;Dolar = pom;*CZK = *Euro; *pom = *CZK + *Euro;pom = NULL; Riešenie na tabuli
Definícia makra (obsah kruhu) #define PI 3.14 #define obsah(r) (PI * (r) * (r))
Vyhodnocovanie logických operátorov #include <stdio.h> int main(void) { int i = 10, j = 5; if ((i %= j) && ++j == 6) printf ("Logicky sucin\n"); printf("i: %d j: %d\n", i, j); return 0; } i: 0 j: 5
Vyhodnocovanie logických operátorov #include <stdio.h> int main(void) { int i = 12, j = 5; if ((i %= j) || ++j == 6) printf ("Logicky sucet\n"); printf("i: %d j: %d\n", i, j); return 0; } Logicky sucet i: 2 j: 5
Procedurálne programovanie: Štrutkúry, uniony a výmenované typy
struct { položka_1; ... položka_n; } Čo je to štruktúra? • štruktúra (struct) je heterogénny dátový typ • heterogénny: je zložený z prvkov rozličných dátových typov (pole je homogénny dátový typ) dá sa definovať piatimi rôznymi spôsobmi
Definícia štruktúry (1) • základný spôsob • štruktúra nie je pomenovaná, • nedá sa inde v progame použiť • dajú sa použiť len definované premenné struct { int vyska; float vaha; } pavol, jan, karol;
Definícia štruktúry (2) • modifikácia základného spôsobu • štruktúra je pomenovaná, • dá sa využiť aj inde v programe struct miery{ int vyska; float vaha; } pavol, jan, karol;
Definícia štruktúry (3) • podobne ako predchádzajúci spôsob • definícia štruktúry a premenných je oddelená od definície premenných (ktoré sa môžu robiť viackrát) struct miery { int vyska; float vaha; }; struct miery pavol; struct miery jan, karol;
Definícia štruktúry (4) • definícia nového typu (typedef) • štruktúra nie je pomenovaná, pomenovaný je typ • typ sa dá použiť na definíciu premenných, pretypovanie... typedef struct { int vyska; float vaha; }MIERY; MIERY pavol, jan, karol; nebolo použité "struct"
Definícia štruktúry (5) • modifikácia predchádzajúceho spôsobu • štruktúry aj typ je pomenovaná (v tomto prípade to nie je potrebné, ale neskôr to budeme potrebovať) typedef struct miery{ int vyska; float vaha; } MIERY; MIERY pavol, jan, karol; odporúča sa pomenovať typ aj štruktúru rovnako, odlíšiť ich len veľkosťou písma
Používanie štruktúr • odporúča sa používať definície typu (4) a (5) • je to prehľadnejšie ("struct" sa použije len raz) typedef struct { int vyska; float vaha; } MIERY; MIERY pavol, jan, karol; typedef struct miery { int vyska; float vaha; } MIERY; MIERY pavol, jan, karol;
často sa používa pole štruktúr: MIERY ludia[100]; ludia[50].vyska = 156; v ANSI C sa dá urobiť Prístup k položkám štruktúry • bodková notácia typedef struct { int vyska; float vaha; } MIERY; MIERY pavol, jan, karol; pavol.vyska = 182; karol.vaha = 62.5; jan.vyska = pavol.vyska; ludia[0] = ludia[50];
takto sa dá použiť štruktúra na to, aby sa dalo naraz skopírovaťcelé pole Pole v štruktúre typedef struct { int pole[10]; }STR_POLE; void main() { STR_POLE a, b; a.pole[0] = 5; b = a; }
p_s = (STUDENT *) malloc(sizeof(STUDENT)); p_s = &s; Štruktúry a ukazovatele • použitie: • štruktúra v dynamickej pamäti • štruktúra vo funkcii *p_s - ukazovateľ naštruktúru, nemá pridelené miesto v pamäti, preto je potrebné alokovať mu pamäť. typedef struct { char meno[30]; int rocnik; }STUDENT; STUDENT s, *p_s; alebo nastaviť ukazovateľ na inú pamäť
STUDENT s; P_STUDENT p_s; p_s = (P_STUDENT *) malloc(sizeof(STUDENT)); s.rocnik = 2; (*p_s).rocnik = 3; p_s->rocnik = 4; Štruktúry a ukazovatele typedef struct { char meno[30]; int rocnik; }STUDENT, *P_STUDENT; definícia typu ukzovateľa na štruktúru prístup k štruktúre pomocou ukazovateľa
Prístup do štruktúry pomocou ukazovateľa STUDENT s, *p_s; s.rocnik = 2; chybné, lebo. má väčšiu prioritu ako *, teda tam, kam ukazuje p_s.rocnik (adesa 3) priraďhodnotu 4 (*p_s).rocnik = 3; *p_s.rocnik = 4; p_s->rocnik = 5;
vyskum.html home.html <html> <head> <title>Vyskum </title> ... <html> <head>...</head> <body> .... tato stranka sa odkazuje na stranku <a href="vyskum.html">vyskum</a> ... <a href="pub.html">publikacie</a> ... <a href="vyucba.html">vyucba</a> ... </body> pub.html <html> <head> <title>Publika </title> ... vyucba.html <a href="vyskum.html">vyskum</a> <html> <head> <title>Vyucba </title> ... <a href="pub.html">publikacie</a> <a href="vyucba.html">vyucba</a> Štruktúry ukazujúce samy na seba: príklad 1 • hypertext • web stránka má odkaz na web stránku (ukazovateľ na rovnaký typ)
AMBULANCIA Štruktúry ukazujúce samy na seba: príklad 2 • pacienti v čakárni u lekára • "Kto je posledný?" • každý človek si pamätá človeka, ktorý je pred ním (ukazovateľ na ten istý typ)
typedef struct { int hodnota; struct POLOZKA *p_dalsi; }POLOZKA; Štruktúry ukazujúce samy na seba typedef structpolozka { int hodnota; struct polozka *p_dalsi; }POLOZKA; odkaz na samého seba (na takú istú štruktúru) aj štruktúra, aj typ musia byť pomenované chyba: v čase, keď sa definujem p_dalsi, POLOZKA ešte nie je známa
typedef struct clovek { char meno[30]; int rocnik; struct clovek *dalsi; }CLOVEK; 1. položka ... n. položka ukazovateľ Spájaný zoznam • dynanamický zoznam prvkov : • v pamäti je práve toľko prvkov, koľko je potreba • dá sa pridávať na ktorékoľvek miesto v zozname ukazuje na ten istý typ
q q p Jurko 3 Miško 2 Janko 1 Spájaný zoznam typedef struct clovek { char meno[30]; int rocnik; struct clovek *dalsi; }CLOVEK; CLOVEK *p, *q; q = (CLOVEK *) malloc(sizeof(CLOVEK)); q->meno = Jurko; q->rocnik = 3; q->dalsi = NULL; p->dalsi->dalsi = q; p = (CLOVEK *) malloc(sizeof(CLOVEK)); p->meno = Janko; p->rocnik = 1; p->dalsi = NULL; q = (CLOVEK *) malloc(sizeof(CLOVEK)); q->meno = Misko; q->rocnik = 2; q->dalsi = NULL; p->dalsi = q;
1 2 3 4 5 6 7 Spájaný zoznam: príklad • Vtvorí sa spájaný zoznam s hodnotami 1...n, potom sa vymažú všetky prvky, ktoré sú deliteľné 3. typedef structprvok { int hodnota; struct prvok *dalsi; } PRVOK;
p_akt p_prv p_pred 1 #include <stdio.h> #include <stdlib.h> typedef structprvok { int hodnota; struct prvok *dalsi; } PRVOK; void main() { int i, n; PRVOK *p_prv, *p_akt, *p_pred; printf("Zadaj pocet prvkov zoznamu: "); scanf("%d", &n); if((p_prv = (PRVOK *) malloc(sizeof(PRVOK))) == NULL){ printf("Malo pamate.\n") return; } p_prv->hodnota = 1;
1 n ... p_akt = p_prv; for(i = 2; i < n; i++) { if(p_akt->dalsi = (PRVOK *) malloc(sizeof(PRVOK))) == NULL) { printf("Malo pamate.\n") break; } p_akt = p_akt->dalsi; p_akt->hodnota = i; } p_akt->dalsi = NULL; p_akt p_prv p_pred 2 for(p_pred = p_akt = p_prv; p_akt != NULL; p_pred = p_akt, p_akt = p_akt->dalsi) { if(p_akt->hodnota % 3 == 0) { p_pred->dalsi = p_akt->dalsi; free((void *) p_akt); p_akt = p_pred; } } }
Štruktúra v inej štruktúre • štruktúra, ktorá je v inej štruktúre musí byť definovaná skôr ako je do inej štruktúry uložená (vhniezdená štruktúra) • predtým sme mali len odkaz na štruktúru typedef struct { char meno[30]; ADRESA adresa; float plat; }OSOBA; typedef struct { char ulica[30]; int cislo; }ADRESA; príklad: vypísať adresu zamestnanca s najvyšším platom (OSOBA ludia[100])
int i, kto = 0; float max = 0.0, pom; OSOBA ludia[100]; ... /* inicializacia */ for (i = 0; i < 100; i++) { if((pom = ludia[i].plat) > max) { max = pom; kto = i; } } printf("Zamestnanec s najvyssim platom byva: %s %d", ludia[kto].adresa.ulica, ludia[kto].adresa.cislo); Príklad: štruktúra v inej štruktúre typedef struct { char ulica[30]; int cislo; }ADRESA; typedef struct { char meno[30]; ADRESA adresa; float plat; }OSOBA;
float max = ludia[0].plat, pom; OSOBA ludia[100], *p_kto, *p_pom; ... /* inicializacia */ for (p_pom = p_kto = ludia; p_pom < ludia + 100; p_pom++) { if ((p_pom->plat) > max) { p_kto = p_pom; max = p_pom->plat; } } printf("Zamestnanec s najvyssim platom byva: %s %d", p_kto->adresa.ulica, p_kto->adresa.cislo); Príklad: štruktúra v inej štruktúre - cez ukazovateľe typedef struct { char ulica[30]; int cislo; }ADRESA; typedef struct { char meno[30]; ADRESA adresa; float plat; }OSOBA;
Alokácia pamäte pre jedotlivé položky štruktúry • položky obsadzujú pamäť zhora dole a zľava doprava • pre p v poradí: c i j k d • položky sú väčšinou zarovnávané na párne adresy • za položkou c je väčšinou 1 prázdny Byte • štruktúra väčšinou končí na párnej adrese • za položkou d - 1 volný Byte typedef struct { char c; int i, j, k; char d; } POKUS; POKUS p; na zistenie veľkosti:sizeof(p);
Šturktúry a funkcie • K&R verzia jazyka C: • parameter: ukazovateľ na štruktúru • návratový typ: ukazovateľ na štruktúru • ANSI C: • parameter: ukazovateľ na štruktúru aj samotná štruktúra • návratový typ: ukazovateľ na štruktúru aj samotná štruktúra
ak sú štrutúry veľké, nevýhodné, lebo sa vytvárajú lokálne kópie (časovo aj pamäťovo náročné) vhodné používať ukazovatele Príklad: šturktúry a funkcie • sčítanie komplexných čísel typedef struct { double re, im; } KOMP; KOMPsucet(KOMP a, KOMP b) { KOMP c; c.re = a.re + b.re; c.im = a.im + b.im; return c; } void main() { KOMP x, y, z; x.re = 1.4; x.im = 3.2; y = x; z = sucet(x, y); }
Príklad: šturktúry a funkcie -pomocou ukazovateľov • sčítanie komplexných čísel typedef struct { double re, im; } KOMP; voidsucet(KOMP *a, KOMP *b, KOMP *c) { c->re = a->re + b->re; c->im = a->im + b->im; } void main() { KOMP x, y, z; x.re = 1.4; x.im = 3.2; y = x; sucet(&x, &y, &z); }
STUDENT *vytvor1(void) { STUDENT p; p = (STUDENT *) malloc(sizeof(STUDENT)); if (p = NULL) printf("Malo pamate.\n"); return p; } void vytvor2(STUDENT **p) { p = (STUDENT *) malloc(sizeof(STUDENT)); if (p = NULL) printf("Malo pamate.\n"); } Príklad: dynamické vytváranie štruktúry vo funkciách typedef struct { char meno[30]; int rocnik; } STUDENT; vracia štruktúru ako ukazovateľ vracia štruktúru cez parameter
void main() { STUDENT s, *p_s1, *p_s2; p_s1 = vytvor1(); vytvor2(&p_s2); s.rocnik = p_s1->rocnik = 1; nastav(&s, "Martin", 1); nastav(p_s1, "Peter", 2); nastav(p_s2, "Michal", 3); } Príklad: dynamické vytváranie štruktúry vo funkciách void nastav(STUDENT *p, char *meno, int rok) { p->rocnik = rok; strcpy(p->meno, meno); }
Inicializácia štruktúr typedef struct { char meno[30]; int rocnik; } STUDENT; STUDENT s = { "Janko", 3 }; STUDENT studenti[] = { { "Misko", 3 }, { "Jurko", 2 } }; pocet = sizeof(studenti) / sizeof(STUDENT);
Vymenované typy • enumerate type - zoznam symbolických konštánt, ktoré sú zvyčajne vzájomne závislé • zvyšuje čitateľnosť programu tu nie je bodkočiarka typedef enum { MODRA, CERVENA, ZELENA, ZLTA } FARBY; FARBY c, d; c = MODRA; d = CERVENA; ak nepriradíme konštatnám hodnoty, implicitne sú 0, 1, 2, ...
BOOLEAN dobre; Príklad: boolovské hodnoty typedef enum { FALSE, TRUE } BOOLEAN; if(isdigit(c) == FALSE) ... nie je nutné ani definovať premennú premenná môže byť definovaná
Explicitná a implicitná inicializácia • explicitná inicializácia: • zoradiť podľa veľkosti • inicializujeme všetky prvky poľa typedef enum { MODRA = 0, CERVENA = 4, ZELENA = 2, ZLTA } FARBY; najhoršie možné: čiastočne explicitné, čiastočne implicitné (ZLTA bude mať hodnotu 3)
Výpis mena položky typedef enum { MODRA, CERVENA, ZELENA, ZLTA } FARBY; ... c = MODRA; chyba! printf("Farba: %s \n", c); printf("Farba: %d \n", (int) c); s pretypovaním: výpis hodnôt switch (c) { case MODRA: printf("Modra farba.\n"); break; ... } výpis mien položiek: pomocou switch
Výpis mena položky: pomocou poľa typedef enum { MODRA, CERVENA, ZELENA, ZLTA } FARBY; FARBY farba = MODRA; char *nazvy[]= { "Modra", "Cervena", "Zelena", "Zlta" }; printf("Farba: %s \n", nazvy[farba]); len pre neinicializované vymenované typy
a.c = '#'; p_a->i = 1; a.f = 2.3; premazávajú sa hodnoty Uniony • dátový typ • vyhradí sa pamäť pre najväčšiu položku • všetky položky sa prekrývajú typedef union { char c; int i; float f; } ZIF; ZIF a, *p_a = &a; Union neposkytuje informáciu o typu prvku, ktorý bol naposledy do neho uložený! vyhradí sa pamäť o veľkosti najväčšieho prvku
Union vložený do štruktúry typedef enum { ZNAK, CELE, REALNE } TYP; typedef union { char c; int i; float f; } ZIF; typedef struct { TYP typ; ZIF polozka; } ZN_INT_FL; vymenovaný typ: slúži na rozlíšenie typov union: umožňuje uchovávať znak, celé a reálne číslo štruktúra: obsahuje informáciu o type položky a samotnú položku
#include<stdio.h> #include<stdlib.h> #define MAXR 5 #define MAXS ('E' - 'A') #define NPRIKAZ 10 typedef enum { VYR, CIS } TYP; typedef struct { char oper; double l_operand; double r_operand; } VYRAZ; typedef struct { TYP typ; union { VYRAZ vyraz; double cislo; } hodnota; } BUNKA;
void inicializuj(BUNKA excel[][MAXS], int r); void priradit_vyraz(BUNKA excel[][MAXS], int r, int i, int j, char prikaz[]); double vypocitaj(VYRAZ v); void vypis_hodnoty(BUNKA excel[][MAXS], int r); void vypis_vyrazy(BUNKA excel[][MAXS], int r);
void main() { BUNKA excel[MAXR][MAXS]; int i=0, j=0; char c; char prikaz[NPRIKAZ]; inicializuj(excel, MAXR); do { printf("\n*** TABULKOVY PROCESOR ***\n"); printf("= priradene: format =o(c1,c2)\n"); printf("p presun kurzora: format prs\n"); printf("h vypis hodnot \nv vypis vyrazov\n"); printf("k koniec\n"); printf("\nKurzor: %c%d\n\n", i+'A', j); gets(prikaz);
switch (tolower(prikaz[0])) { case '=': priradit_vyraz(excel, MAXR, i, j, prikaz); break; case 'p': if (sscanf(prikaz+1, "%c %d", &c, &j) != 2) { printf("Nespravny format vstupu.\n"); break; } if ((i = toupper(c)-'A') > MAXR) i = MAXR - 1; if (i < 0) i = 0; if (j > MAXS) j = MAXS - 1; if (j < 0) j = 0; break; case 'h': vypis_hodnoty(excel, MAXR); break; case 'v': vypis_vyrazy(excel, MAXR); break; case 'k': break; default: break; } } while (prikaz[0] != 'k'); }