650 likes | 830 Views
Pro cedurálne programovanie: 10 prednáška. Gabriela Kosková. Obsah. Opakovanie v príkladoch. getchar() - na na čítavanie znakov, nie čísel!. int i ; char c ; ... c = getchar() ; scanf("%c", &c); scanf("%d", &i);. Na čítanie znaku aj pomocou getchar , aj pomocou scanf.
E N D
Procedurálne programovanie:10 prednáška Gabriela Kosková
Obsah • Opakovanie v príkladoch
getchar() - na načítavanie znakov, nie čísel! int i; char c; ... c = getchar(); scanf("%c", &c); scanf("%d", &i); Načítanie znaku aj pomocou getchar, aj pomocou scanf getchar a scanf int i; ... i = getchar();
scanf a & int i; char c, str[10], *r; r = (char *) malloc(5*sizeof(char)); scanf("%d", &i); scanf("%c", &c); scanf("%s", str); scanf("%s", r); scanf očakáva adresy premenných, do ktorých má zapísať načítanú hodnotu vo funkcii scanf sa vytvorí lokálna premenná ako kópia parametra - adresa, tam sa zapíše načítaná hodnota keď skončí funkcia, zabudne sa lokálna kópia, teda zabudne sa adresa, no na tej adrese zostane načítaná hodnota i - premenná, &i- adresa premennej, c - premenná, &c - adresa premennej, str - statická adresa poľa (reťazca znakov) r - adresa poľa (reťazca znakov)
char str[10], pismeno; int pocet; ... pismeno = najcastejsie_pismeno(str, &pocet); Vrátenie hodnoty cez parameter funkcie char najcastejsie_pismeno(char *str, int *pocet) { int hist['Z'-'A'+1], i, i_max; for (i=0; i<'Z'-'A'+1; i++) hist[i] = 0; for (i=0; i<strlen(str); i++) hist[toupper(str[i])-'A']++; i_max = 0; for (i=0; i<'Z'-'A'+1; i++) if (hist[i]>hist[i_max]) i_max = i; *pocet = hist[i_max]; return (i_max + 'A'); }
& a && Čo vypíše táto časť programu? Pomôcka: 11 = (1011)2 4 = (100)2 x = 11; y = 4; if (x && y) printf("*"); if (x & y) printf("+"); Logický súčin (&&): nenulové čísla sú PRAVDA, 11, 4 sú nenulové, preto výsledok je PRAVDA vypíše sa * Bitový súčin (&): súčin po bitoch 0: NEPRAVDA + sa nevypíše Vypíše sa *
Typová konverzia Reálne delenie dvoch celých čísel. #include <stdio.h> int main(void) { int i = 5, j = 2; float f; f = (float) i / j; printf("Typova konverzia: 1. moznost: %lf\n", f); f = i / (float) j; printf("Typova konverzia: 2. moznost: %lf\n", f); f = (float) i / (float) j; printf("Typova konverzia: 3. moznost: %lf\n", f); f = (float) (i / j); printf("Explicitna typ. konverzia - chybne: %lf\n", f); f = i / j; printf("Implicitna typ. konverzia - chybne: %lf\n", f); return 0; }
Čítanie čísel, ktoré predchádza niekoľko hviezdičiek Vrátenie znaku #include <stdio.h> int main(void){ FILE *fr; int c, cislo, suma = 0; if ((fr = fopen("cisla.txt", "r")) == NULL) { printf("Subor cisla.txt sa nepodarilo otvorit\n"); return 1; } while (1) { while ((c = getc(fr)) == '*')/* citanie znakov '*' */ ; if (c == EOF) break; ungetc(c, fr);/*vratenie znaku spat do suboru*/ fscanf(fr, "%d\n", &cislo); suma += cislo; } printf("Sucet cisel je: %d\n", suma); if (fclose(fr) == EOF) printf("Subor sa nepodarilo uzavriet.\n"); return 0; }
Ukazovatele • Premenné obsahujúce adresy • Definícia ukazovateľa: int *p; • Nikdy nepracujte s ukazovateľom, ktorý ste predtým nenasmerovali na nejakú zmysluplnú adresu! • Ak potrebujeme zaistiť, aby ukazovateľ neukazoval na konkrétne miesto priradíme mu hodnotu NULL
& - vráti adresu premennej Ukazovatele bez operátora - hodnota premennej (ak je hodnotou adresa, tak je to adresa) int **p, *q, r; p = &q; * - vráti hodnotu premennej vezme ako adresu a z tej adresy vráti hodnotu q = &r; r = 5; printf("%p %p %p %p %p %d %p %d %d", &p,&q,&r, p, q, r, *p,*q,**p); 17 51 67 51 67 5 67 5 5 p: ukazovateľ na ukazovateľ na int q: ukazovateľ na int r: int 51 67 5 17 51 67
Ukazovatele a polia int *p, q[5], i=0; for (i=0; i<5; i++) q[i] = i; p = q; p = q+2; /* to iste ako p = &q[2] */ i = *(q+2); /* to iste ako i = q[2] */ q: statický ukazovateľ na int p: ukazovateľ na int q[0]:int i:int q[1]:int q[4]:int 5 2 57 61 0 1 2 3 4 57 59 61 63 65 103 19
Ukazovatele Adresa začiatku poľa &pole[0] pole+0 pole &pole[i] pole+i pole[i] *(pole+i) pole[0]=10; *pole=10; pole[10]=70;*(pole+10)=70; Adresa i-teho prvku poľa Hodnota i-teho prvku poľa Priradenie do 1. prvku poľa Priradenie do 10. prvku poľa
Názov knihy Meno autora Rok položky jednoho záznamu jeden záznam o jednej knihe (obsahujúci všetky položky) zoznam záznamov o knihách (pole) Kartotéka v knižnici Hlava XXII Joseph Heller 1961
Príklad: Kartotéka v knižnici Program načíta celé číslo n, následne načíta n záznamov o knihách a uloží ich do poľa. Potom ponúkne používateľovi menu, kde môže pridávať záznam na koniec, zmazať ktorýkoľvek záznam a ukončiť program.
Kartotéka v knižnici: implementácia #include <stdio.h> #include <stdlib.h> #include <conio.h> #define N 50 /* dlzka retazcov znakov */ #define K 50 /* max. pocet prvkov v kartoteke */ typedef struct { char meno[N]; char priezvisko[N]; } AUTOR; typedef struct { char nazov[N]; AUTOR autor; int rok; } KNIHA;
/* nacitanie a pridanie zaznamu na koniec zoznamu*/ void pridaj(KNIHA kniznica[], int *n); /* nacitanie indexu zaznamu a jeho zmazanie */ int zmaz(KNIHA kniznica[], int n); /* vypis zoznamu */ void vypis(KNIHA kniznica[], int n); int main() { int i, n; char c; KNIHA kniznica[K]; printf("Zadajte pocet knih: "); scanf("%d", &n); if (n > K) return 1; i = 0; /* nacitanie zaznamov do zoznamu */ while (i < n) pridaj(kniznica, &i);
do { vypis(kniznica, n); printf("p: pridanie\nz: zmazanie\nk: koniec\n"); c = tolower(getch()); switch(c) { case 'p': pridaj(kniznica, &n); break; case 'z': n = zmaz(kniznica, n); break; } } while (c != 'k'); return 0; }
void pridaj(KNIHA kniznica[], int *n) { if ((*n+1) > K) { printf("Kniznica je plna.\n"); return; } else { printf("Zadajte nazov knihy, autora (meno, "); printf("priezvisko) a rok vydania:\n"); scanf("%s %s %s %d", kniznica[*n].nazov, kniznica[*n].autor.meno, kniznica[*n].autor.priezvisko, &kniznica[*n].rok); (*n)++; } }
int zmaz(KNIHA kniznica[], int n) { int i; printf("Zadajte index zaznamu na zmazanie: "); scanf("%d", &i); if (i < 0 || i >= n-1) { printf("Prvok sa v poli nenachadza.\n"); return n; } while (i < n-2) { kniznica[i] = kniznica[i+1]; i++; } return n-1; }
void vypis(KNIHA kniznica[], int n) { int i; printf("\nKNIZNICA\n\n"); for (i=0; i<n; i++) printf("%s %s: %s (%d)\n", kniznica[i].autor.meno, kniznica[i].autor.priezvisko, kniznica[i].nazov, kniznica[i].rok); printf("\n\n"); }
Námety na precvičenie • kartotéka ako spájaný zoznam: typedef struct kniha{ char nazov[N]; AUTOR autor; int rok; struct kniha *dalsia; } KNIHA;
Príklad: Zlomky • oddelený preklad: • modul zlomky: zlomky.c a zlomky.h • modul hlavny: hlavny.c
zlomky.h typedef struct { int citatel; int menovatel; } ZLOMOK; extern ZLOMOK *spocitaj(ZLOMOK *a, ZLOMOK *b); extern void vypis(ZLOMOK a);
zlomky.c #include <stdio.h> #include "zlomky.h" ZLOMOK *spocitaj(ZLOMOK *a, ZLOMOK *b) { int n; ZLOMOK *z = (ZLOMOK *) malloc(sizeof(ZLOMOK)); z->citatel = a->citatel* b->menovatel + b->citatel * a->menovatel; z->menovatel = a->menovatel * b->menovatel; n = nsd(z->citatel, z->menovatel); z->citatel /= n; z->menovatel /= n; return z; } void vypis(ZLOMOK *a) { printf("%d / %d\n", a->citatel, a->menovatel); } static int nsd(int a, int b) { /* o chvilu... */ }
hlavny.c #include <stdio.h> #include "zlomky.h" int main() { ZLOMKY *x, *y, *z; x = (ZLOMOK *) malloc(sizeof(ZLOMOK)); y = (ZLOMOK *) malloc(sizeof(ZLOMOK)); printf("Zadajte dva zlomky: "); scanf("%d %d", &x->citatel, &x->menovatel); scanf("%d %d", &y->citatel, &y->menovatel); z = spocitaj(x, y); printf("Sucet zlomkov je: "): vypis(z); return 0; }
typedef struct { int citatel; int menovatel; } ZLOMOK; extern ZLOMOK *spocitaj(ZLOMOK *a, ZLOMOK *b); extern void vypis(ZLOMOK a); zlomky.h #include <stdio.h> #include "zlomky.h" ZLOMOK *spocitaj(ZLOMOK *a, ZLOMOK *b) { int n; ZLOMOK *z = (ZLOMOK *) malloc(sizeof(ZLOMOK); z->citatel = a->citatel + b->citatel; z->menovatel = a->menovatel + b->menovatel; n = nsd(z->citatel, z->menovatel); z->citatel /= n; z->menovatel /= n; } void vypis(ZLOMOK *a) { printf("%d / %d\n", a->citatel, a->menovatel); } static int nsd(int a, int b) { } #include <stdio.h> #include "zlomky.h" int main() { ZLOMKY *x, *y, *z; x = (ZLOMOK *) malloc(sizeof(ZLOMOK)); y = (ZLOMOK *) malloc(sizeof(ZLOMOK)); printf("Zadajte dva zlomky: "); scanf("%d %d", &x->citatel, &x->menovatel); scanf("%d %d", &y->citatel, &y->menovatel); z = spocitaj(x, y); printf("Sucet zlomkov je: "): vypis(z); return 0; } hlavny.c zlomky.c
NSD a NSN program načíta dve celé čísla a vypíše ich najväčší spoločný deliteľ (NSD) a najmenší spoločný násobok (NSN).
NSD • platí • NSD(0,0)=0 • NSD(a, b)=NSD(b, a) • NSD(a, b)=NSD(-a, b) • NSD(a,0)=ABS(a) budeme uvažovať len nezáporné čísla • algorimtus: • Eukleidos popísal tento algoritmus v knihe Základy (okolo r. 300 p.n.l.). Algoritmus je založený na platnosti rekurzívneho vzťahu: NSD(a, b)=NSD(b, a % b)
Dôkaz algoritmu • Predpokladajme, že: • a, b - čísla, ktorých NSD chceme nájsť • zvyšok po delení a/b je t, teda a = qb + t • Potom • každý spoločný deliteľ a a b delí t bezo zvyšku (lebo t = a - qb) • podobne, každý spoločný deliteľ b a t tiež delí a • Potom aj najväčší spoločný deliteľ a a b je tiež najväčším spoločným deliteľom b a t • Potom sa dá ďalej pokračovať s b a t namiesto a a b. Keďže t je menšie v absolútnej hodnote, pokým t nedosiahne 0
NSD int nsd(int a, int b) { int pom; do { if (a < b) { pom = a; a = b; b = pom; } a %= b; } while (a); return b; }
NSN • najmenšie kladné číslo, ktoré je násobkom čísel a, b • algorimtus: • vychádza zo vzťahu: a * b =NSD(a, b)*NSN(a, b) int nsn(int a, int b) { return a * b / nsd(a, b); }
NSD a NSN #include <stdio.h> int nsd(int a, int b); int nsn(int a, int b); void main(void) { int m, n; scanf("%d %d",&m,&n); printf("NSD(%d,%d) = %d\n",m, n, nsd(m, n)); printf("NSN(%d,%d) = %d\n",m, n, nsn(m, n)); }
Po Ut St Št Pi So Ne Matematika Mrkvička 3 hodiny Príklad rozvrh Program načíta zo súboru údaje o hodinách v rozvrhu a vypíše rozvrh na obrazovku • dvojrozmerné pole • práca so súborom • štruktúra • parametre funkcie main
vyuč. hodina: 4 riadne hodiny 4 záznamy: MAT Maly 0 MAT Maly 1 MAT Maly 1 MAT Maly 1 Vstupný súbor a štruktúra 1 1 MAT Maly 4 2 3 FYZ Velky 2 3 2 ANG Pekna 3 3 3 TEL Vesely 10 5 3 SJ Zeleny 1 • Súbor: • deň hodina • skratka predmetu • meno učiteľa • počet hodín • Štruktúra: • predmet • ucitel • cast: • -1: voľno • 0: začiatok vyuč. hodiny • 1: stred alebo koniec vyuč.hodiny • Námet na precvičenie: • Rozvrh ako pole spájaných zoznamov
Rozvrh: príklad výstupu ROZVRH ----------------------------------------------------------------------- | Pondelok| MAT, Maly | | ----------------------------------------------------------------------- | Utorok| | | FYZ,Velky | | ----------------------------------------------------------------------- | Streda| | ANG,Pekna| TEL,Vesel | ----------------------------------------------------------------------- | Stvrtok| | | | | | ----------------------------------------------------------------------- | Piatok| | | SJ,Zelen| | | ----------------------------------------------------------------------- | Sobota| | | | | | ----------------------------------------------------------------------- | Nedela| | | | | | -----------------------------------------------------------------------
#include <stdio.h> #include <string.h> #define N 6 /* pocet pismen v slove (5 znakov) */ #define ND 7 /* pocet dni */ #define NH 5 /* pocet hodin */ #define SUBOR "subor.txt" /* default nazov subora */ typedef enum { pondelok, utorok, streda, stvrtok, piatok, sobota, nedela }; typedef struct { char predmet[N]; char ucitel[N]; int cast; /* -1 volno, 0 zaciatok, 1 stred,koniec */ } HODINA; char *dni[] = {"Pondelok", "Utorok", "Streda", "Stvrtok", "Piatok", "Sobota", "Nedela"};
void inicializuj(HODINA rozvrh[][NH]); int nacitaj(HODINA rozvrh[][NH], char subor[]); void vypis(HODINA rozvrh[][NH]); int main (int argc, char *argv[]) { HODINA rozvrh[ND][NH]; char subor[N]; if (argc == 2) strcpy(subor, argv[1]); else strcpy(subor, SUBOR); inicializuj(rozvrh); if (nacitaj(rozvrh, subor)) { return 1; } vypis(rozvrh); return 0; }
void inicializuj(HODINA rozvrh[][NH]) { int i, j; for(i=0; i<ND; i++) for(j=0; j<NH; j++) rozvrh[i][j].cast = -1; }
/* nacitanie rozvrhu zo subora */ int nacitaj(HODINA rozvrh[][NH], char subor[]) { int i, den, hodina, dlzka; FILE *f; if ((f = fopen(subor, "r")) == NULL) { printf("Nepodarilo sa otvorit subor %s.\n", subor); return 1; } while(!feof(f)) { fscanf(f, "%d %d", &den, &hodina); den--; hodina--; fscanf(f, "%s", rozvrh[den][hodina].predmet); if (strlen(rozvrh[den][hodina].predmet) > 5) rozvrh[den][hodina].predmet[5] = '\0'; /*5 zn.*/ fscanf(f, "%s", rozvrh[den][hodina].ucitel); if (strlen(rozvrh[den][hodina].ucitel) > 5) rozvrh[den][hodina].ucitel[5] = '\0'; /*5 zn.*/ fscanf(f, "%d", &dlzka); rozvrh[den][hodina].cast = 0; /*zaciatok vyuc. h.*/
/* ak ma vyuc.hod. viac ako 1 hodinu, naplnia sa dalsie zaznamy */ if (dlzka > 1) { for (i=1; i<dlzka && hodina+i < NH; i++) { rozvrh[den][hodina+i] = rozvrh[den][hodina]; rozvrh[den][hodina+i].cast = 1; } } } if(fclose(f) == EOF) printf("Subor sa nepodarilo zatvorit.\n"); return 0; }
void vypis(HODINA rozvrh[][NH]) { int i, j; printf("\nROZVRH\n\n"); for(i=0; i<ND; i++) { /* horna ciara + ciary oddelujuce dni */ for(j=0; j<NH*12+1+10; j++) putchar('-'); printf("\n|%9s", dni[i]); /* oznacenie dna */
/* riadok */ for(j=0; j<NH; j++) { if (j == 0 || rozvrh[i][j].cast < 1) putchar('|'); /* ciara pred vyuc. hod. */ else putchar(' '); /* vo vnutri v.h. ' ' */ if (rozvrh[i][j].cast == 0) /* vypis udajov */ printf("%5s,%5s", rozvrh[i][j].predmet, rozvrh[i][j].ucitel); else printf(" "); /* medzery */ if (j == NH-1) putchar('|'); /* koniec dna */ } putchar('\n'); /* prechod na dalsi riadok-den */ } /* dolna ciara */ for(j=0; j<NH*12+1+10; j++) putchar('-'); printf("\n"); }
Binárne operácie #include <stdio.h> int main(){ printf("1 << 1 = %d\t%x\n", 1 << 1, 1 << 1); printf("1 << 7 = %d\t%x\n", 1 << 7, 1 << 7); printf("1024 >> 9 = %d\t%x\n",1024 >> 9,1024 >>9); printf("13 & 6 = %d\t%x\n", 13 & 6, 13 & 6); printf("13 | 6 = %d\t%x\n", 13 | 6, 13 | 6); printf("13 ^ 6 = %d\t%x\n", 13 ^ 6, 13 ^ 6); printf("2 & 1 = %d\t%x\n", 2 & 1, 2 & 1); printf("2 | 1 = %d\t%x\n", 2 | 1, 2 | 1); printf("2 ^ 1 = %d\t%x\n", 2 ^ 1, 2 ^ 1); return 0; } 128 = 27 1024 = 210 13: 1101 6: 110 1: 01 2: 10 1 << 1 = 2 0x2 1 << 7 = 128 0x80 1024 >> 9 = 2 0x2 13 & 6 = 4 0x4 13 | 6 = 15 0xf 13 ^ 6 = 11 0xb 2 & 1 = 0 0 2 | 1 = 3 0x3 2 ^ 1 = 3 0x3
Binárne operácie vytvoricislo s 1 napozíciii, ostatnesu 0 #include <stdio.h> #define vytvorit_cislo(i) (1<<(i)) #define rad(x,i) (((x)>>(i))&1) unsigned invert(unsigned x,int i, int n){ unsigned j; for (j=i;j<i+n;j++){ if (rad(x,j)==0) x=x|(vytvorit_cislo(j)); else x=x&(~(vytvorit_cislo(j))); } return x; } void vypis(unsigned x){ if (x>0) { vypis(x>>1); printf("%d",x&1); } } vraticislicui-tehoraducislax Rekurzívny výpis
Vyhľadávanie v usporiadanom poli program načíta do poľa usporiadanú postupnosť čísel a hodontu, ktorú chce v postupnosti (v poli) vyhľadať (nájsť jej index): použije sekvenčné a binárne vyhľadávanie
Sekvenčné vyhľadávanie • najjednoduchšie vyhľadávanie: • od začiatku poľa postupne zväčšuje index pokým nepríde na hodnotu, korá je väčšia alebo rovná alebo pokým nepríde na koniec poľa • neefektívne
Sekvenčné vyhľadávanie int sekvencne(int pole[], int n, int x) { int i=0; while(i < n && pole[i] < x) i++; if(pole[i] == x) return i; return -1; }
0 1 2 3 4 5 6 7 8 9 10 11 12345 6 7 8 9 10 11 12 Binárne vyhľadávanie • nájdenie stredu intervalu - ak je hľadaná hodnota menšia ako hodnota stredného prvku hľadanie v ľavej polovici, inak v pravej polovici hľadáme pozíciu hodnoty 7
int binarne(int pole[], int n, int x) { int m, l = 0, r = n-1; while (l <= r) { m = (l + r) / 2; if (x == pole[m]) return m; if (x < pole[m]) r = m - 1; else l = m + 1; } if (pole[m] == x) return m; else return -1; }
#include <stdio.h> #include <stdlib.h> int sekvencne(int pole[], int n, int x); int binarne(int pole[], int n, int x); int main() { int p[100], i, n, x, vysl; char c; printf("Zadaj pocet prvkov pola (<100): "); scanf("%d", &n); if (n >= 100) { printf("Prilis velky pocet prvkov...\n"); return 1; } for (i=0; i<n; i++) { printf("p[%d]: ", i); scanf("%d", &p[i]); }