0
Osnove programskega
inženirstva, C
Marjan JenkoFakulteta za
strojništvo
Univerze v
Ljubljani
Osnove programskega
inženirstva, C
Marjan Jenko
Fakulteta za
strojništvo
Univerze v
Ljubljani
Recenzenta: prof. ddr. Janez Žerovnik in doc. dr. Nikolaj Mole
Lektorirala: Andreja Cigale, prof. slov.
Grafična obdelava besedila: Avtor
Univerza v Ljubljani, Fakulteta za strojništvo, 2014
CIP - Kataložni zapis o publikaciji
Narodna in univerzitetna knjižnica, Ljubljana
004.43(075.8)(0.034.2)
JENKO, Marjan, 1961-
Osnove programskega inženirstva, C [Elektronski vir] /
Marjan Jenko. - El. knjiga. - Ljubljana : Fakulteta za strojništvo,
2014
Način dostopa (URL):
http://www2.arnes.si/~mjenko9/OPI-C/OPI-C.pdf
ISBN 978-961-6536-80-6 (pdf)
I
Kazalo
1 Uvod ... 1
1.1 Programsko inženirstvo ... 1
1.2 Vgradni sistem ... 6
1.2.1 Strojna oprema vgradnega sistema ... 9
1.2.2 Programska oprema vgradnega sistema ... 13
1.3 Učenje jezika C ... 14
2 Prvi programi – prevajanje in izpis ... 15
2.1 Naloge ... 16
2.1.1 N: Dober dan, svet ... 16
2.1.2 N: Navodilo programerju ... 16
2.1.3 N: printf(), vrnjena vrednost ... 17
2.1.4 N: Osebna vizitka ... 17
2.2 Rešitve (R) ... 18
2.2.1 R: Dober dan, svet ... 18
2.2.2 R: Navodilo programerju ... 19
2.2.3 R: printf(), vrnjena vrednost ... 20
2.2.4 R: Osebna vizitka ... 21
3 Spremenljivke, podatkovni tipi in aritmetični izrazi ... 22
3.1 Naloge ... 23
3.1.1 N: scanf(), printf() ... 23
3.1.2 N: Kalkulator ... 24
3.1.3 N: Polinom ... 24
3.1.4 N: Ulomek z eksponenti ... 25
3.1.6 N: Vsota kotov ... 26
3.1.7 N: Preračun iz °F v °C ... 26
3.1.8 N: Pretvorba iz radianov v stopinje ... 27
3.1.9 N: Obrat števk ... 27 3.2 Rešitve (R) ... 28 3.2.1 R: scanf(), printf() ... 28 3.2.2 R: Kalkulator ... 29 3.2.3 R: Polinom ... 30 3.2.4 R: Ulomek z eksponenti... 31
3.2.5 R: Obseg in površina kroga ... 33
3.2.6 R: Vsota kotov ... 34
3.2.7 R: Preračun iz °F v °C ... 36
3.2.8 R: Pretvorba iz radianov v stopinje... 37
3.2.9 R: Obrat števk ... 38
4 Programske zanke ... 39
4.1 Naloge ... 40
4.1.1 N: Izpis ASCII znakov, [0 .. 255] ... 40
4.1.2 N: Izpis ASCII znakov iz intervala ... 40
4.1.3 N: Izpis abecede velikih črk ... 41
4.1.4 N: Izpis abecede malih črk ... 41
4.1.5 N: getchar(), putchar() ... 41
4.1.6 N: 12 faktoriel ... 42
4.1.7 N: Tabela sinus[0..2π]... 43
4.1.8 N: Integral sin(x) ... 43
III
4.1.12 N: Poštevanka 10 * 10 ... 45
4.1.13 N: Vsota števk ... 46
4.1.14 N: ex kot vrsta do (člen < ε) ... 46
4.2 Rešitve (R) ... 47
4.2.1 R: Izpis ASCII znakov, [0 .. 255] ... 47
4.2.2 R: Izpis ASCII znakov iz intervala ... 48
4.2.3 R: Izpis abecede velikih črk ... 49
4.2.4 R: Izpis abecede malih črk ... 50
4.2.5 R: getchar(), putchar()... 51 4.2.6 R: 12 faktoriel ... 52 4.2.7 R: Tabela sin[0 .. 2π] ... 53 4.2.8 R: Integral sin(x) ... 54 4.2.9 R: Integral polinoma ... 55 4.2.10 R: Fibonaccijevo zaporedje ... 56 4.2.11 R: Piramida ... 57 4.2.12 R: Poštevanka 10 * 10 ... 58 4.2.13 R: Vsota števk ... 59
4.2.14 R: ex kot vrsta do (člen < ε) ... 60
5 Odločanje ... 61
5.1 Naloge ... 61
5.1.1 N: Je zadnja števka enaka »0«? ... 61
5.1.2 N: Celoštevilska deljivost? ... 62
5.1.3 N: Deljenje z realnim rezultatom ... 62
5.1.4 N: Značilke vnosov števil ... 63
5.1.5 N: Je leto prestopno? ... 64
5.1.6 N: Trikotnik a,b,c obstoja? ... 64
5.1.8 N: Sklanjanje za vnos ... 66
5.1.9 N: Je n praštevilo? ... 67
5.1.10 N: Produkt ne-nič števk ... 67
5.1.11 N: Izpis števk z besedami ... 68
5.2 Rešitve (R) ... 69
5.2.1 R: Je zadnja števka enaka »0«? ... 69
5.2.2 R: Celoštevilska deljivost? ... 70
5.2.3 R: Deljenje z realnim rezultatom ... 71
5.2.4 R: Značilke vnosov števil ... 72
5.2.5 R: Je leto prestopno? ... 74
5.2.6 R: Trikotnik a, b, c obstoja? ... 75
5.2.7 R: Kalkulator + - * / ... 77
5.2.8 R: Sklanjanje za vnos... 79
5.2.9 R: Je n praštevilo? ... 80
5.2.10 R: Produkt ne-nič števk ... 81
5.2.11 R: Izpis števk z besedami ... 82
6 Polja ... 84
6.1 Naloge ... 85
6.1.1 N: Vnosi in povprečje ... 85
6.1.2 N: Vnosi in dva izpisa... 86
6.1.3 N: Kopiranje polja v polje ... 87
6.1.4 N: Iskanje v polju... 88
6.1.5 N: Sprememba številske baze ... 89
6.1.6 N: Fibonaccijeva števila ... 89
V
6.2.1 R: Vnosi in povprečje ... 92
6.2.2 R: Vnosi in dva izpisa ... 93
6.2.3 R: Kopiranje polja v polje ... 94
6.2.4 R: Iskanje v polju ... 96
6.2.5 R: Sprememba številske baze ... 98
6.2.6 R: Fibonaccijeva števila ... 100 6.2.7 R: Koliko bankovcev ? ... 101 6.2.8 R: Transponiranje matrike ... 102 7 Funkcije ... 104 7.1 Naloge ... 104 7.1.1 N: Vsota števil ... 104 7.1.2 N: Parameter in spremenljivka ... 105 7.1.3 N: Globalni spremenljivki ... 105
7.1.4 N: Rešitev kvadratne enačbe ... 106
7.1.5 N: Funkcija Največji Skupni Delitelj (NSD) ... 107
7.1.6 N: Funkcija Fib() – Fibonaccijevo število ... 108
7.1.7 N: Funkcija s poljem ... 109 7.1.8 N: Fibonacci rekurzivno ... 110 7.1.9 N: Faktoriela rekurzivno ... 111 7.2 Rešitve (R) ... 112 7.2.1 R: Vsota števil ... 112 7.2.2 R: Parameter in spremenljivka ... 113 7.2.3 R: Globalni spremenljivki ... 114
7.2.4 R: Rešitev kvadratne enačbe ... 115
7.2.5 R: Funkcija Največji Skupni Delitelj (NSD) ... 119
7.2.6 R: Funkcija Fib() – Fibonaccijevo število ... 121
7.2.8 R: Fibonacci rekurzivno ... 124 7.2.9 R: Faktoriela rekurzivno ... 125 8 Strukture ... 126 8.1 Naloge ... 126 8.1.1 N: Razdalja ... 126 8.1.2 N: Pretečeni čas ... 127 8.2 Rešitve ... 128 8.2.1 R: Razdalja ... 128 8.2.2 R: Pretečeni čas ... 130 9 Nizi ... 132 9.1 Naloge ... 132
9.1.1 N: Vpis, izpis niza... 132
9.1.2 N: Obrni niz ... 133 9.1.3 N: Niz v strukturi ... 133 9.1.4 Naredimo najdiNiz() ... 134 9.1.5 N: Naredimo odstraniNiz() ... 135 9.1.6 N: Naredimo vstaviNiz() ... 136 9.1.7 N: Naredimo zamenjajNiz() ... 137 9.1.8 N: Preštej besede... 138 9.1.9 N: Sprememba velikosti črk ... 138 9.1.10 N: Palindrom? ... 139 9.1.11 N: Značilke niza ... 139 9.1.12 N: Združitev nizov ... 140 9.2 Rešitve ... 141
VII 9.2.4 R: Naredimo najdiNiz() ... 144 9.2.5 R: Naredimo odstraniNiz() ... 145 9.2.6 R: Naredimo vstaviNiz() ... 147 9.2.7 R: Naredimo zamenjajNiz() ... 149 9.2.8 R: Preštej besede ... 152 9.2.9 R: Sprememba velikosti črk ... 153 9.2.10 R: Palindrom? ... 154 9.2.11 R: Značilke niza ... 156 9.2.12 R: Združitev nizov ... 158 10 Kazalci ... 159 10.1 Naloge ... 160 10.1.1 N: Kazalci, * ... 160 10.1.2 N: Kazalci, * in & ... 161
10.1.3 N: Kazalci, dinamična dodelitev spremenljvke ... 162
10.1.4 N: Kazalec in operatorji *, &, ++ ... 163
10.1.5 N: Dinamično narejen povezan seznam... 164
10.1.6 N: Kazalci – parametri funkcije; statična spremenljivka ... 165
10.1.7 N: Kazalci – parametri funkcij... 166
10.1.8 N: Kazalec na funkcijo ... 167
10.2 Rešitve ... 168
10.2.1 R: Kazalci, * ... 168
10.2.2 R: Kazalci, * in & ... 168
10.2.3 R: Kazalci, dinamična dodelitev spremenljivke ... 168
10.2.4 R: Kazalec in operatorji *, &, ++ ... 169
10.2.5 R: Dinamično narejen povezan seznam ... 170
10.2.6 R: Kazalci - parametri funkcij; statična spremenljivka... 172
10.2.8 R: Kazalec na funkcijo... 175
11 Delo z biti ... 177
11.1 Naloge ... 177
11.1.1 N: Bitni operatorji ... 177
11.1.2 N: Prireditveni bitni operatorji ... 178
11.1.3 N: Velikost tipov integer, short integer, long integer ... 179
11.1.4 N: Iskanje bitnega vzorca ... 180
11.2 Rešitve ... 181
11.2.1 R: Bitni operatorji ... 181
11.2.2 R: Prireditveni bitni operatorji ... 183
11.2.3 R: Velikosti tipov int, short int, long int ... 185
11.2.4 R: Iskanje bitnega vzorca ... 187
12 Datotečne funkcije ... 190
12.1 Naloge ... 190
12.1.1 N: Pisanje v datoteko ... 190
12.1.2 N: Vpis in izpis ... 191
12.1.3 N: Kopiranje datoteke po bytih ... 192
12.1.4 N: Kopiranje datoteke po blokih ... 193
12.1.5 N: Sprememba v velike črke ... 194
12.1.6 N: Velikost datoteke ... 195 12.1.7 N: Izpis meritev ... 196 12.1.8 N: Izpis po n vrstic ... 198 12.2 Rešitve ... 200 12.2.1 R: Pisanje v datoteko ... 200 12.2.2 R: Vpis in izpis ... 201
IX
12.2.5 R: Sprememba v velike črke ... 208
12.2.6 R: Velikost datoteke ... 209
12.2.7 R: Izpis meritev ... 210
12.2.8 R: Izpis po n vrstic ... 212
13 Literatura ... 214
e_branje:
Bralniki pdf: Adobe, Foxit, Nitro, PDF-Xchange, Sumatra.
Velikosti strani in črk sta usklajeni z navodilom Založbe FS.
1 Uvod
1.1 Programsko inženirstvo
Programsko inženirstvo je strukturiranje in izvajanje programerskih
procesov od potrebe po programski rešitvi preko razvoja, uporabe,
vzdrževanja programskega produkta do opustitve programske rešitve
[1, str. 82-250]. Velika večina načinov strukturiranja programerskih
procesov po načelih programskega inženirstva je univerzalna oziroma
neodvisna od konkretnih funkcionalnih zahtev programov, njihovega
namena, od platform na katerih naj delujejo ter od njihovih lastnosti in
uporabnikov.
V programskem inženirstvu je uveljavljen inženirski pristop k pisanju
programov. Poudarek je na zagotavljanju kakovosti programskih rešitev.
To je omogočeno s sprotno verifikacijo funkcionalnosti, s strukturiranjem
in z dokumentiranjem programske opreme za kasnejše vzdrževanje
tekom življenjske dobe produkta ter z doseganjem rokov izdelave
programske opreme ob nepreseženih stroških.
Programsko inženirstvo je interdisciplinarno področje. Obsega
strukturiranje programske opreme, kodiranje, verifikacijo, timsko
vodenje, razumevanje procesov, ki naj jih programska rešitev krmili in
odnose z naročniki. Najbolj osnovna zahteva je, da programski produkti
ne vsebujejo napak. Sprotne verifikacije funkcionalnosti zelo izboljšajo
kakovost programskih rešitev. Pri razvoju računalniško krmiljenih in
računalniško spremljanih distribuiranih proizvodnih procesov ter
visokotehnoloških mehatronskih naprav razvoj programske opreme še
vedno predstavlja visok dejavnik tveganja. Razloga sta vsaj dva: a)
krmiljenje procesov in funkcionalnost naprav sta vedno bolj odvisna od
programske opreme in b) interna kompleksnost programske opreme – od
uporabniškega programa do izvajanja strojne kode – je v primerjavi z
ostalimi gradniki visokotehnoloških naprav velika. Programiranje je
pomanjkljivosti in odpravijo napake, preden postanejo prepoznavne v
delovanju sistema in/ali naprave.
Programsko opremo lahko delimo na uporabniške programe, opremo
sistemov za krmiljenje v realnem času, distribuirane rešitve upravljanja
proizvodnih procesov, sistemsko programsko opremo, programe
informacijsko-komunikacijske infrastrukture, distribuirane poslovne
aplikacije in drugo. Zakonitosti za uspešen razvoj teh različnih sistemov
so skupne.
Proces izdelave programske opreme razdelimo v posamezne faze:
definicija problema, študija izvedljivosti, analiza in določitev zahtev,
načrtovanje sistema, strukturiranje programske rešitve, kodiranje,
testiranja in verifikacije, sistemska integracija, testiranje celote, predaja
produkta, vzdrževanje in posodabljanje programskega produkta tekom
življenjske dobe.
Prednosti formalno strukturiranega in izvajanega razvoja programskih
produktov, torej udejanjanja metod programskega inženirstva, pred ad
hoc rešitvami so: večja produktivnost, projekt je bolj obvladljiv -
posledično je delo manj stresno, zanesljivost delovanja programskega
izdelka je bistveno večja; ni nujno, da čas in cena izdelave programskega
izdelka bistveno odstopata od napovedi; čas učenja novih programerjev
je krajši, kakovost znanja pa je višja.
Razvoj programske opreme po metodah programskega inženirstva
sistemsko izloča razloge za neuspeh programskih izdelkov. Običajno so
to napake v delovanju, do katerih prihaja skoraj naključno oziroma je
kakovost programske rešitve slaba, preseženi so roki in stroški,
nerazumljene in/ali nezadovoljene so uporabnikove potrebe, vzdrževanje
je težavno. Do teh usodnih razlogov za neuspeh sicer pride zaradi
neustreznega planiranja razvoja, nezadostno določenih ciljev projekta,
prepovršnega razumevanja uporabnikovih potreb, nezadostnega
sprotnega in končnega preverjanja funkcionalnosti, nezadostnega znanja
razvojnikov in nezadostnega razumevanja potrebnih razvojnih vložkov
razvijalca in uporabnika [3, str. 175–189].
Po metodah programskega inženirstva nameravano funkcionalnost
programske opreme strukturiramo v diagrame, sestavljene iz hierarhično
oblikovanih medsebojno povezanih funkcijskih blokov. Ti diagrami so
formalizacija delovanja programske opreme.
Programsko opremo kodiramo v različnih programskih jezikih. Vsaka
programska oprema se izvaja na nekem računalniku, v katerem nek
mikroprocesor izvaja programske ukaze. Najbolj elementarno je
programiranje v strojnem jeziku, ki je na nivoju ničel in enojk, nosilcev
informacije v digitalnem sistemu. Produktivnost takšnega programiranja
je za izdelavo uporabniških programov neuporabno nizka. Vendar, tak je
bil začetek programiranja (orodja za drugačno programiranje je bilo šele
treba narediti). Nadgradnja strojnega jezika je zbirnik (asembler), ki že
ima besedne programske ukaze. Ti ukazi so določeni z ozirom na
arhitekturo mikroprocesorja – gre za programske ukaze na nivoju dela z
registri, spominskimi lokacijami, logičnimi in aritmetičnimi enotami.
Vsak mikroprocesor ima praktično svoj zbirnik. Ti programi niso
prenosljivi. Na prvi pogled to ni pomembno, dejansko pa je prenosljivost
programske opreme med njenimi najpomembnejšimi lastnostmi. Tudi
takšno programiranje je za izdelavo uporabniških programov
predolgotrajno in s tem neproduktivno. Kasneje, za nizkonivojskima
strojnim jezikom in zbirnikom, so nastali višjenivojski programski
jeziki, ki imajo sintakso in semantiko prilagojeno logičnim potrebam
pisanja programov, ne pa arhitekturi mikroprocesorja.
Tehnološko so glavni del teh jezikov prevajalniki nizov programskih
ukazov v zbirnik in naprej v strojno kodo mikroprocesorja. Uporabniško
pa je glavni del teh jezikov nabor efektivnih ukazov za programiranje,
oziroma za »izražanje v programskem jeziku«. Ogromna je razlika med
kodiranjem z ukazi, ki so »pisani na kožo« danemu mikroprocesorju in
med kodiranjem z ukazi, ki so »pisani na kožo« uporabniku programerju
oziroma so definirani kot gradniki za efektivno pisanje uporabniških
programov.
v strojni jezik. Zato so zbirniki za različne mikroračunalnike lahko
nastajali hkrati z razvojem mikroračunalnikov od šestdesetih let
prejšnjega stoletja naprej. Na začetku računalniških tehnologij so v
zbirniku (ker drugega ni bilo) pisali celo operacijske sisteme in
uporabniške programe. Na primer, IBM PC DOS in Lotus 123 sta
napisana v zbirniku.
Šele v sedemdesetih letih prejšnjega stoletja so nastali prevajalniki iz
višjih programskih jezikov v zbirnik in/ali v strojno kodo za vsaj najbolj
razširjene mikroprocesorske arhitekture. Takrat je nastajal programski
jezik C (med 1969 in 1973), ki ga tudi danes najbolj uporabljamo za
razvoj programske opreme vgradnih sistemov. Pred C-jem so nastali
Fortran (1953), ALGOL (ALGOrithmic Language), Simula, BASIC,
pascal (1968) in objektni pascal. C-ju sledijo Visual BASIC, LabVIEW,
objektni C, C++, C#, .NET, IEC 61131-3 ST (Strukturirani Tekst, angl.
structured text), Java in PHP. Evolucija programskih jezikov je zvezna.
Sedanji poudarek je na platformski neodvisnosti programskih rešitev.
Programski jezik C je nastal z namenom univerzalne uporabnosti (visoko
in nizkonivojski jezik) v AT&T Bell Laboratories. Avtorja sta Dennis
Ritchie in Brian Kernighan. Prve C prevajalnike so napisali za platforme
z UNIX operacijskim sistemom. Kasnejši C prevajalniki za MS-DOS so
omogočili masovno uporabo C jezika.
Programski jezik C vsebuje ukaze in podatkovne strukture, ki so
namenjeni preglednemu in strukturiranemu pisanju uporabniških
programov oziroma visokonivojskemu programiranju ter tudi ukaze in
podatkovne strukture, ki so namenjeni programiranju na nivoju
spominskih lokacij in posameznih bitov oziroma nizkonivojskemu
programiranju. V C-ju so na primer napisani orodji Mathematica in
MATLAB ter operacijski sistem UNIX. Na osnovi C-ja so razviti
objektno orientirani jeziki C++, objektni C, C# in Java. Programsko
sintakso in semantiko po C-ju povzema IEC 61131-3 ST za
programiranje programabilnih logičnih krmilnikov (PLK-jev). Zaradi
dobre logične zasnove in posledične uporabnosti C-ja so razvijalci
napisali prevajalnike iz C kode v strojno kodo za večino
mikroprocesorjev. C kodo, ki je pisana po standardu ANSI (angl.
American National Standards Institute), lahko prevajamo za izvajanje na
različnih strojnih platformah in na različnih operacijskih sistemih ob zelo
malo spremembah kode. Posledično je večina programske opreme za
upravljanje visokotehnoloških naprav in procesov, implementiranih v
vgradnih sistemih (angl. embedded systems), pisana v jeziku C. Leta
1990 je bil publiciran prvi ANSI C standard. Zadnji ANSI C standard je
iz leta 2011.
Jezik C zaradi premišljene strukture ukazov lahko uporabljamo za pisanje
obsežnih distribuiranih programov, samostojne programe, zaradi podpore
delu s kazalci (angl. pointers) za direktno programiranje strojne opreme,
pisanje operacijskih sistemov, skratka C se je zaradi njegove
univerzalnosti smiselno naučiti. C podpira veliko večino konceptov
programiranja. Za objektno programiranje je C nadgrajen v objektni C in
v C++.
Pri razvoju C-ja je bilo pomembno, naj prevajalnik generira čim bolj
efektivno strojno kodo (malo kode, nič odvečnosti, hitro izvajanje), naj
omogoča direkten dostop do spomina oziroma do naslovov spominskih
lokacij, in naj deluje s čim manj podpornimi knjižnicami. Posledično
C-jeva zasnova omogoča pisanje programske opreme tudi na področjih,
kjer je bil prej potreben zbirnik. Višjenivojski C jezik je nadgradnja
zmožnosti nizkonivojskega programiranja in omogoča univerzalno
programiranje oziroma neodvisnost od strojne platforme.
Inženirji strojništva razvijajo sisteme za krmiljenje in spremljanje
proizvodnje, integracijo proizvodnih s poslovnimi sistemi, krmiljenje in
spremljanje distribuiranih proizvodnih in logističnih procesov, procesno
avtomatizacijo in nove mehatronske naprave. Komponente
visokotehnološke mehatronske naprave so mehanski sistem, elektronska
platforma z mikrokrmilnikom za zajem podatkov, za izvajanje krmilnih
algoritmov in krmiljenje aktuatorjev ter programska oprema.
jo v bolj ali manj narejenem stanju prenesemo na vgradni sistem naprave,
kjer jo razvijemo do konca. Prenosljivost programske opreme z
zmogljive na manj zmogljivo platformo je kar nujna za produktiven in
kakovosten razvoj programske opreme za vgradne sistema. Tu pride do
izraza v ANSI C vgrajena prenosljivost. Poleg tega, da omogočajo visoko
in nizkonivojsko programiranje, so ANSI C programi teoretično
popolnoma, praktično pa zelo prenosljivi med razvojnimi platformami in
vgradnimi sistemi. Programiranje v ANSI C-ju omogoča tudi
vzdrževanje vgradnih sistemov. Ko je iz različnih razlogov treba
zamenjati mikrokrmilnik z novejšim (dobavljivost ali s časom potreba po
razširitvi funkcionalnosti), je velika večina ANSI C kode v
nespremenjeni obliki primerna za ponovno uporabo v novem sistemu.
Učiti se večino aktualnih programskih jezikov na zalogo predstavlja
neučinkovito rabo energije in časa. Metodično se seznaniti z uporabo
večine ukazov standardiziranega platformsko prenosljivega visoko in
nizkonivojskega jezika, ki predstavlja osnovo tudi za druge moderne
jezike, pa je smiselna osnova za pisanje distribuiranih programskih orodij
in za mehatronsko interdisciplinarno delo.
Komponenta mehatronskega interdisciplinarnega projekta je vgradni
sistem oziroma sodobna implementacija krmiljenja.
1.2 Vgradni sistem
Vgradni sistem je krmilni sistem, ki sestoji iz mikrokrmilnika (angl.
microcontroller) , vseh potrebnih perifernih enot – zaznaval, aktuatorjev,
torej iz celotne elektronike in ustrezne programske opreme, ki določa
funkcionalnost visokotehnološke naprave [4, str. 5-31].
Še pred desetimi leti je večina naprav delovala brez vgrajenih
mikroračunalnikov. Krmilna logika je bila izvedena na nivoju logičnih
vrat in spominskih celic ali celo z zobniki, kontakti in vzmetmi (kot so še
vedno narejeni na primer krmilniki cenejših pralnih in pomivalnih
strojev). V teh tehnologijah praktično ni možno izvesti kompleksnejših
upravljalskih funkcij. Od iznajdbe računalnika naprej pa je zmogljivejši
krmilni sistem realiziran z ločenim računalnikom, povezanim z napravo
ali sistemom z množico kablov za zajemanje podatkov in za krmiljenje
aktuatorjev.
Vgradni sistem je del same naprave. Vgrajeno mikroračunalniško
krmiljenje naprave poenostavi sistemski razvoj in omogoča fleksibilnost
delovanja naprave – spremembe in izboljšave so narejene v programski
opremi. Visokotehnološkega mehatronskega izdelka se danes brez
vgradnega sistema praktično ne da več narediti. Uporabnik pogosto niti
ne ve, da je naprava računalniško krmiljena. Z uporabniškega stališča
način krmiljenja niti ni pomemben. Obstoj vgradnih sistemov je
spremenil celoten koncept delovanja in uporabniške izkušnje
visokotehnoloških naprav. Za ponazoritev navajamo dva primera:
Pri ščetki na sliki 1 mikrokrmilnik krmili intenzivnost in čas trajanja
vibracij ščetke, brezkontaktno indukcijsko polnjenje ter prikaz stanja
baterije. Nekoč je bila zobna ščetka sestavljena samo iz ročaja in ščetin.
Razlika med staro in novo zobno ščetko je očitna in velika. Čiščenje na
novi način je uspešnejše (odstranjevanje oblog z vibracijami) in manj
uničujoče kot prej (manj je drgnjenja in posledično obrabe).
Pri parnem kotlu na sliki 1 zmogljivejši mikrokrmilnik krmili več deset
kilovatov električne moči za izvajanje termičnih procesov kuhanja ali
vrenja ali poparjevanja do sto petdeset litrov hrane. Hkrati krmili tudi
uporabniški vmesnik na dotik, prikaz spremenljivk, beleženje procesnih
spremenljivk in podatkovno/servisno komunikacijo prek internetnega
omrežja.
Konceptualno sta si krmilna sistema obeh naprav zelo podobna. Seveda
kompleksnost izvedbe narašča z zahtevnostjo krmiljenja.
Mikrokrmilnik krmili tudi moderno računalniško miško, vsak podatkovni
disk, tiskalnik, avtomat za hrano in/ali pijačo, telefon, multimedijske
naprave, veliko igrač in predvsem tehnološko zahtevne produkte, kjer
zmogljivo krmiljenje res pride do izraza: kompleksna industrijska
pečice, razne gospodinjske naprave, medicinske diagnostične naprave,
roboti za medicinske operacije, prodajni terminali in mnogo drugega.
Slika 1: Z vgradnim sistemom krmiljena zobna ščetka Sonicare® in Parni
kotel Kogast®
Trenutno na vsak osebni računalnik izdelajo več kot sto vgradnih
sistemov. Razvoj krmiljenja naprav z vgradnimi sistemi je omogočil
krajše čase razvoja novih naprav in več funkcionalnosti ob dosegljivi
ceni. Nove naprave za industrijsko in osebno rabo so informacijsko
povezljive in imajo intuitivne uporabniške vmesnike. Predvsem v
krmiljenju procesov so na razpolago nove možnosti pri zaznavalih,
krmiljenju samem in pri aktuatorjih. Potencialen rezultat so naprave s
popolnejšim krmiljenjem, posledično z večjim izkoristkom, torej z
manjšo porabo energije in z manj škodljivim vplivom na okolje.
Vgradni sistemi sestojijo iz strojne in programske opreme.
1.2.1
Strojna oprema vgradnega sistema
Strojna oprema je danes izključno v domeni elektrotehnike in
elektronike. Prve implementacije krmiljenja procesov so bile izvedene z
mehanskimi in/ali elektromehanskimi sistemi in še to le takrat, kadar je
bilo to res nujno za implementacijo delovanja in/ali določeno tehnološko
prednost. Takšno uporabo so predstavljali elektromehanski računalniki za
določanje parametrov streljanja na vojaških ladjah in sklopi krmilnih
sistemov na vojaških letalih za podporo in razbremenitev pilota v drugi
svetovni vojni.
Z razvojem polprevodniških tehnologij so krmilne naprave postale
manjše in zmogljivejše. Razvoj digitalne tehnologije je najprej omogočil
industrijsko avtomatizacijo z logičnimi vezji. Njihovi gradniki so logična
vrata AND, OR, NAND, NOR, XOR, XNOR in spominski elementi D flip
flopi ter SR flip flopi. Na tak način lahko realiziramo logične sekvenčne
avtomate, gradnja kompleksnejše avtomatizacije pa ni ekonomsko
upravičena.
Leta 1971 je podjetje Texas Instruments vložilo patentno prijavo za prvi
mikroprocesor narejen v enem samem vezju (angl. single-chip
microprocessor) . Osemdeseta leta prejšnjega stoletja zaznamuje začetek
tehnologije vgradnih sistemov.
Gradniki današnjih vgradnih sistemov so mikrokrmilniki, potencialno vsa
kataloška integrirana vezja in drugi elektronski elementi. Kadar zahteve
implementacije tehnološkega procesa to zahtevajo in je ekonomsko
upravičeno, izdelamo tudi dodatna integrirana vezja po naročilu (angl.
custom integrated circuit). Enostavnejša tehnologija, ki to omogoča, je
izdelava ASIC (angl. Application Specific Integrated Circuit). Samo
velike serije izdelka in visoke tehnološke zahteve upravičijo tak razvojni
strošek.
Vsak mikrokrmilnik vsebuje mikroprocesor. Na splošno le-ta sestoji iz
aritmetične logične enote (angl. arithmetic logic unit ALU),
instrukcijskega dekoderja, polja registrov (spominskih lokacij) in
kontrolne enote.
V najosnovnejšem smislu je mikroprocesor naprava za izvajanje algebre.
Prvi izdelki z vgrajenim mikroprocesorjem so bili ročni kalkulatorji, ki
vsakršno računanje močno poenostavijo. Pred tem so si inženirji pri
računanju pomagali s pomičnim mehanskim računalom (angl. slide rule,
nem. Rechenschieber), ki ga je kalkulator povsem izpodrinil. Ob
primerljivi ceni omogoča bistveno več in je enostavnejši za uporabo.
Naprava, ki izvaja algebro, izvaja tudi logične funkcije. Le-te so
definirane v dvojiškem številskem sistemu, ki je za računalniško
implementacijo bistveno primernejši od desetiškega, ki ga uporabljamo
za vsakodnevno računanje.
Za rabo mikroprocesorja v krmiljenju procesov v realnem času je bilo
treba dodati bistvene periferne enote za zajem podatkov krmiljenega
sistema, krmiljenje aktuatorjev in prenos podatkov po komunikacijskem
omrežju. Takšno integrirano napravo imenujemo mikrokrmilnik.
Mikrokrmilnik z blokovno shemo na sliki 2 vsebuje mikroprocesor in
periferijo za krmiljenje industrijskih procesov in naprav v realnem času:
programabilne vhodno-izhodne enote, ki jih lahko precej poljubno
programsko nastavimo kot digitalne in analogne podatkovne vhode ter
izhode, primerjalnike signalov, časovnike za merjenje časov in
zakasnitev, več podatkovnih vhodov s sposobnostjo proženja prekinitve
osnovnega delovanja in takojšnje obdelave logičnega pogoja v trenutku,
ko se zgodi. Dodanih je še več analogno digitalnih pretvornikov za zajem
analognih veličin in enota za komuniciranje z mrežnim informacijskim
sistemom.
Slika 2: Blokovna shema mikrokrmilnika družine MSP430, Texas
Instruments
mikrokrmilniku je shranjenih in se izvaja približno pet tisoč vrstic kode
C. Ostali elementi na sliki 3 so močnostna stikala in signalni filtri ter
napetostne zaščite vhodnih signalov. Ti elementi zahtevajo določeno
površino oziroma volumen, saj preklapljajo konkretne moči pri omrežni
napetosti. Popolna miniaturizacija tiskanega vezja ni možna zaradi
omrežne napetosti med posameznimi povezavami vezja. S podobno
grajenimi sistemi krmilimo različne industrijske procese, naprave in
sklope naprav.
Vmesna stopnja med delovno postajo (angl. workstation), uporabljeno
kot računalnik za upravljanje industrijskega procesa in/ali naprave ter
med vgradnim sistemom za upravljanje procesa in/ali naprave predstavlja
Programabilni Logični Krmilnik - PLK (angl. Programmable Logic
Controller – PLC), slika 4.
Slika 4: Programabilni modularno grajen logični krmilnik Beckhoff®
PLK-ji so namenjeni krmiljenju industrijskih procesov in splošni
industrijski avtomatizaciji. PLK-je programiramo v lestvičastih
diagramih (angl. ladder diagram, LD), v diagramih funkcijskih blokov
(angl. function block diagram, FBD), v sekvenčnih funkcijskih diagramih
(angl. sequential function chart, SFC), v zaporedjih instrukcij (angl.
instruction list. IL), v strukturiranem tekstu (angl. structured text, ST,
zelo podobno C-ju), lahko pa tudi v C-ju [5, str. 40] (določila PLK
programskega standarda IEC 61131-3). PLK-ji so narejeni modularno.
Za vsako aplikacijo sestavimo potrebno konfiguracijo iz posameznih
tipskih gradnikov. PLK-ji kot vgradni sistemi niso primerni – še vedno so
preveč univerzalni, oziroma ne dovolj specializirani za krmiljenje
serijsko izdelanih naprav. Cena in fizični volumen takih krmilnih naprav
bi bila prevelika! Le optimizacija mikroračunalnika na nivoju
integriranih vezij omogoča največjo fleksibilnost ter zmogljivostno in
cenovno optimizacijo serijsko izdelane visokotehnološke moderne
naprave.
Uporabniški vmesniki vgradnega sistema so lahko zelo različni.
Vmesniki polpreteklega časa so narejeni s folijskimi tipkovnicami in s
prikazovalniki s svetlečimi diodami. Najmodernejši vmesniki imajo
zaslone LCD (angl. Liquid Crystal Display), ki so občutljivi na dotik.
Takšne vmesnike imajo na primer pametni telefoni. Narejeni so v
milijonskih serijah, zato so lahko in morajo biti popolnoma funkcionalno
optimizirani. Nudijo najboljšo možno uporabniško izkušnjo, ki si jo
uporabnik lahko želi pri vseh visokotehnoloških napravah. Veliko
proizvodov pa ne prenese dodatne cene vseh tehnologij, ki so uporabljene
v pametnem telefonu. Mnogo naprav je narejenih v majhnih serijah, ker
so namenjene specifični uporabi in ne vsakemu prebivalcu globalnega
sveta. Količina ekonomsko upravičenega razvojnega dela je tesno
odvisna od velikosti serije naprave.
1.2.2
Programska oprema vgradnega sistema
Mikrokrmilnik je namensko konstruiran za krmiljenje procesov in naprav
v realnem času. Za konkretno krmiljenje je treba programsko nastaviti
delovanje vseh perifernih enot in napisati programsko opremo, ki določa
funkcionalnost naprave v realnem času – brez nenačrtovanih zakasnitev
delovanja in z zanesljivim delovanjem ob vsakršnih kombinacijah ter
zaporedjih vhodnih podatkov.
standardu ANSI, lahko prevajamo za različne strojne platforme in za
različne operacijske sisteme, ob relativno majhnih spremembah kode.
1.3 Učenje jezika C
Referenčni dokument jezika C je [6] v slovenskem prevodu [7]. Sintaksa
in semantika programskih ukazov C sta podani na primer v [6, str.
191-239], [8, str. 905–1004] in [9, str. 429–466].
Funkcionalnost standardne knjižnice C je podana na primer v [6, str.
241–258], [9, str. 467–492] in [10].
Učenje programskega jezika strukturiramo za postopno dodajanje
kompleksnosti kot na primer v [11]. Tudi v tem učnem pripomočku so
naloge in koda njihovih rešitev strukturirani v zaključene celote.
Razpored poglavij je povzet po [9]. Kompleksnost nalog narašča
postopoma, saj v naslednjih poglavjih uporabljamo znanje iz prejšnjih
poglavij. C je jezik s širokim krogom uporabnikov, kratke primere
najdemo tudi na medmrežju, kot na primer v [12]. Znanje C-ja nam
predstavlja programersko osnovo, ki jo nadgrajujemo s posebnostmi
programiranja za izdelavo krmiljenja v realnem času in z drugimi
proceduralnimi in objektno orientiranimi jeziki za izdelavo distribuiranih
programskih rešitev.
2 Prvi programi – prevajanje in izpis
Poudarki:
−
Prevajanje programa v izbranem programskem okolju.
−
Vključitev knjižnice stdio (standardni I/O) v program.
−
Argumenti programa main().
−
Znaki za vključitev komentarja.
−
Izpis nizov s printf().
−
Kontrolni znak ‘\n’ v izpisu.
−
Kontrolni znak za oblikovanje podatka v izpisu – ‘%d’ – decimal,
desetiški izpis celega števila.
−
Vrnjena vrednost funkcije printf().
−
Izpis celoštevilskega števila s printf().
−
#pragma ukazi prevajalniku.
Opombi:
−
V navodilih nalog so šumniki pravilno pisani. V zahtevkih po
izpisih programov in v rešitvah nalog pa šumnikov ni. Velika
večina programskih orodij za ANSI C programiranje za zapis črk
uporablja le standardno tabelo 256 ASCII znakov brez šumnikov.
−
Za ANSI C prevajalnik s piko ločimo celi in decimalni del
realnega števila. Oba dela nimata dodatnih znakov za izboljšanje
preglednosti (na primer knjižno oblikovan zapis 1.2345,67 tu
pišemo kot 12345.67).
2.1 Naloge
2.1.1
N: Dober dan, svet
Program naj izpiše:
“Dober dan, svet!”
“Hello world!“
Namen: Naš prvi program. Nepisano pravilo je, da je v vsakem jeziku
prvi izdelek napis “Hello world“, torej “Dober dan, svet! “
Izpis:
//---
2.1.2
N: Navodilo programerju
Program naj izpiše:
“1. V C jeziku je pomembno razlikovati med velikimi in malimi crkami.
2. Program zacnemo s funkcijo main().
3. Vsako funkcijo zacnemo z zavitim oklepajem in koncamo z zavitim
zaklepajem.
4. Vsak programski stavek zakljucimo s podpicjem.“
Namen: Raba funkcije printf() s kontrolnim znakom za novo vrsto in z
zapisom oklepaja.
Izpis:
2.1.3
N: printf(), vrnjena vrednost
S funkcijo printf() izpišimo »Zdaj je cetrtek zvecer«. V naslednjem
printf() izpišimo vrnjeno vrednost prvega printf(), - dolžino prvega izpisa.
Namen: Izpis vrnjene vrednosti funkcije printf(). Funkcije pišemo tako,
da z vrnjeno vrednostjo informirajo o načinu izvajanja ali o vrsti napake
v izvajanju funkcije.
Izpis:
//---
2.1.4
N: Osebna vizitka
Napišimo program, ki s funkcijo printf() semi-grafično izpiše vizitko
poljubne osebe v poljubni obliki.
Namen: Izpis besedila z ambicijo grafičnega oblikovanja.
Izpis:
2.2 Rešitve (R)
2.2.1
R: Dober dan, svet
/* najprej pojasnilo o #pragma – pragmatic – pragmaticen – prakticen: vsi ukazi, ki sledijo po #pragma do konca vrste, so namenjeni prevajalniku iz C kode v strojni jezik.
#pragma hdrstop – header stop: vsa koda pred vrstico #pragma hdrstop se prevede ob zahtevku po prevajanju le, ce je v tej kodi kaksna sprememba, sicer pa se le doda zadnji prevod te kode trenutnemu prevodu ostanka kode za vrstico #pragma hdrstop. Namen: hitrejse prevajanje, kadar je na zacetku datoteke veliko #include stavkov z deklaracijami in/ali definicijami podatkovnih struktur in funkcij iz knjiznic in/ali preostalih datotek, gradnikov konkretnega programa.
#pragma argsused – arguments used: velja za argumente funkcije neposredno za #pragma argsused. Prevajalnik naj ne opozori, kadar argumenti funkcije v funkciji niso uporabljeni. main() obicajno klicemo brez argumentov in ne potrebujemo opozorila na to pri vsakem prevajanju.
*/ //--- #include <stdio.h> #pragma hdrstop //--- #pragma argsused
int main(int argc, char* argv[]) { printf("\nPozdravljen svet!\n"); printf("Hello world!\n"); return 0; } //---
2.2.2
R: Navodilo programerju
//--- #include <stdio.h> #pragma hdrstop //--- #pragma argsusedint main(int argc, char* argv[]) {
printf ("\n1. V C jeziku je pomembno razlikovati med velikimi in malimi crkami.\n");
printf ("2. Program zacnemo s funkcijo main\(\).\n");
printf ("3. Vsako funkcijo zacnemo z oklepajem in koncamo z oklepajem.\n"); printf ("4. Vsak programski stavek zakljucimo s podpicjem.\n");
printf("\n"); return 0; }
2.2.3
R: printf(), vrnjena vrednost
//--- #include <stdio.h> #pragma hdrstop //--- #pragma argsusedint main(int argc, char* argv[]) {
int x;
x = printf("\nZdaj je cetrtek zvecer.\n");
printf("Vrnjena vrednost funkcije printf\(\) je: %d\n", x);
return 0; }
2.2.4
R: Osebna vizitka
//--- #include <stdio.h> #pragma hdrstop //--- #pragma argsusedint main(int argc, char* argv[]) {
printf("\n******************************\n"); printf("* *\n"); printf("* Janez Franc Novakov *\n"); printf("* *\n"); printf("* Cesta v mestni log 42 *\n"); printf("* 1000 Ljubljana *\n"); printf("* *\n"); printf("* +386 41 555 000 *\n"); printf("* *\n"); printf("******************************\n"); return 0; } //---
3 Spremenljivke, podatkovni tipi in aritmetični izrazi
Poudarki:
−
Deklaracija spremenljivk tipa int, float, double, long double,
char.
−
Niz spremenljivk tipa char.
−
Aritmetični operatorji +, -, *, /, % s celoštevilskimi
spremenljivkami tipa int.
−
Aritmetični operatorji +, -, *, / s tipi spremenljivk za realna
števila.
−
Kompaktni aritmetični operator +=.
−
Računske operacije med argumenti tipov int in float.
−
Potenciranje x
y, pow(x,y).
−
Uporaba in oblike izpisov velikih in majhnih števil z eksponenti,
n *10
m, nEm.
−
Vnos celih in realnih števil s scanf().
−
Izpis niza s puts().
−
Izpis spremenljivk tipa int, float, double, long double, char s
printf().
3.1 Naloge
3.1.1
N: scanf(), printf()
Napišimo program, ki naj z uporabo printf(), scanf() izvede:
Vpisite avtomobilsko znamko in model: npr. Renault
Vpisite model avtomobila: npr. Clio
Vpisite ceno: npr. 1400
Avtomobil Renault Clio stane 1400 Eur.
Namen: Vpis podatka s scanf(), sestavljen izpis.
Izpis:
3.1.2
N: Kalkulator
Napišimo program, ki prebere dve celi števili ter izpiše vsoto, razliko,
produkt, kvocient in ostanek pri deljenju. Delovanje:
Vpisite 1. celo stevilo: npr. 5
Vpisite 2. celo stevilo: npr. 4
6 + 4 = 10
6 - 4 = 2
6 * 4 = 24
6 / 4 = 1
6 % 4 = 2
Namen: Delo s celimi števili: vnos, uporaba operatorjev algebre, izpis.
Izpis:
//---
3.1.3
N: Polinom
Napišimo program, ki bo izračunal 3 ∗ 𝑥
3− 5 ∗ 𝑥
2+ 6 za x = 2.55
Namen: Računanje z realnimi števili, spremenljivke tipa float, funkcija
pow(x,y).
Možen izpis:
3.1.4
N: Ulomek z eksponenti
Napišimo program, ki bo izračunal in izpisal rezultat za izraz
(3.31 * 10
-8* 2.01 * 10
-7) / (7.16 * 10
-6+ 2.01 * 10
-8)
Namen: Računanje z majhnimi (in velikimi) števili, spremenljivke tipa
float, double, long double, rezultat izpisan v različnih formatih.
Možen izpis:
//---
3.1.5
N: Obseg in površina kroga
Program naj izračuna obseg in površino kroga in naj podatke izpiše na 3
decimalna mesta natančno.
Namen: Določitev π, izpis realnih števil na n decimalnih mest.
Izpis:
3.1.6
N: Vsota kotov
Napišimo program, ki prebere dva kota v stopinjah, minutah in sekundah
(celoštevilske vrednosti). Nato naj izračuna in izpiše njuno vsoto.
Rezultat naj bo spet v stopinjah, minutah in sekundah.
Namen: Seštevanje in pretvarjanje podatkov v celih številih. Za dosego
tega cilja je smiselno računati v najmanjših enotah (v tem primeru v
sekundah) in rezultat ob izpisu prilagoditi v željeno obliko.
Izpis:
//---
3.1.7
N: Preračun iz °F v °C
Program naj preračuna Fahrenheitove v Celzijeve stopinje.
Namen: Vnos celega števila, izpis realnega števila, algebra s celim in
realnim številom.
Izpis:
3.1.8
N: Pretvorba iz radianov v stopinje
Napišimo program, ki prebere geometrijski kot kot realno število v
radianih in ga izpiše kot realno število v stopinjah.
Namen: Določitev števila π, vpis in izpis ter račun z realnimi števili.
Izpis:
//---
3.1.9
N: Obrat števk
Napišimo program, ki prebere štirimestno številko in jo izpiše v
obratnem vrstnem redu.
Namen: Razstavljanje in sestavljanje številke v števke. Uporaba
celoštevilskega deljenja in ostanka celoštevilskega deljenja.
Izpis:
3.2 Rešitve (R)
3.2.1
R: scanf(), printf()
//--- #include <stdio.h> #pragma hdrstop //---char cZnamkaAvta[80], cModelAvta[80]; int iCena;
printf("\nVpisite avtomobilsko znamko: "); scanf("%s",&cZnamkaAvta);
printf("Vpisite model avtomobila: "); scanf("%s",&cModelAvta);
printf("Vpisite ceno: "); scanf("%d",&iCena);
printf("Avtomobil %s %s stane %d Eur.\n",cZnamkaAvta, cModelAvta, iCena); return 0;
}
3.2.2
R: Kalkulator
//--- #include <stdio.h> #pragma hdrstop //--- #pragma argsusedint main(int argc, char* argv[]) {
int iA, iB;
int vsota, razlika, produkt, kolicnik, ostanek;
puts("\nPo vpisu dveh celih stevil dobite vsoto, razliko. produkt, kolicnik in ostanek.");
printf("Vpisite 1. celo stevilo: "); scanf("%d", &iA);
printf("Vpisite 2. celo stevilo: "); scanf("%d", &iB); vsota = iA + iB; razlika = iA - iB; produkt = iA * iB; kolicnik = iA / iB; ostanek = iA % iB;
printf("%d + %d = %d\n", iA, iB, vsota); printf("%d - %d = %d\n", iA, iB, razlika); printf("%d * %d = %d\n", iA, iB, produkt); printf("%d / %d = %d\n", iA, iB, kolicnik); printf("%d %% %d = %d\n", iA, iB, ostanek); puts("");
return 0; }
3.2.3
R: Polinom
//--- #include <stdio.h> #include <math.h> #pragma hdrstop //--- #pragma argsusedint main(int argc, char* argv[]) {
float x = 2.55;
float y = 3 * x*x*x - 5 * x*x + 6;
float yy = 3 * pow(x,3) - 5 * pow(x,2) + 6; float fRazlika = y - yy;
puts("\nRacunamo 3 * x**3 - 5 * x**2 + 6 za x=2.55."); printf ("Rezultat je %f.\n", y);
printf ("Razlika med mnozenjem in rabo pow(x,y) je %f.\n", fRazlika); puts("");
return 0; }
3.2.4
R: Ulomek z eksponenti
//--- #include <stdio.h> #include <math.h> #pragma hdrstop //--- #pragma argsusedint main(int argc, char* argv[]) {
// za prikaz rezultata uporabimo exponentni format // (3.31 x 10-8 x 2.01 x 10-7) / (7.16 x 10-6 + 2.01 x 10-8)
// Mozna deklariranja za realno stevilo so: // "float": 32 bitov, 3.4E-38 <-> 3.4E38 // "double": dvojni "float", 64 bitov
// opcijski modifier "long" poveca tocnost tipa "double", 80 bits float fRezultat;
puts("\nRacunamo (3.31E-8 * 2.01E-7) / (7.16E-6 + 2.01E-8)\n"); fRezultat = (3.31E-8 * 2.01E-7) / (7.16E-6 + 2.01E-8);
//double dRezultat = (3.31E-8 * 2.01E-7) / (7.16E-6 + 2.01E-8); puts ("Izpis z %i, razumljivo narobe:");
printf ("Rezultat je %i\n\n", fRezultat);
// %i: -1073741824 je narobe, kar je razumljivo: float je izpisan kot int puts ("Izpis z %e:");
printf ("Rezultat je %e\n\n", fRezultat); // eXponent // %e: 9.266027e-10
// %E: 9.266027E-10
puts ("Izpis z %f:");
printf ("Rezultat je %f\n\n", fRezultat); // float // %f: 0.000000
puts ("Izpis z %g, je krajse izmed %e in %f:"); printf ("Rezultat je %g\n\n", fRezultat); // %g: 9.26603e-10
puts ("Izpis z %G, je krajse izmed %E in %f, NAJBOLJ USTREZNO"); printf ("Rezultat je %G\n\n", fRezultat);
// %g: 9.26603E-10
return 0; }
3.2.5
R: Obseg in površina kroga
//--- #include <stdio.h> #include <math.h> #pragma hdrstop //--- #pragma argsusedint main(int argc, char* argv[]) {
#define PI 3.1416
double r, obseg, ploscina;
printf("\nRacunamo obseg in povrsino kroga, vpisite polmer: "); scanf("%lf", &r);
obseg = 2 * PI * r; ploscina = PI * pow(r,2);
printf("Radij kroga je %.3f, obseg kroga je %.3f, povrsina kroga je %.3f.\n\n", r, obseg, ploscina);
return 0; }
3.2.6
R: Vsota kotov
//--- #include <stdio.h> #pragma hdrstop //--- #pragma argsusedint main(int argc, char* argv[]) {
int vsota, n; int st, min, sek; vsota = 0;
// smiselno je vse racunati v sekundah, da bo vse v celostevilskem racunanju puts("\nRacunamo vsoto dveh kotov:");
puts("Vpisite prvi kot:");
// stopinja: 3600 sekund
printf(" stopinje: "); scanf("%d", &n); vsota += 3600*n;
// minuta: 60 sekund
printf(" minute: "); scanf("%d", &n); vsota += 60*n;
printf(" sekunde: "); scanf("%d", &n); vsota += n;
printf("Vpisite drugi kot:\n");
printf(" stopinje: "); scanf("%d", &n); vsota += 3600*n; printf(" minute: "); scanf("%d", &n); vsota += 60*n; printf(" sekunde: "); scanf("%d", &n); vsota += n;
// vsota je v sekundah, operator % 60 da ostanek sekund sek = vsota % 60;
// minut 60 krat manj od sekund, operator % 60 da ostanek minut min = (vsota / 60) % 60;
st = vsota / 3600; // celostevilsko deljenje s 3600
printf("Vsota obeh kotov je %i stopinj, %i minut in %i sekund.\n\n", st, min, sek);
return 0; }
3.2.7
R: Preračun iz °F v °C
//--- #include <stdio.h> #include <math.h> #pragma hdrstop //--- #pragma argsusedint main(int argc, char* argv[]) {
// C = (F - 32) / 1.8
int iFStopinje; float fCStopinje;
puts("\nCelostevilske F stopinje, pretvorba v C stopinje: "); scanf("%d", &iFStopinje);
fCStopinje = (iFStopinje - 32) / 1.8;
printf ("%i stopinj Fahrenheita je %f stopinj Celzija\n", iFStopinje, fCStopinje); return 0;
}
3.2.8
R: Pretvorba iz radianov v stopinje
//--- #include <stdio.h> #include <math.h> #pragma hdrstop //--- #pragma argsusedint main(int argc, char* argv[]) {
const double PI = acos(-1); float rad, st;
//double rad, st;
printf("\nVpisite kot v radianih: "); scanf("%f", &rad);
//scanf("%lf", &rad);
st = rad * 180 / PI;
printf("%f radianov = %f stopinj.\n", rad, st); //printf("%lf radianov = %lf stopinj.\n", rad, st); return 0;
}
3.2.9
R: Obrat števk
//--- #include <stdio.h> #include <math.h> #pragma hdrstop //--- #pragma argsusedint main(int argc, char* argv[]) {
int iNTisocic, iNStotic, iNDesetic, iNEnic; int iStevilka, iObrnjena;
puts("\nObracamo stirimestno stevilko."); printf("Vpisite stirimestno stevilko: "); scanf("%d", &iStevilka); iNEnic = iStevilka % 10; iNDesetic = (iStevilka / 10) % 10; iNStotic = (iStevilka / 100) % 10; iNTisocic = (iStevilka / 1000) % 10;
iObrnjena = 1000 * iNEnic + 100 * iNDesetic + 10 * iNStotic + iNTisocic; printf("Obrnjena stevilka %d je %d.\n", iStevilka, iObrnjena);
// ali:
// printf("Obrat številke %d je %d%d%d%d.\n", iStevilka, iNEnic, iNDesetic, // iNStotic, iNTisocic);
return 0; }
4 Programske zanke
Poudarki:
−
Zanka for (inicializacija; logični pogoj; sprememba) { stavki; };.
−
Zanka do { stavki; } while (logični pogoj);.
−
Zanka while (logični pogoj) { stavki; }.
−
Logični pogoji za izvajanje zank: a <=b, c != n, n-- > 0.
−
Inkrementi za izvajanje zank: ++i; i++; i+=n.
−
Izhod iz zanke z break;.
−
V zanko vgnezdena zanka.
−
Izpis ASCII znakov tipa char v zanki po različnih kriterijih izbire.
−
Branje črk vrstice v zanki z getchar(), pisanje črk vrstice v zanki s
putchar().
−
Argumenti krožnih funkcij iz knjižnice math so v radianih in so
tipa double.
−
Izpisi v zanki for (inicializacija; logični pogoj; inkrement) {
4.1 Naloge
4.1.1
N: Izpis ASCII znakov, [0 .. 255]
Napišimo program, ki bo izpisal tabelo ASCII znakov od 0 do 255.
Namen: ASCII znaki, izpis v zanki.
Izpis:
//---
4.1.2
N: Izpis ASCII znakov iz intervala
Program naj izpiše ASCII znake iz intervala med dvema vnešenima
številkama.
Namen: Izpis določenih ASCII znakov v zanki.
Izpis:
4.1.3
N: Izpis abecede velikih črk
Izpišimo abecedo velikih črk. Izpis napišimo v zanki.
Namen: Izpis velikih črk abecede v zanki.
Izpis:
//---
4.1.4
N: Izpis abecede malih črk
Izpišimo abecedo malih črk. Izpis napišimo v zanki.
Namen: Izpis malih črk abecede v zanki.
Izpis:
//---
4.1.5
N: getchar(), putchar()
Program naj prebere vrstico, ki jo vpišemo do tipke »Enter« in naj jo
izpiše. To naj poteka v zanki. Če je v prebrani vrstici znak ‘.’, naj se
delovanje programa konča.
Namen: Branje črk vrstice v zanki z getchar(), pisanje črk vrstice v zanki
s putchar().
4.1.6
N: 12 faktoriel
Napišimo program, ki izračuna in izpiše tabelo prvi 12 faktoriel (od 1 !
do 12 ! ).
npr. 5! = 5 x 4 x 3 x 2 x 1 = 120
Namen: Računanje in izpis v zanki. Prejšnji rezultat uporabimo v
izračunu trenutnega rezultata.
Izpis:
4.1.7
N: Tabela sinus[0..2π]
Tabelirajmo funkcijo sin(x) med 0° in 360° (2 π radianov) s korakom 10°.
Namen: Uporaba funkcij iz matematične knjižnice. Ugotovitvi, da so
argumenti teh funkcij tipa double (64 bit) in da je argument x funkcije
sin(x) v radianih. Pretvorba med radiani in stopinjami, oblikovanje izpisa.
Izpis:
//---
4.1.8
N: Integral sin(x)
Napišimo program za računanje integrala funkcije sin(x) po trapezni
metodi v mejah [0 .. 2π]. Program naj sešteva predznačene ploščine
oziroma produkte vrednosti (sin(x) + sin(x+ Δ
x) / 2) z razmaki Δx.
Namen: Računanje integrala funkcije po trapezni metodi oziroma
predznačene ploščine pod krivuljo funkcije. Opaziti, da je računanje
ploščine pod krivuljo funkcije, ki je simetrična glede na absciso,
praktično neodvisno od velikosti Δx, če predznačeno ploščino računamo
za celo periodo funkcije in če je perioda večkratnik Δ
x. Razlog je
simetričnost funkcije – enako napako predznačene ploščine dobimo nad
in pod absciso. Napaki se odštejeta. Če perioda ni večkratnik Δx, je
napaka opazna.
4.1.9
N: Integral polinoma
Po trapezni metodi izračunajmo približek integrala funkcije 𝑓(𝑥) =
𝑥
2+ 5𝑥 + 3 na intervalu [0 .. 10] s korakom 0,001 (10000 korakov).
Namen: Računanje integrala funkcije oziroma predznačene ploščine pod
krivuljo funkcije. Opaziti, da bo napaka rezultata odvisna od izbire
velikosti Δx.
Izpis:
//---
4.1.10 N: Fibonaccijevo zaporedje
Sestavimo program, ki izpiše prvih n členov Fibonaccijevega zaporedja
(to je zaporedje, podano s predpisom: f(1) = 1, f(2) = 1, f(n) = f(n-1) +
f(n-2).
Namen: Računanje in izpis v zanki. Seznanitev s Fibonaccijevim
zaporedjem.
Izpis:
4.1.11 N: Piramida
Sestavimo program, ki bo izpisal piramido velikosti n, kot je to prikazano
v izpisu. Uporabnik vnese število vrstic n oziroma višino. Spodnja vrstica
piramide naj začne skrajno levo.
Namen: Oblikovanje izpisa v zanki. Ugotoviti zakonitost pisanja splošne
vrstice, ki jo potem izpisujemo v zanki s tekočimi indeksi.
Izpis:
//---
4.1.12 N: Poštevanka 10 * 10
Vprogramirajmo izpis poštevanke od 1 do 10, z oznakami 1-10 zgoraj in
ob strani.
Namen: Izračun in oblikovanje izpisa v zankah. Ena zanka naj bo za prvo
vrsto, ena za drugo vrsto, ena za preostanek izpisa.
4.1.13 N: Vsota števk
Napišimo program, ki izračuna vsoto števk vnesene številke. Vse števke
naj bodo različne od 0. Vpis številke, izračun in izpis naj bodo v zanki,
katere izvajanje prekinemo z vnosom številke 999.
Namen: Uporaba celoštevilskega deljenja in ostanka v zanki za izvedbo
naloge.
Izpis:
//---
4.1.14 N: e
xkot vrsta do (člen < ε)
Sestavimo program, ki prebere realno število x in izračuna e
xs pomočjo
spodnje potenčne vrste. Zadnji upoštevani člen potenčne vrste naj bo
večji ali enak vnaprej predpisani konstanti ε (dovoljena napaka).
𝑒
𝑥= 1 +
𝑥
22! +
𝑥
33! + ⋯ +
𝑥
𝑛−1(𝑛 − 1)!
Namen: Računanje v zanki. Iteracijski postopek zaključimo ob dovolj
majhnem členu.
Izpis:
4.2 Rešitve (R)
4.2.1
R: Izpis ASCII znakov, [0 .. 255]
//--- #include <stdio.h>
#pragma hdrstop
//--- #pragma argsused
int main(int argc, char* argv[]) { int i; puts (""); for (i = 0; i <= 255; ++i) printf("%d %c\n", i, i); return 0; } //---
4.2.2
R: Izpis ASCII znakov iz intervala
//--- #include <stdio.h> #pragma hdrstop //--- #pragma argsusedint main(int argc, char* argv[]) {
int m, n, i;
printf("\nVpisite spodnjo mejo v ASCII tabeli: "); scanf("%d", &m);
printf("Vpisite zgornjo mejo v ASCII tabeli: "); scanf("%d", &n);
for (i=m; i<=n; i++) printf("%d = '%c'\n", i, i); printf("\n"); return 0; } //---
4.2.3
R: Izpis abecede velikih črk
//--- #include <stdio.h> #pragma hdrstop //--- #pragma argsusedint main(int argc, char* argv[]) { int i; puts(""); for (i = 65; i <= 90; ++i) { //printf("%d %c ", i, i); printf("%c ", i); } printf("\n"); return 0; } //---
4.2.4
R: Izpis abecede malih črk
//--- #include <stdio.h> #pragma hdrstop //--- #pragma argsusedint main(int argc, char* argv[]) { int i; puts(""); for (i = 97; i <= 122; ++i) { //printf("%d %c ", i, i); printf("%c ", i); } printf("\n"); return 0; } //---
4.2.5
R: getchar(), putchar()
//--- #include <stdio.h> #pragma hdrstop //--- #pragma argsusedint main(int argc, char* argv[]) {
char c;
puts("\nVpisite besedilo (koncajte vpis z Enter, program pa s . (piko)):");
do { c=getchar(); putchar(c); } while (c != '.'); puts(""); return 0; } //---
4.2.6
R: 12 faktoriel
//--- #include <stdio.h> #pragma hdrstop //--- #pragma argsusedint main(int argc, char* argv[]) {
int i, j = 1;
puts ("\nTabela prvih 12 faktoriel:\n"); puts (" i i!\n");
for (i=1; i<= 12; i++) { j = j * i;
printf (" %2i %10i\n", i, j); }
return 0; }
4.2.7
R: Tabela sin[0 .. 2π]
//--- #include <stdio.h> #include <math.h> #pragma hdrstop //--- #pragma argsusedint main(int argc, char* argv[]) {
// pi = 180 stopinj, cos(pi) = -1
// kotne funkcije imajo argumente v radianih
// sin(x) argumenti: double, zato double Pi in izpis %9lf int i; double Pi = acos(-1); puts(""); for (i = 0; i <= 360; i += 10) { printf("sin(%3d) = %9lf\n", i, sin(Pi*i/180.0)); } return 0; } //---
4.2.8
R: Integral sin(x)
//--- #include <stdio.h> #include <math.h> #pragma hdrstop //--- #pragma argsusedint main(int argc, char* argv[]) {
double pl=0, y; int i;
double Pi = acos(-1); int korak = 1; // stopinj puts("");
for (i = 0; i <= 360-korak; i += korak)
pl += (sin(Pi*i/180.0) + sin(Pi*(i+korak)/180.0)) /2 * korak;
printf("pl = %lf\n", pl); return 0;
}
4.2.9
R: Integral polinoma
//--- #include <stdio.h> #include <math.h> #pragma hdrstop //--- #pragma argsusedint main(int argc, char* argv[]) {
double korak = 0.001; double pl=0, y1, y2, x;
for (x=0.0; x<=(10.0-korak); x+=korak) { y1 = pow(x,2) + 5*x + 3; y2 = pow(x+korak,2) + 5*(x+korak) + 3; pl += (y1+y2)/2 * korak; } printf("\npl = %lf\n", pl); return 0; } //---
4.2.10 R: Fibonaccijevo zaporedje
//--- #include <stdio.h> #include <math.h> #pragma hdrstop //--- #pragma argsusedint main(int argc, char* argv[]) {
int n, a, b, c;
printf("\nVpisite stevilo clenov: "); scanf("%d", &n);
printf("Cleni zaporedja so:"); a = 1;
b = 0;
while (n-- > 0) { // n se postopno zmanjsuje // je pac navzdol tekoci stevec // razlikovati med --n in n-- c = a + b; printf(" %d", c); a = b; b = c; //n--; } printf("\n"); return 0; } //---
4.2.11 R: Piramida
//--- #include <stdio.h> #include <math.h> #pragma hdrstop //--- #pragma argsusedint main(int argc, char* argv[]) {
int visina; int i, j;
printf("\nVpisite visino piramide: "); scanf("%d", &visina);
// najprej je potrebno ugotoviti pravilo:
// V i-ti vrstici je (visina - i) presledkov in (2 * i - 1) zvezdic.
for (i=1; i<=visina; i++) { for (j=1; j<=visina-i; j++) printf(" "); for (j=1; j<=2*i-1; j++) printf("*"); printf("\n"); } return 0; } //---
4.2.12 R: Poštevanka 10 * 10
//--- #include <stdio.h> #pragma hdrstop //--- #pragma argsusedint main(int argc, char* argv[]) {
int i, j, k, l; // prva vrsta printf("\n |"); for(i=1; i<=10; i++) printf(" %3d",i); printf("\n"); // druga vrsta for(j=1; j<=i; j++) printf("----"); printf("\n"); // preostanek izpisa for(k=1; k<=10; k++){ printf(" %2i| ", k); for(l=1; l<=10; l++) printf("%3i ",k*l); printf("\n"); } return 0; } //---