a Základy algoritmizace a programování Přednáška 12. října 2011
Co už víme Algoritmus...... za nás počítač nevymyslí! Program... Základní příkazy jsou: přiřazení větvení (podmíněný) if (...)...else... cyklus (opakování) for...while...do - while v příkazech se vyskytují proměnné proměnné mají jméno a hodnotu prozatím používáme jednoduché proměnné - bud celočíselné nebo reálné.
Oblast "viditelnosti" (platnosti) proměnných Podle místa deklarace jsou proměnné lokální nebo globální. Oblastí lokalizace je blok, ve kterém je proměnná deklarována. Globální proměnné jsou "vidět" v souboru (od místa uvedení do konce souboru). Lokální proměnné od místa uvedení do konce funkce, ve které byly deklarovány. Globální proměnné jsou implicitně inicializovány nulou. Lokální proměnné nejsou inicializovány, jejich hodnota je náhodná! Lokální proměnné "zastíní" globální. int globalni,c; main(){ int a,b,c;...c=2; globalni=c*2;...}
Program v C Program v C je množina funkcí, z nichž právě jedna je main. /*Šablona programu:*/ /* poznámky*/ #include<stdio.h> /*použití funkcí z knihoven */ #define N 10 /* konstanty*/ int pocet; float b; /*globální proměnné */ float f(float x) { /*funkce jiné než main */ return x*x; } main() /* hlavní program */ { int a; float b; /*deklarace proměnných */ a=1; b=3*a;} /*příkazy */
Úloha trojúhelník - formulace a postup řešení Úloha trojúhelník - programujeme a testujeme Deklarace funkce: hlavička_funkce tělo_funkce hlavička_funkce: typ jméno ( seznam_parametrů ) typ: void, int, float... typ návratové hodnoty seznam parametrů: () nebo (void)... žádné parametry (typ jmeno, typ jmeno) (int a, float b) tělo_funkce: { deklarace_ proměnných; příkazy; } V těle funkce je příkaz return výraz ; kde hodnota výrazu má typ návratové hodnoty. Volání funkce: jmeno_funkce (seznam_argumentů); za parametry se dosadí hodnoty v zadaném pořadí Uvnitř funkce nesmí být deklarována jiná (lokální) funkce.
funkce main Úloha trojúhelník - formulace a postup řešení Úloha trojúhelník - programujeme a testujeme hlavička: main () typ: neuveden implicitně typ int jméno: main prázdný seznam parametrů: tělo: {... } nebo: void main (void) {... return ; }
K čemu jsou funkce? Úloha trojúhelník - formulace a postup řešení Úloha trojúhelník - programujeme a testujeme Dělba práce Čitelnost (srozumitelnost) programu...
Úloha trojúhelník Úloha trojúhelník - formulace a postup řešení Úloha trojúhelník - programujeme a testujeme Jsou dána 3 čísla, která mají význam: délek 3 stran trojúhelníka (sss) délek 2 stran a velikosti úhlu jimi sevřeného (sus) délky strany a velikosti přilehlých 2 úhlů (usu) Napište program, ve kterém budou určeny zbývající strany a úhly, výšky, obvod, obsah, poloměr kružnice opsané a poloměr kružnice vepsané.
Jak postupovat? Úloha trojúhelník - formulace a postup řešení Úloha trojúhelník - programujeme a testujeme Jak se to počítá?... potřebujeme vzorečky Co mám (vstupní data) a co chci vypočítat? sss: dáno: a,b,c vypočítat: α, β, γ, v_a,v_b,v_c, S,o,r,ρ sus: dáno: a, b, γ vypočítat: α, β, c, v_a,v_b,v_c, S,o,r,ρ usu: dáno: α, β, c vypočítat: a, b, γ, v_a,v_b,v_c, S,o,r,ρ Mám 3 různé možnosti zadání: pro každý typ zadání napíšu funkci! Všechny údaje o trojúhelníku (a, b, c, α, β, γ, v_a,v_b,v_c, S,o,r,ρ ) budou uloženy v globálních proměnných. Představím si, jak bude program pracovat.
Scénáře Úloha trojúhelník - formulace a postup řešení Úloha trojúhelník - programujeme a testujeme 1 program: Jakou úlohu řešíme? uživatel: sss, sus, usu, žádnou, nebo něco "hloupého". 2 program: přejde do jednoho ze stavů: "sss", "sus", "usu", "nic" nebo "chyba". 3 program je ve stavu: nic : program skončí chyba : program: "na to nejsem, odcházím" a přejde k bodu 1. sss,sus,usu : program: zadej vstupní data uživatel: zadá vstupní data 4 program: ověří, zda jsou údaje korektní bud pokračuje, nebo přejde do stavu "chyba". 5 program: provede výpočet 6 program: sdělí výsledky nebo upozorní na chybu 7 program: vrátí se k bodu 1.
Upřesnění ("dělba práce") Úloha trojúhelník - formulace a postup řešení Úloha trojúhelník - programujeme a testujeme main : komunikace s uživatelem (zadání dat a tisk výsledků) a "změnu stavu", tj. volání funkcí. nic : program skončí chyba : funkce oznam(chyba) bude oznamovat, že je něco špatně výpočty : funkce sss, sus a usu budou předpokládat, že v globálních proměnných mají potřebné hodnoty, ověří, zda jsou věrohodné, a bud neprovedou výpočet, ale vrátí "číslo chyby" nebo se pustí do výpočtu, při kterém výsledky uloží do globálních proměnných
V jakém pořadí Úloha trojúhelník - formulace a postup řešení Úloha trojúhelník - programujeme a testujeme 1 napíšeme funkci main a otestujeme 2 postupně upravujeme funkci oznam (přidáváme možné druhy chyb) 3 napíšeme jednu z funkcí, které realizují výpočet 4 ověříme (otestujeme) 5 napíšeme druhou a třetí
main a její okolí Úloha trojúhelník - formulace a postup řešení Úloha trojúhelník - programujeme a testujeme #include<stdio.h> #include<math.h> float a,b,c,alha, beta, gamma; float v_a,v_b,v_c, S, o, r, rho; void oznam(int chyba){/*pozdeji*/ return;}; int sss(){/*pozdeji*/ return 0;}; int sus(){/*pozdeji*/ return 0;}; int usu(){/*pozdeji*/ return 0; }; main() {/*hned*/ };
Programujeme (funkce main) Úloha trojúhelník - formulace a postup řešení Úloha trojúhelník - programujeme a testujeme main() { int uloha,chyba; do { /* uloha: bude zadano 0,1,2,3 nebo jine*/ switch(uloha){ case 0:chyba=0; break; /*pripadne return 0;*/ case 1:/*zadej data*/ chyba=sss(); break; case 2:/*zadej data*/ chyba=sus();break; case 3:/*zadej data*/ chyba=usu(); break; default:chyba = 1; }/*konec switch*/ if(chyba) oznam(chyba); else /*tiskni vysledky*/ ;}/*konec do-while*/ while(uloha);/* while(uloha!=0)*/ }/*konec main*/
Programujeme (funkce main) Úloha trojúhelník - formulace a postup řešení Úloha trojúhelník - programujeme a testujeme main() { int uloha,chyba; do { printf("uloha: 0:nic, 1:sss, 2:sus, 3:usu"); scanf("%d",&uloha); switch(uloha){ case 0:chyba=0; break; /*pripadne return 0;*/ case 1:/*zadej data*/ chyba=sss(); break; case 2:/*zadej data*/ chyba=sus();break; case 3:/*zadej data*/ chyba=usu(); break; default:chyba = 1; }/*konec switch*/ if(chyba) oznam(chyba); else /*tiskni vysledky*/ ;}/*konec do-while*/ while(uloha);/* while(uloha!=0)*/ }/*konec main*/
Doplňujeme funkci oznam Úloha trojúhelník - formulace a postup řešení Úloha trojúhelník - programujeme a testujeme void oznam (int chyba) { switch(chyba) { case 1: printf("takovou ulohu neresim\n"); break; default: printf("takovou chybu neznam\n"); }/*konec switch*/ return; }/*konec funkce*/
Testujeme funkci main Úloha trojúhelník - formulace a postup řešení Úloha trojúhelník - programujeme a testujeme zadáme zadáme očekáváme úloha strany, úhly 1. 9 oznámení o chybném výběru úlohy 2. 0 vytisknuté výsledky (všechny nulové) 3. 1 1,1,1 vytisknuté výsledky: nulové, které jsme nezadali + zadané hodnoty 4. 2 5. 3
Úloha trojúhelník - formulace a postup řešení Úloha trojúhelník - programujeme a testujeme Z jakých údajů lze sestrojit trojúhelník? Strany (a,b,c) musí být kladná čísla. Úhly zadáváme bud ve stupních (a potom v programu převádíme na radiány) nebo v radiánech. Pro stupně musí platit: úhel (0, 180), pro radiány: úhel (0, π). Pro úlohu sss musí délky stran splňovat trojúhelníkovou nerovnost. a + b < c a b > c.
Programujeme kontrolu dat Úloha trojúhelník - formulace a postup řešení Úloha trojúhelník - programujeme a testujeme sss: int ok; ok=(a > 0&&b > 0&&c > 0); ok = ok&&(a + b) > c&&fabs(a b) < c); /* v proměnné ok bude 0 ("false") v případě, že došlo k nesplnění aspoň jedné z podmínek */ if(! ok) return 2 ; /* data nesprávná, výpočet se nekoná */ /*zde bude výpočet */ sus: int ok; ok=(a > 0&&b > 0); ok = ok&& gamma >0 && gamma < 180; if(! ok) return 2; /*zde bude výpočet */ usu: int ok; ok=c>0; ok=ok && alpha>0 && alpha < 180 ; ok = ok && beta >0 && beta < 180 ; if (!ok) return 2; /*zde bude výpočet */
Testujeme nesprávná data Úloha trojúhelník - formulace a postup řešení Úloha trojúhelník - programujeme a testujeme Doplníme funkci oznam: void oznam (int chyba) { switch(chyba) { case 1: printf("takovou ulohu neresim\n"); break; case 2: printf("ze zadanych udaju neumim sestrojit trojuhelnik"); break; default: printf("takovou chybu neznam\n"); }/*konec switch*/ return; }/*konec funkce*/ Zadáváme všechny možné případy chyb!
Úloha trojúhelník - formulace a postup řešení Úloha trojúhelník - programujeme a testujeme Potřebujeme vzorečky... umíme je najít Vzorce pro obecný trojúhelník obvod o = a + b + c obsah S = a va 2 S = 1 2ab sin γ o S = 2 ( o 2 a)( o 2 b)( o 2 c) poloměr kružnice opsané r = abc 4S r = a 2 sin α poloměr kružnice vepsané ρ = 2S o kosinová věta a 2 = b 2 + c 2 2bc cos α a sinová věta sin α = b sin β = c sin γ = 2r Převod stupňů na radiány a naopak:(π radiánů = 180 stupňů) a stupňů = a radiánů 180 π b radiánů = b stupňů π 180.
Výpočet podle vzorců Úloha trojúhelník - formulace a postup řešení Úloha trojúhelník - programujeme a testujeme sss 1 přečteme hodnoty a,b,c 2 z kosinové věty vyjádříme úhly ( b 2 + c 2 a 2 ) α = arccos 2bc ( a 2 + b 2 c 2 ) γ = arccos 2ab 3 vypočteme obvod o = a + b + c a obsah o S = 2 ( o 2 a)( o 2 b)( o 2 c) ( a 2 + c 2 b 2 ) β = arccos 2ac 4 vypočteme výšky v a = 2S a, v b = 2S b, v c = 2S c 5 vypočteme polomě ry kružnic : opsané: r = abc 4S a vepsané: ρ = 2S o
Úloha trojúhelník - formulace a postup řešení Úloha trojúhelník - programujeme a testujeme sus 1 přečteme hodnoty a,b,gamma 2 z kosinové věty vyjádříme stranu c a úhly α, β. usu c = a 2 + b 2 2ab cos γ ( b 2 + c 2 a 2 ) ( a 2 + c 2 b 2 ) α = arccos β = arccos 2bc 2ac 3 Ostatní vypočteme stejně jako pro úlohu sss. 1 přečteme hodnoty a,beta,gamma 2 dopočítáme úhel α = π β γ 3 ze sinové věty vyjádříme strany b a c. b = a sin β sin α c = a sin γ sin α 4 Ostatní vypočteme stejně jako pro úlohu sss.
Testujeme výpočet Úloha trojúhelník - formulace a postup řešení Úloha trojúhelník - programujeme a testujeme Vhodné trojúhelníky jsou: rovnostranný a=b=c=2, α = β = γ = 60, v_a = v_b=v_c= 3, o = 6, S= 3, r =..., ρ =... pravoúhlý...
Malé shrnutí Úloha trojúhelník - formulace a postup řešení Úloha trojúhelník - programujeme a testujeme Na příkladu úlohy trojúhelník jsme si ukázali, jak postupovat při řešení větší úlohy. Pro podstatu úlohy používáme nejvíce přiřazovací příkaz (jedná se o výpočetní úlohu). Větvení a cykly slouží k tomu, aby jednotlivé části úlohy spolu "komunikovaly". Aby byl zápis úlohy přehlednější, rozdělili jsme úlohu na menší samostatné části, které jsme realizovali jako funkce. Kudy dál? Výlet do polí!
POLE Jednoduchá proměnná POLE (jednoduchých)proměnných...
POLE Jednoduchá proměnná POLE (jednoduchých)proměnných jméno hodnota jméno hodnoty...
POLE Jednoduchá proměnná POLE (jednoduchých)proměnných hodnota a jméno jméno hodnoty... deklarace: int a;
POLE Jednoduchá proměnná POLE (jednoduchých)proměnných hodnota a 5 jméno jméno hodnoty... deklarace: int a; zadání hodnoty: a = 5;
POLE Jednoduchá proměnná POLE (jednoduchých)proměnných hodnota a 5 jméno hodnoty v jméno... deklarace: int a; zadání hodnoty: a = 5; deklarace: int v[4];
POLE Jednoduchá proměnná hodnota a 5 jméno deklarace: int a; zadání hodnoty: a = 5; POLE (jednoduchých)proměnných hodnoty v... jméno v[0]v[1]v[2]v[3] deklarace: int v[4];
POLE Jednoduchá proměnná hodnota a 5 jméno deklarace: int a; zadání hodnoty: a = 5; POLE (jednoduchých)proměnných hodnoty v... jméno v[0]v[1]v[2]v[3] deklarace: int v[4]; zadání hodnot:
POLE Jednoduchá proměnná hodnota a 5 jméno deklarace: int a; zadání hodnoty: a = 5; POLE (jednoduchých)proměnných hodnoty v... jméno 1 v[0]v[1]v[2]v[3] deklarace: int v[4]; zadání hodnot: v[0]=1;
POLE Jednoduchá proměnná hodnota a 5 jméno deklarace: int a; zadání hodnoty: a = 5; POLE (jednoduchých)proměnných hodnoty v... jméno 1 10 v[0]v[1]v[2]v[3] deklarace: int v[4]; zadání hodnot: v[0]=1; v[3]=10;
POLE Jednoduchá proměnná hodnota a 5 jméno deklarace: int a; zadání hodnoty: a = 5; POLE (jednoduchých)proměnných hodnoty v... jméno 1 2 10 v[0]v[1]v[2]v[3] deklarace: int v[4]; zadání hodnot: v[0]=1; v[3]=10; v[1]=2;
POLE Jednoduchá proměnná hodnota a 5 jméno deklarace: int a; zadání hodnoty: a = 5; POLE (jednoduchých)proměnných hodnoty v... jméno 1 2 4 10 v[0]v[1]v[2]v[3] deklarace: int v[4]; zadání hodnot: v[0]=1; v[3]=10; v[1]=2; v[2]=4;
Deklarace pole deklarace pole: typ jméno [ počet ]; typ počet musí být znám při překladu, proto int float... SPRÁVNĚ int v[4]; #define POCET 10 float r[20];... int z[pocet]; počet určuje, kolik prvků má pole, tj. (kolik paměti bylo přiděleno).
Prvky pole Prvky pole jsou proměnné typu typ. K jednotlivým prvkům se dostaneme pomocí závorek [ ] Indexují se vždy od 0. NENÍ kontrola mezí! int v[4];... v[4]... lezeme na cizí území v v[0]v[1]v[2]v[3] v[4]
Kdy potřebujeme pole Chceme označit jedním jménem "podobné" hodnoty Vytvořit pole 100 prvočísel. Práce s vektory. Zpracování 50 naměřených hodnot stejné veličiny. Musíme data zkoumat vícekrát Kolik čísel se liší od aritmetického průměru o více než p %. Kolik ze zadaných čísel se rovná poslednímu. Seřadit čísla podle velikosti.
Operace Nelze provést operaci s celým polem najednou. Zpravidla realizujeme operaci pomocí cyklu, ve kterém pracujeme s jednotlivými prvky pole. : Naplnit pole hodnotami. Vytisknout pole. Určit, kolik ze zadaných čísel se liší od aritmetického průměru o p. Vytvořit pole prvních 100 prvočísel. Uvažujte, kde je nutné použít pole, kde si vystačíme s jednoduchými proměnnými: Dáno 50 čísel. Určit aritmetický průměr. Dáno 50 čísel. Kolik z nich se rovná poslednímu? Dáno 100 čísel. Vytisknout nejprve kladná, potom ostatní.
Výplata Příklad: Je dána celočíselná částka P (například v Kč). Napište program, který určí, jak uvedenou částku vyplatit co nejmenším počtem platidel (za předpokladu, že je máme v dostatečném množství). Uvažujeme platidla v hodnotách např. {5000,2000,1000,500,200,100,50,20,10,5,2,1} Jak? operace celočíselného dělení a zbytku po dělení! Částku můžeme vyplatit : P / 5000 + (P%5000)/2000 + ((P%5000)%2000)/1000 +... Můžeme se obejít bez pole i bez cyklu, ale platidel je příliš moc, tak pro ně vytvoříme pole. A když máme pole... tak použijeme cyklus.
Výplata /*proměnné*/ int P, pocet, i=0, money [ ] = {5000,2000,1000,500,200,100,50,20,10,5,2,1}; printf("zadej sumu\n"); scanf("%d",&p); if(p>=0) while(p>=0) { pocet=p/money[i]; printf("%d x %d Kc\n", pocet, money[i]); P=P%money[i]; i++; } else printf("vyplacim pouze kladne castky");
Naplnění pole známým počtem čísel #include<stdio.h> #define pocet 4 main() { int i, pole[pocet]; v printf("zadej %d cisel", pocet); for(i=0; i< pocet; i++) v[0]v[1]v[2]v[3] { scanf("%d",&v[i]); } i //Vytiskneme obsah pole for(i=0; i< pocet; i++) { printf("%d ",v[i]); } }
Naplnění pole známým počtem čísel #include<stdio.h> #define pocet 4 main() { int i, pole[pocet]; v 2 printf("zadej %d cisel", pocet); for(i=0; i< pocet; i++) v[0]v[1]v[2]v[3] { scanf("%d",&v[i]); } i 0 //Vytiskneme obsah pole for(i=0; i< pocet; i++) { printf("%d ",v[i]); } }
Naplnění pole známým počtem čísel #include<stdio.h> #define pocet 4 main() { int i, pole[pocet]; v 2 printf("zadej %d cisel", pocet); 4 for(i=0; i< pocet; i++) v[0]v[1]v[2]v[3] { scanf("%d",&v[i]); } i 01 //Vytiskneme obsah pole for(i=0; i< pocet; i++) { printf("%d ",v[i]); } }
Naplnění pole známým počtem čísel #include<stdio.h> #define pocet 4 main() { int i, pole[pocet]; v 2 printf("zadej %d cisel", pocet); 4 6 for(i=0; i< pocet; i++) v[0]v[1]v[2]v[3] { scanf("%d",&v[i]); } i 012 //Vytiskneme obsah pole for(i=0; i< pocet; i++) { printf("%d ",v[i]); } }
Naplnění pole známým počtem čísel #include<stdio.h> #define pocet 4 main() { int i, pole[pocet]; v 2 printf("zadej %d cisel", pocet); 4 6 8 for(i=0; i< pocet; i++) v[0]v[1]v[2]v[3] { scanf("%d",&v[i]); } i 0123 //Vytiskneme obsah pole for(i=0; i< pocet; i++) { printf("%d ",v[i]); } }
Naplnění pole známým počtem čísel #include<stdio.h> #define pocet 4 main() { int i, pole[pocet]; v 2 printf("zadej %d cisel", pocet); 4 6 8 for(i=0; i< pocet; i++) v[0]v[1]v[2]v[3] { scanf("%d",&v[i]); } i 01234 //Vytiskneme obsah pole for(i=0; i< pocet; i++) { printf("%d ",v[i]); } }
Naplnění pole neznámým počtem čísel Dokud nezadáno číslo KONEC, ukládáme hodnoty do pole. #include<stdio.h> #define pocet 10 #define KONEC 157 main() { int i, cislo, pole[pocet]; i=0; scanf("%d",&cislo); while (i< pocet && cislo!= KONEC) { pole[i]=cislo; i=i+1; scanf("%d",&cislo); }
Kolik z daných čísel se liší od jejich aritmetického průměru o méně než p. Hodnoty musíme projít dvakrát: Určit celkový součet Aritmeticý průměr Znovu všechny hodnoty projít a spočítat, kolik z nich... Zadáme: počet "naměřených hodnot" N, "chybu" p, v cyklu zadáváme hodnoty. Součet: nejprve se rovná nule, po zadání hodnoty se Součet zvětšuje o zadané číslo. (S=0;... S=S+cisla[i];) Počet: nejprve se rovná nule, když najdeme číslo, které má hledanou vlastnost, Počet se zvětšuje o jedna. (P=0;... if (cisla[i]... ) P=P+1;)
#include<stdio.h> #include<math.h> #define pocet 100 main() { int i, kolik, N; float s, p, prumer, cisla[pocet]; scanf("%d",&n); if(n>= pocet){ return;} //"Prilis moc cisel" scanf("%f",&p); s = 0; for(i=0; i<n; i++) { scanf("%f",&cisla[i]); s = s + cisla[i]; } prumer = s / N; kolik = 0; for(i=0; i<n; i++) { if(fabs(cisla[i]-p) < p) kolik = kolik +1; } printf("%d ",kolik);}
Najdi je všechny! V určitém druhu výrobku je přibalena kartička. Celá sbírka obsahuje 10 různých kartiček. Kolik výrobků si budeme muset koupit, abychom měli celou sbírku? Budeme modelovat nákup.
Modelujeme hledání (Pseudo)náhodná čísla knihovna stdlib, funkce srand(číslo);, rand(); pole kartičky[10] vynulujeme "nákup": karta = rand()%10; pole[karta]=pole[karta]+1; "máme je všechny?" projdeme kartičky: všechny kartičky[ i ] jsou nenulové máme zbyly nulové opakujeme nákup
Hledáme v poli Předpokládejme, že čísla v poli jsou nesetříděná. Musíme prohlédnout (v nejhorším případě) všechna čísla, abychom zjistili, zda hledané číslo v poli je nebo není. proměnná mam: hodnota 0 dosud nenalezeno "pro jistotu" můžeme použít "zarážku"
Příště... další typ složených proměnných více o funkcích