Jazyk C (príklady) - Vzorové príklady: Rozdiel medzi revíziami
(Vytvorená stránka „Kategória:Študijné materiály Kategória:Informatika {{Priklady_ZI}} __TOC__ ==Obsah== V ďalšom texte budú ukázané zložitejšie príklady, ktoré už v…“) |
|||
Riadok 261: | Riadok 261: | ||
− | |||
− | |||
− | |||
+ | |||
+ | ;Vzorec 1: <math>l=\int_a^b\ f(x)dx,</math> kde <math> f(x)= a_nx^n+a_{n-1}x^{n-1}+...+a_1x^1+a_0x^0</math> | ||
+ | ;Vzorec 2: <math>l=\sum_{i=0}^{m} d\frac{ (f(x_i) + f(x_{i+1}) }{2}</math> ,kde <math>d=\frac{ \left( d-a \right)} {m}</math> | ||
+ | [[Súbor:Funkcia.png |550px|none|náhľad|left|Priebeh]] | ||
Hlavný program trochu upravíme, aby sme dodržali zadanie, že máme určiť optimálnu presnosť. Budeme opakovane volať funkciu integral, vždy s dvojnásobnou presnosťou integrovania (hodnotu m vždy vynásobíme číslom 2). | Hlavný program trochu upravíme, aby sme dodržali zadanie, že máme určiť optimálnu presnosť. Budeme opakovane volať funkciu integral, vždy s dvojnásobnou presnosťou integrovania (hodnotu m vždy vynásobíme číslom 2). | ||
Riadok 324: | Riadok 325: | ||
}while(getch() != 'a'); | }while(getch() != 'a'); | ||
} | } | ||
− | </source> | + | </source> |
===Analyzátor textu=== | ===Analyzátor textu=== |
Verzia zo dňa a času 11:33, 6. máj 2020
Riešené príklady
zdroj: Juraj Ďuďák, Zbierka úloh z algoritmizácie pre predmet Základy informatiky
ISBN: 978-80-8075-199-9
Obsah
Obsah
V ďalšom texte budú ukázané zložitejšie príklady, ktoré už viac či menej využívajú doposiaľ zvládnuté problémy. Prvé dva príklady (uhádni číslo, hra so zápalkami) sú jednoduché hry, kde je úloha postaviť počítač do úlohy protihráča, teda naprogramovať danú hru tak, aby počítač hral čo najlepšie (pojem inteligentne nie je namieste, pretože problematika umelej inteligencie ďaleko prevyšuje túto publikáciu).
Ďalšie dva príklady sú ukážky ako pomocou malých jednoduchých krokov, napísať komplexnejší program. V príklade určitý integrál je úlohou vypočítať určitý integrál z polynomiálnej funkcie. V poslednom prípade je za úlohu urobiť štatistiku textu, podobnú ako robí napr. textový editor MS Word.
Príklady
Uhádni číslo
- Zadanie
- Naprogramujeme hru, kde bude človek hádať číslo z daného intervalu. Toto číslo si vymyslí (vygeneruje) počítač. Základné princípy hry:
Počítač si vymyslí číslo od 1 do 100
- Hráč musí uhádnuť toto číslo
- Hráč má obmedzený počet pokusov
- Počítač bude hráčovi radiť, pri tipovaní
- Položka zoznamu s odrážkami
- Postup pri programovaní tohto problému
- Počítač si vymyslí číslo
- Hráč háda číslo
- Ak uhádol, hra skončila
- Ak neuhádol
- Počítač napovie: hádaj väčšie/menšie číslo
- Ak sa prekročil povolený počet pokusov - koniec
- Inak, Skoč na 2
V programe si zadefinujeme 2 globálne konštanty. MAX_TIP=100 // horná hranica ktoré môže mať číslo, ktoré vygeneruje počítač POCET_POKUSOV =10 // max. počet pokusov pri hádaní
Pre hádanie čísla (človek háda číslo) si vytvorme funkcie tipniSi. Funkcia vráti číslo, ktoré človek zadal.
1 int TipniSi()
2 {
3 int t;
4 printf("\nTipni si cislo od 1 do %d: ",MAX_TIP);
5 scanf("%d",&t);
6 return t;
7 }
Ďalšia funkcia vyhodnotí tip človeka. Teda ak človek zadal malé číslo, program vypíše „zadaj väčšie číslo“. V opačnom prípade vypíše „zadaj menšie číslo"
1 void Vyhodnot(int cislo,int tip)
2 {
3 if(tip>cislo)
4 printf("Skus si tipnut mensie\n");
5 else
6 printf("Skus si tipnut vacsie\n");
7 }
Hlavná funkcia – počítač vygeneruje náhodné číslo od 1 do MAX_TIP. Potom nasleduje samotné hádanie tohto čísla. Nasleduje výpis jednoduchšej verzie:
1 int main()
2 {
3 int tip; // nas tip
4 srand(time(NULL));
5 int cislo=1+rand()%MAX_TIP;
6 tip=tipniSi();
7 while(tip!=cislo)
8 {
9 Vyhodnot(cislo,tip);
10 tip=TipniSi();
11 }
12 }
Funkcia srand(); inicializuje generátor pseudonáhodných čísel. Ako parameter má inicializažný parameter, ktorý by malbyť tieť náhodným číslom. Preto použijeme ako parameter volanie funkcie time() ktorá vracia počet milisekúnd od 1.1.1970. Funkcia time() je definovaná v hlavičkovom súbore time.h. Samotné generovanie náhodného čísla robí funkcia rand(), ktorá generuje pseudonáhodné číslo od 0 do RAND_MAX (čo je 32767). Ak chceme generovať po hranicu MAX_TIP, môžeme použiť zvyšok po delení náhodného čísla a konštanty MAX_TIP.
Vo vylepšenej verzii hlavnej funkcie máme obmedzený počet pokusov hádanie čísla na POCET_POKUSOV. V prípade, ak človek neuhádne ani na posledný pokus (uspech=0), človek prehrá hru. Ak uhádne číslo v limite, hru vyhráva.
Listing programu:
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<time.h>
4 #define MAX_TIP 100
5 #define POCET_POKUSOV 10
6 //----------------------------------------------------------------
7 int TipniSi()
8 {
9 int t;
10 printf("\nTipni si cislo od 1 do %d: ",MAX_TIP);
11 scanf("%d",&t);
12 return t;
13 }
14 //---------------------------------------------------------------------
15 void Vyhodnot(int cislo,int typ)
16 {
17 if(typ>cislo)
18 printf("Skus si tipnut mensie\n");
19 else
20 printf("Skus si tipnut vacsie\n");
21 }
22 //--------------------------------------------------------------------
23 int main()
24 {
25 int tip; // nas tip
26 int uspech=1;
27 srand(time(NULL));
28 int cislo=1+rand()%MAX_TIP;
29 tip=tipniSi();
30 int pokusy=1;
31 while(tip!=cislo)
32 {
33 if(pokusy>=POCET_POKUSOV)
34 { printf("Vycerpany pocet pokusov, prehral si\n");
35 uspech=0;
36 break;
37 }
38 Vyhodnot(cislo,tip);
39 tip=TipniSi();
40 pokusy++;
41 }
42 if(uspech)
43 printf("Uhadol si cislo %d na %d pokus",cislo, pokusy);
44 else
45 printf("Neuhadol si cislo %d.",cislo);
46 }
Hra so zápalkami
- Zadanie
- V hre zápalky je na stole n zápaliek. Hrajú dvaja hráči. Hráči sa striedajú a berú z kopy 1, 2, alebo 3 zápalky. Prehráva ten, kto zoberie z kopy poslednú zápalku.
V tejto verzii bude hrať jeden hráč proti počítaču. Treba vymyslieť najlepšiu stratégiu pre počítač, aby sa vždy snažil vyhrať. Základný princíp programu ilustruje nasledujúci pseudokód.
1 int stroj = 0;
2 pocet // pocet zapaliek
3 "zadanie počtu zápaliek "
4 do
5 {
6 if (stroj)
7 "Stroj odoberie zápalky"
8 else
9 "človek odoberie zápalky"
10 stroj = !stroj;
11 } while (pocet>0);
12 if (stroj)
13 "vyhral stroj"
14 else
15 "vyhral hráč"
Premenná stroj môže mať 2 hodnoty: 0 alebo 1. Ak je stroj=1, na rade je stroj. V prípade že stroj=0, z kopy berie zápalky človek. Z kopy sa berie potiaľ, pokiaľ tam zostanú nejaké zápalky.
Tento pseudokód môžeme upraviť do jazyka C. V zdrojovom kóde sú funkcie, ktoré si naprogramujeme neskôr.
1 int main()
2 {
3 int pocet_zapaliek;
4 pocet_zapaliek=ZadajPocetZapaliek();
5 int stroj=0;
6 do { if(stroj)
7 BereStroj(pocet_zapaliek);
8 else
9 BereHrac(pocet_zapaliek);
10 stroj=!stroj;
11 }while(pocet_zapaliek);
12 if(stroj)
13 printf("\nVyhral stroj");
14 else
15 printf("\nVyhral si!!!“);
16 }
Funkcia ZadajPocetZapaliek(); vygeneruje a vráti náhodné číslo od 15 do 50. Je to počet zápaliek, s ktorými budeme hrať.
1
2 int ZadajPocetZapaliek()
3 { int pocet;
4 randomize();
5 pocet =15+rand()%35; // cislo od 15 do 50
6 return pocet;
7 }
Funkcia void BereHrac(int &zapalky); nám rieši prípad, keď hráč berie z kopy zápalky. Hráč može zobrať 1, 2 alebo 3 zápalky. Nemôže zobrať viac zápaliek, ako je na kope. Funkcia nič nevráti (je typu void). Ako argument funkcie je počet zápaliek na kope. Keďže tento argument je predaný odkazom, zmenou hodnoty vo funkcii sa zmení jej hodnota i vo funkcii main. Vo funkcii je jeden cyklus, ktorý sa opakuje dovtedy, pokiaľ hráč nezoberie povolený počet zápaliek. Potom sa tento počet odčíta z celkového počtu zápaliek.
1
2 void BereHrac(int &zapalky)
3 { int x,error=0;
4 printf("\nHrac berie: ");
5 do{
6 error=0;
7 scanf("%d",&x);
8 if(x>zapalky)
9 { printf("\nNeda sa odobrat viac zapaliek, ako je na kope.");
10 error=1;
11 }
12 else if(x>3)
13 { printf("\nNajviac mozete odobrat 3 zapalky.");
14 error=1;
15 }
16 if(x<1)
17 { printf("\nOdobrali ste malo zapaliek.");
18 error=1;
19 }
20 }while(error);
21 zapalky-=x;
22 printf("\nHrac odobral %d zapaliek.\nPocet zapaliek na kope: %d\n",x,zapalky);
23 }
- Pravidlá pre odoberanie zápaliek strojom, ktoré vedú k víťazstvu (ak je to možné)
- počet zápaliek nevýhodných pre protihráča je 1, 5, 9, atď., všeobecne 4n+1, kde n je celé nezáporné číslo,
- stroj musí z počtu p zápaliek odobrať x zápaliek tak, aby platilo p – x = 4n + 1
- z tohto vzťahu po úprave a s ohľadom na obmedzenia pre x dostaneme x = (p – 1) mod 4
- Ak bude x=0, znamená to, že okamžitý počet zápaliek je pre stroj nevýhodný a ak bude protihráč postupovať správne, stroj prehrá. V tomto prípade stroj odoberie 1 zápalku.
1
2 void BereStroj(int &zapalky)
3 {
4 printf("\nStroj berie: ");
5 int x=(zapalky-1)%4; // vypocet najlepsieho pocetu zapaliek, ktore moze zobrat stroj
6 if(x==0) x=1;
7 zapalky-=x;
8 printf("\nStroj odobral %d zapaliek.\nNa kope je %d zapaliek",x,zapalky);
9 }
Určitý integrál
- Zadanie
- Navrhnite program, ktorý by vypočítal určitý integrál z polynomiálnej funkcie f(x) stupňa n. Interval integrovania je daný hodnotami a a b. Čiže máme vypočítať (pozri vzorec 1). Tento integrál vypočítajte s rôznou presnosťou výpočtu. Výsledky porovnajte a určite optimálnu presnosť. Na výpočet daného integrálu použijeme obdĺžnikovú metódu – interval (a,b) si rozdelíme na m častí. Veľkosť premennej m nám určuje presnosť výpočtu. Čím je m väčšie, tým dosiahneme vyššiu presnosť. Ak zvolíme delenie na m častí, potom delenie d intervalu (a,b) môžeme vypočítať ako: d=(b-a)/m. Pri výpočte integrálu budeme spočítavať obsah obdĺžnikov, ktorých jedna strana má veľkosť d a druhá strana má veľkosť [f(xi+1)+f(xi)]/2. Na obrázku je to oblasť Si. Týmito úvahami sme si pôvodný problém výpočtu integrálu transformovali na výpočet sumy: (pozri vzorec 2)
- Na výpočet funkčnej hodnoty polynómu použijeme už naprogramovanú funkciu
- float h_polynom(float koeficienty[MAX], int stupen, float x0);
- Na samotný výpočet integrálu si naprogramujeme funkciu
- float integral(float poly[MAX],int n, float a, float b, int m);
kde:
- poly – polynóm, z ktorého budeme počítať integrál
- n – stupeň polynómu poly
- a, b - určujú hranice integrovania
- m – definuje presnosť integrovania
Vo funkcii integral budeme počítať integrál pomocou cyklu for. Budeme vždy počítať funkčnú hodnotu polynómu v bode a, pričom každý v každej iterácii cyklu zvýšime hodnotu a o hodnotu d. Funkcia integral môže vyzerať takto:
1
2 float integral(float poly[MAX],int n, float a, float b, int m)
3 {
4 float I=0,xi1,xi;
5 float d=(b-a)/m;
6 xi = h_polynom(poly,n,a); // hodnota v bode xi , funkcia h_polynom bola definovana v kap. 6
7 for(int i=0; i<m; i++,a+=d)
8 {
9 xi1 = h_polynom(poly,n,(a+d)); // hodnota v bode xi+1
10 I+=d*(xi+xi1)/2; // vypocet vysledneho integralu
11 xi=xi1;
12 }
13 return I;
14 }
- Vzorec 1
- [math]l=\int_a^b\ f(x)dx,[/math] kde [math] f(x)= a_nx^n+a_{n-1}x^{n-1}+...+a_1x^1+a_0x^0[/math]
- Vzorec 2
- [math]l=\sum_{i=0}^{m} d\frac{ (f(x_i) + f(x_{i+1}) }{2}[/math] ,kde [math]d=\frac{ \left( d-a \right)} {m}[/math]
Hlavný program trochu upravíme, aby sme dodržali zadanie, že máme určiť optimálnu presnosť. Budeme opakovane volať funkciu integral, vždy s dvojnásobnou presnosťou integrovania (hodnotu m vždy vynásobíme číslom 2).
1
2 #include <stdio.h>
3 #include <string.h>
4 #include <conio.h>
5 #define MAX 10
6
7 float h_polynom(float koeficienty[MAX], int stupen, float x0)
8 {
9 float f_hodnota=0; // funkcna hodnota polynomu v x0
10 float x=1;
11 for(int i=0 ; i<= stupen ; i++) // vypocet hodnoty polynomu v x0
12 {
13 f_hodnota += koeficienty [i] * x; // ai*x0^i
14 x*=x0;
15 }
16 return f_hodnota;
17 }
18 //---------------------------------------------------------------
19 float integral(float poly[MAX],int n, float a, float b, int m)
20 {
21 float I=0,xi1,xi;
22 float d=(b-a)/m;
23 xi = h_polynom(poly,n,a);
24 for(int i=0; i<m; i++,a+=d)
25 {
26 xi1 = h_polynom(poly,n,(a+d));
27 I+=d*(xi+xi1)/2;
28 xi=xi1;
29 }
30 return I;
31 }
32 //------------------------------------------------------------
33 void main()
34 {
35 int n,i;
36 float polynom[100],x1;
37 float a,b;
38 printf("Zadaj stupen polynomu\n");
39 scanf("%d",&n);
40 for(i=0 ; i<=n ; i++)
41 {
42 printf("\nZadaj prvok a[%d]",i);
43 scanf("%f",&polynom[i]); // nacitavanie prvkov do pola
44 }
45 printf("Zadaj hranice integrovania\n");
46 scanf("%f %f",&a,&b);
47 int m;
48 // urcenie hodnotu m
49 m=(b-a)*10; // krok bude 0.1
50 do
51 {
52 printf("(delenie:%d) I=%f \n",m,integral(polynom,n,a,b,m));
53 printf("Staci Vam vypocitana presnost ? (a/n) \n");
54 m*=2;
55 }while(getch() != 'a');
56 }
Analyzátor textu
- Zadanie
- V niektorých textových editoroch je možnosť zobraziť si štatistiku o počte znakov, slov a viet v texte. Takúto štatistiku si naprogramujeme v tomto príklade. Náš program bude vyhodnocovať:
- počet všetkých znakov
- počet všetkých znakov, ktoré sa dajú zobraziť
- počet slov
- počet viet
- počet riadkov
- priemerný počet znakov v jednom riadku
Analyzovaný text bude v textovom súbore. Meno súboru sa programu zadá pomocou spúšťacieho argumentu (napr analyzuj.exe subor.txt). Náš program sa bude volať analyza. Pri spúšťaní musí mať program jeden argument, ktorý bude názov súboru, ktorý chceme analyzovať. Ak argument chýba, program sa ukončí. Ak tam argument je, program sa pokúsi otvoriť súbor s menom, udaným v argumente. Dajme tomu že chceme analyzovať súbor zivotopis.txt . Program budeme spúšťať nasledovne: (cez príkazový riadok) analyza zivotopis.txt
- Práca so spúšťacími argumentmi.
Pre použitie argumentov musíme trochu upraviť hlavičku funkciu main nasledovne:
void main(int argc, char *argv[])
- argc: počet argumentov pri volaní funkcie. Prvý argument je názov programu, preto hodnota argc je vždy o 1 väčšia ako je skutočný počet argumentov.
- *argv[]: pole argumentov (pole ukazovateľov na dátový typ char)
- argv[0] je názov programu
- argv[1] je prvý argument
Pri volaní analyza zivotopis.txt bude argc=2, argv[0]=“analyza“, argv[1]=“zivotopis.txt“ V nasledujúcom kóde si ukážeme otvorenie súboru s menom prvého argumentu:
1
2 void main(int argc, char *argv[])
3 {
4 if(argc==1 || argc>2)
5 {
6 printf("Spravne pouzitie programu: 'analyza subor'");
7 return;
8 }
9 FILE *f;
10 f=fopen(argv[1],"r");
11 if(f==NULL)
12 printf("Subor %s sa nepodarilo otvorit",argv[1]);
13 else
14 {
15 // praca so suborom
16 fclose(f);
17 }
18 }
Ako v súbore spočítať:
- Znaky: Zo súboru budeme čítať po znakoch. Tieto znaky budeme hneď spočítavať.
- Tlačiteľné znaky: sú to všetky znaky – biele znaky. Teda sú to všetky znaky, ktoré sa dajú vytlačiť. V ASCII tabuľke sú to znaky od 33(!) po 126(~).
- Slová: Slová sú oddelené jednou alebo viac bielymi znakmi. Ak sa za slovom nachádza viac bielych znakov, musíme túto situáciu ošetriť. Výskyt slova pripočítame len v tom prípade ak narazíme na biely znak a zároveň bol predchádzajúci znak tlačiteľný.
- Vety: za každou vetou je bodka
- Riadky: na konci každého riadku je znak nový riadok "\n". Za posledným riadkom je symbolická konštanta EOF.
Vytvorme si pomocné funkcie, ktoré budú zisťovať, či je znak písmeno, číslo alebo biely znak
Test na biely znak.
Biely znak môže byť medzera (kód 32) nový riadok (kód 13, 10) alebo tabulátor (kód 9). Funkcia vráti 1, ak je znak biely znak.
1 int je_bielyznak(int c)
2 {
3 if(c==9 || c==13 || c==10 || c==32)
4 return 1;
5 else return 0;
6 }
Tlačiteľné znaky sú všetky znaky v ASCII tabuľke od 33 do 126. Funkcia vráti 1 ak je argument funkcie tlačiteľný znak.
1 int je_znak(int c)
2 {
3 if(c>31 && c<127)
4 return 1;
5 else return 0;
6 }
Tieto funkcie využijeme v hlavnej funkcii. Môžeme využiť i funkcie definované v knižnici ctype.h (isalnum, isdigit, isprint, isalpha ...).
- Listing programu
1 #include <stdio.h>
2 #include <string.h>
3 #include <conio.h>
4 #define MAX 10
5 //––––––––––––––––––––––––––––––––––
6 int je_bielyznak(int c)
7 {
8 if(c==9 || c==13 || c==32)
9 return 1;
10 else return 0;
11 }
12 //––––––––––––––––––––––––––––––––––
13 int je_znak(int c)
14 {
15 if(c>31 && c<127)
16 return 1;
17 else return 0;
18 }
19 //––––––––––––––––––––––––––––––––––
20 void main(int argc, char *argv[])
21 {
22 if(argc==1 || argc>2)
23 {
24 printf("Spravne pouzitie 'analyza subor'");
25 return;
26 }
27 FILE *f;
28 f=fopen(argv[1],"r");
29 if(f==NULL)
30 printf("Subor %s sa nepodarilo otvorit",argv[1]);
31 else
32 {
33 int vsetky_znaky=0,tlac_znaky=0,slova=0,vety=0,riadky=1;
34 int znaky_v_riadku=0,riadok_znaky=0;
35 char c,tmp=' '; // v premennej tmp je predchadzajuci nacitany znak
36 do
37 {
38 c = fgetc(f);
39 znaky_v_riadku++;
40 vsetky_znaky++;
41 if(!je_bielyznak(c)) // tlacitelne znaky
42 tlac_znaky++;
43 if(je_bielyznak(c) && !je_bielyznak(tmp) ) // pocitadlo slov
44 slova++;
45 if(c=='.') // pocitadlo viet
46 vety++;
47 if(c=='\n' || c==EOF) // pocitadlo riadkov. Posleny riadok je ukonceny konstantou EOF
48 {
49 riadok_znaky+=znaky_v_riadku;
50 znaky_v_riadku=0;
51 riadky++;
52 }
53 tmp=c;
54 } while (c != EOF); /* opakuje az po koniec suboru */
55
56 fclose(f);
57 printf("\nznaky:\t\t%d",vsetky_znaky);
58 printf("\ntlacitelne:\t%d",tlac_znaky);
59 printf("\nslova:\t\t%d",slova);
60 printf("\nvety:\t\t%d",vety);
61 printf("\nriadky:\t\t%d",riadky);
62 printf("\npriemer riadku:\t%.3f",(float)riadok_znaky/riadky);
63 }
64 }