Funkcije, spremenljivke in prototipi
NA�A PRVA UPORABNI�KO DEFINIRANA FUNKCIJA
Primer programa ------> SUMSQRES.C
Nalo�ite in si oglejte program SUMSQRES.C kot primer programa v C-ju s funkcijami. Pravzaprav to ni prva funkcija, ki smo jo do sedaj sre�ali, saj je program, ki smo ga do sedaj najve� uporabljali funkcija, to je printf( ) funkcija. Printf( ) funkcija sodi v knji�nico funkcij, ki je �e na voljo prevajalniku.
V tem poglavju bomo kon�no definirali, �emu slu�i vrstica 3, vendar �ele, ko pridemo to �etrtega primera, torej �e malo po�akajte in za sedaj to vrstico ignorirajte.
Pozorni bodite na izvajalni del tega programa, ki se za�ne v vrstici
10 z vrstico kode, ki pravi "header( );", to pa je na�in klicanja katerekoli
funkcije. Oklepaj je potreben, saj
C z njegovo pomo�jo ugotovi, da je to funkcija, ne pa narobe postavljena
spremenljivka. Ko program pride do te vrstice kode, pokli�e funkcijo header(),
njeni stavki se izvedejo, nato pa nas kontrola programa vrne na stavek,
ki sledi temu klicu. �e nadaljujemo, pridemo do for zanke, ki se
bo izvedel sedemkrat in ki ob vsakem prehodu skozi zanko kli�e novo funkcijo,
square( ). Nazadnje se bo poklicala in izvedla �e funkcija ending( ). Za
trenutek ignorirajte ime spremenljivke index v oklepaju klica funkcije
square( ). Vidimo, da ta program pokli�e header, sedemkrat poklice square,
ter enkrat ending. Sedaj moramo te funkcije definirati.
DEFINIRANJE FUNKCIJ
Glavnemu programu sledi funkcija, ki se za�ne v vrstici 19, ki se dr�i vseh pravil, ki smo jih podali za glavni porgram, le da se imenuje header( ). To je funkcija, ki jo klicemo iz vrstice 19 v programu. Vsak od njenih stavkov se izvede, ko pa je to kon�ano, nas kontrola vrne v glavni program ali bolj natan�no, funkcijo main( ).
Prvi stavek dodeli spremenljivki sum vrednost ni�, saj jo nameravamo uporabiti za se�tevek vseh kvadratov. Ker spremenljivko sum definiramo pred glavnim programom, je dosegljiva vsem funkcijam, ki jih definiramo pozneje. Taki spremenljivki pravimo globalna spremenljivka, velja pa �ez celoten program, tudi v novih funkcijah. V�asih ji re�emo tudi datote�na spremenljivka, saj je dosegljiva po celotni datoteki. Ve� o dosegljivosti spremenljivk bo povedano na koncu tega poglavja. Stavek v vrstici 22 izpi�e glavo na zaslon. Programska kontrola nas potem vrne v main() funkcijo, saj tu ni ve� stavkov, ki bi se morali izvesti. Tako pademo skozi dno funkcije in se vrnemo na stavek, ki se nahaja takoj za klicem te funkcije.
Moralo bi biti jasno, da bi lahko dva izvajalna stavka iz te funkcije
premaknili v glavni program, z njima nadomestili klic funkcije header(),
pa bi program naredil nata�no to, kot sedaj. To ne zmanj�uje vrednost funkcijam,
pa� pa enostavno prika�e delovanje te preproste funkcije. Videli boste,
da so funkcije zelo dragocene v programiranju v C-ju.
PODAJANJE VREDNOSTI FUNKCIJAM (KLASI�NA METODA)
�e se vrnemo na glavni program, ali �e bolj natan�no, na for zanko, najdemo nov konstrukt s konca prej�njega poglavja, to je index++ v vrstici 11. Koristno bi bilo, �e bi se dobro spoznali s tem konstruktom, saj ga boste videli v ve�ini C programov.
V klicu funkcije square( ), imamo dodano �e eno zadevo, spremenljivko index v oklepaju. To je znak prevajalniku, da �elite ob izvajanju te funkcije s seboj prenesti vrednost spremenljivke index za uporabo ob izvajanju te funkcije. �e pogledamo naprej na funkcijo square() v vrstici 26, vidimo da je v oklepaju te funkcije zapisana druga spremenljivka, number. To je ime, ki ga �elimo uporabljati za klic spremenljivke za uporabo, ko izvajamo stavke znotraj te funkcije. Lahko jo imenujemo kakorkoli, le da se dr�imo pravil imenovanja identifikatorja in da ime ni rezervirana beseda. Ker mora funkcija vedeti, katerega tipa je spremenljivka, je ta definirana za imenom funkcije, vendar pred za�etnim zavitim oklepajem. Torej stavek v vrstici 23 "int number;" pove funkciji, da bo podana vrednost tipa integer (celo�tevilska). Ko smo vse to opravili, imamo vrednost index-a iz glavnega programa podano funkciji square(), vendar preimenovano v number, in tako dosegljivo za uporabo. To je klasi�ni stil definiranja funkcijskih spremenljivk, ki je v uporabi �e od prvih verzij jezika C. Novej�a in mnogo bolj�a metoda pa pridobiva na popularnosti zaradi njenih mnogih prednosti, obdelali pa jo bomo pozneje v tem poglavju.
Za za�etnim zavitim oklepajem definiramo novo spremenljivko numsq za uporabo samo v tej funkciji (ve� o tem kasneje) in pri�nemo s potrebnimi izra�uni. Spremenljivki numsq priredimo vrednost kvadrata spremenljivke number, nato pa numsq pri�tejemo trenutni vsoti, ki se nahaja v spremenljivki sum. Iz prej�njega poglavja se spomnimo, da izraz "sum += numsq;" pomeni isto kot "sum = sum + numsq;". V vrstici 33 izpi�emo �tevilo in njegov kvadrat, nato pa se vrnemo v glavni program.
VE� O PODAJANJU VREDNOSTI FUNKCIJAM
Ko smo vrednost spremenljivke index podali funkciji, se je zgodilo nekoliko ve�, kot se zdi na prvi pogled. Funkciji nismo podali spremenljivke index, pa� pa smo ji podali kopijo njene vrednosti. Tako je izvirna vrednost za�citena pred nenamerno zlorabo funkcije. Spremenljivko number bi lahko v funkciji square( ) spreminjali na katerikoli �eleni na�in, ko pa bi se vrnili v glavni program, se vrednost spremenljivke index ne bi spremenila. Tako lahko za��itimo spremenljivko pred zlorabo, ne moremo pa vra�ati njene vrednosti klicajo�i funkciji iz klicane funkcije. Videli bomo, da obstaja dobro definirana metoda, ko bomo pri�li do polj, in �e ena, ko bomo obdelali kazalce. Do takrat pa bo edini na�in komunikacije s kli�o�o funkcijo s pomo�jo uporabe globalne spremenljivke. Nakazali smo �e nekaj stvari o globalnih spremenljivkah, ve� o njih pa bomo povedali pozneje v tem poglavju.
�e nadaljujemo v main( ) funkciji, pridemo do zadnjega funkcijskega
klica, klica funkcije ending( ) v vrstici 13. Ta vrstica pokli�e funkcijo,
ki nima definiranih nobenih lokalnih spremenljivk. Izpi�e sporocilo in
vrednost spremenljivke sum, ki jo vsebuje in tako zaklju�i program. Program
se kon�a z vrnitvijo v main() funkcijo in ker tam ne najde ni�esar vec,
se program zaklju�i. Prevedite in po�enite ta program in si oglejte izpis.
SEDAJ PA PRIZNANJE MAJHNE LA�I
Pred kratki sem dejal, da je edini na�in prenosa vrednosti do kli�o�e funkcije z uporabo globalne spremenljivke, vendar pa obstaja �e en na�in, katerega bomo obdelali, ko boste nalo�ili in si ogledali program SQUARES.C. V tem primeru bomo videli, da je lahko vrniti posamezno vrednost iz klicane funkcije v kli�o�o funkcijo. Vendar �e enkrat, �e hocemo vrniti ve� kot eno vrednost, bomo morali spoznati polja ali pa kazalce.
Primer programa ------> SQUARES.C
V main() funkciji definiramo dve celo�tevilski spremenljivki
in za�nemo s for zanko, ki se bo izvedla osemkrat. Prvi stavek v
for zanki je "y = squ(x);", kar je nov in precej nenavaden konstrukt. Iz
pre�njih izku�enj vam
verjetno ni te�;ko sklepati, da je del stavka squ(x) klic funkcije
squ(), ki s seboj vzame vrednost x-a kot parameter. �e pogledamo naprej
v vrstico 20, vidimo, da funkcija vhodno spremenljivko imenuje raje input
in njegovo vrednost kvadrira, rezultatu pa da ime square. V vrstici 26
pa se pojavi nova vrsta stavka, return stavek. Vrednost v
oklepaju je podana sami funkciji in se vrne kot vrednost, ki jo lahko uporabimo
v glavnem programu. Tako funkcijskemu klicu "squ(x)priredimo vrednost
kvadrata, ki jo potem vrnemo v glavni program tako, da dobi y vrednost
kvadrata. �e bi torej pred klicem x-u dodelili vrednost 4, bi y zaradi
vrstice 10 dobil vrednost 16.
Oklepaj okrog vra�ajoce vrednosti v vrstici 26 ni nujno potreben, vendar ga ve�ina izku�enih programerjev vseeno zapi�e.
Drug na�in, kako si to la�je predstavljamo je, da si mislimo, da je izraz squ(x) samo �e ena spremenljivka, ki ima vrednost x2 in jo lahko postavimo kamorkoli lahko postavimo spremenljivko tega tipa. Vrednosti spremenljivk x in y nato �e izpi�emo.
Da bi prikazali, da lahko izraz squ(x) res uporabljamo kot navadno spremenljivko, je v vrstici 14 zapisana �e ena for zanka, kamor namesto imena spremenljivke v printf() stavek postavimo kar klic funkcije.
�e eno zadevo je treba omeniti. Tip vrednosti, ki jo funkcija vra�a, moramo definirati, da bi imeli smiselne podatke, �e pa tega ne storimo, prevajalnik definira vrednost kot tip int. �e �elimo imeti katerega od drugih tipov, moramo to izrecno definirati. Kako to storimo, bo prikazano v naslednjem programu. V tem programu uporabljamo kar vrednost, ki nam jo definira prevajalnik.
Prevedite in po�enite ta program, ki prav tako uporablja klasi�no metodo
definiranja funkcijskih spremenljivk. �e enkrat, zanemarite vsa
opozorila.
FUNKCIJE, KI VRACAJO �TEVILA S PLAVAJO�O VEJICO
Primer programa ------> FLOATSQ.C
Nalo�ite program FLOATSQ.C kot primer klasi�no definirane funkcije, ki vra�a vrednost tipa float. Za�ne se z definicijo globalne spremenljivke s plavajo�o vejico z, katero bomo uporabili kasneje. nato v glavnem programu definiramo celo�tevilsko spremenljivko in nato �e dve spremenljivki s plavajo�o vejico, sledita pa �e dve nenavadni definiciji. Izraza sqr() in glsqr() izgledata kot klica funkcij. To je pravilen na�in definicije, da funkcija ne bo vra�ala vrednosti tipa int, pa� pa nekega drugega tipa, v tem primeru float. To pove prevajalniku, da bo vrednost, prene�ena iz teh dveh funkcij, tipa float. To je, �e enkrat, klasi�na metoda definiranja, in je �e zastarel. Bodite pozorni, da iz vrstice 9 ne kli�emo nobene izmed teh dveh funkcij, pa� pa le deklariramo tip, ki jih bosta vra�ali.
Sedaj si oglejte funkcijo z imenom sqr(), ki se za�ne v vrstici 29 in videli boste, da pred imenom funkcije stoji rezervirana beseda float. To je znak prevajalniku, da bo funkcija vra�ala vrednost tipa float vsakemu programu, ki jo bo klical. Tip, ki ga funkcija vra�a, je sedaj kompatibilen z njenim klicem. Vrstica, ki sledi imenu funkcije, vsebuje izraz float inval;, kar je znak prevajalniku, da bo vrednost podana tej funkciji iz klicanega programa tipa float. Ker smo klicatelju povedali, da bomo vra�ali tip float, to v resnici storimo v vrstici 35 tako, da se vse ujema.
Funkcija glsqr(), z za�etkom v vrstici 39, bo prav tako vra�ala tip float, vendar pa za vhod uporablja globalno spremenljivko. Kvadriranje izvaja v samem return stavku in zato ne rabi �e ene spremenljivke, kamor bi shranjevala rezultat. Podobno bi lahko delovala tudi funkcija sqr(), vendar smo to storili posebej, da bi pokazali, da se da to storiti tudi tako.
Splo�na oblika tega programa vam ne bi smela delati problemov in je
zato ne bomo podrobneje obravnavali. Kot je priporo�ljivo z ostalimi primeri,
tudi tega prevedite in po�enite in zanemarite vsa opozorila, ki jih boste
dobili.
KLASI�NI STIL
Trije programi, ki smo jih obdelali do sedaj v tem poglavju uporabljajo
klasi�ni stil definiranja funkcij. �eprav je bil to prvi stil definiran
v C-ju, ga hitro zamenjuje modernej�a metoda definicij funkcije, saj le-ta
veliko bolje odkriva in ozna�uje napake. Ko boste brali �lanke v C-ju,
boste zasledili klasi�no metodo, zato jo morate znati prebrati. To je razlog
za vklju�itev tega stila v te�aj. Priporo�il pa bi vam, da se nau�ite in
uporabljate novej�o metodo, katero bomo kmalu obdelali. Svetujem vam celo,
da v svojem programiranju ne uporabljate klasi�nega
stila.
Knjiga avtorjev Kernigan in Ritchie-a, "The C Programming Language - Second Edition" je najbolj primerno berilo o klasi�nem stilu.
Preostanek tega te�aja bo uporabljal modenro metodo, kot je predlagana
in definirana v ANSI-C standardu. �e imate starej�i prevajalnik, se vam
lahko zgodi, da kateri od primerov ne bodo delovali, zato je na vas, da
jih spremenite v klasi�ni stil. Nazadnje je ANSI-C standard uporabljan
tako splo�no, da bi bilo pametno, da si nabavite prevajalnik kompatibilen
z ANSI-C standardom, �e tega �e niste storili.
TIP, KI GA VRA�A FUNKCIJA main( )
V izvirni K&R definiciji C-ja, so vse funkcije standarno vra�ale tip int, �e avtor ni zahteval �esa drugega. Ker je bilo ekspicitno definiranje vra�ajocega tipa izbirno, je bila ve�ina C-ja napisanega na ta na�in:
main() { ... }Ko pa so bili v jezik dodani prototipi (katere bomo obdelali kmalu), pa so nekateri programerji smatrali, da main() funkcija ne vra�a ni�esar, zato so za tip vra�anih vrednosti uporabili tip void, zato je kmalu postala obi�ajna praksa pisati main() funkcijo na naslednji na�in:
void main() { ... }Ko je bil ANSI-C standard kon�an, je bil edini dovoljeni tip vra�anih vrednosti tip int. Dober prevajalnik bo preveril, �e program v resnici vra�a vrednost tako, da bo zahteval, da se iz vsake izstopne to�ke vra�a vrednost tipa int. To je vodilo do naslednje oblike funkcije main():
int main() { ... return 0; }O�itno zaradi vztrajnosti uporabe tipa void, je veliko piscev prevajalnikov vklju�ilo void kot tip vra�anih vrednosti kot raz�iritev, da bi lahko uporabljali kode brez sprememb. Nekateri prevajalniki zato podpirajo tip void, vendar pa je tip int edini odobren s strani ANSI-C standarda.
Da bi svojo kodo naredili kar se da prenosljivo, uporabljajte kodo, zadnjo omenjeno zgoraj.
Kon�no lahko vidite, zakaj smo v programe dodajali vrstico, ki vra�a
vrednost ni� operacijskemu sistemu. To je namre� znak operacijskemu sistemu,
da se je program izvr�il normalno.
OBMO�JE VELJAVNOSTI SPREMENLJIVK
Primer programa ------> SCOPE.C
Nalo�ite naslednji program, SCOPE.C, in si ga oglejte za razlago obmo�ja
veljavnosti spremenljivke v programu. Vrstice od 2 do 5 lahko zenkrat zanemarite,
saj jih bomo obdelali pozneje. Za ta program bomo porabili kar nekaj �asa
in pokrili veliko novih tem. Mnoge od njih se vam ne bodo zdele uporabne,
vendar jih sku�ajte razumeti, saj so zelo pomembne.
KAJ JE GLOBALNA SPREMENLJIVKA?
Spremenljivka, definirana v vrstici 7, je globalna spremenljivka, imenovana count in je dostopna katerikoli funkciji, saj je definirana pred vsemi funkcijami. Vedno je dostopna zato, ker obstaja celoten izvajalni �as programa. (To bo razlo�eno v kratkem.) Ni�je v programu je v vrstici 29 definirana �e ena globalna spermenljivka counter, ki je prav tako globalna, ni pa dostopna main() funkciji, saj je deklarirana za njo. Globalna spremenljivka je vsaka spremenljivka, ki je deklarirana izven katerekoli funkcije. V�asih se te spremenljivke omenja tudi kot zunanje spremenljivke, saj so zunanje vsem funkcijam, v�asih pa jim pravijo tudi datote�ne spremenljivke.
Globalnim spremenljivkam se avtomatsko dodeli vrednost ni� ob deklaraciji. Zato bosta spremenljivki count in counter obe inicializira na vrednost ni�.
Vrnite se na main() funkcijo in videli boste spremenljivko index
definirano kot tip int. Za trenutek pozabite besedo register.
Spremenljivka je dosegljiva le v main() funkciji, kjer je deklarirana.
Dodatno, je tudi avtomatska spremenljivka, kar pomeni, da za�ne obstajati,
ko se izvr�uje funkcija, v kateri je definirana, in preneha obstajati,
ko je izvajanje funkcije kon�ano. To v tem konkretnem primeru ne pomeni
ni�esar, saj je funkcija main() vedno aktivna, tudi ko prepusti
programsko kontrolo drugi funkciji. V zavitem oklepaju, ki ozna�uje for
zanko, je definirana �e ena celo�tevilska spremenljivka stuff. Vsak
pa zavitih oklepajev lahko vsebuje deklaracije spremenljivk, ki bodo dostopne
le takrat, ko bo program izvr�eval stavke, ki se nahajajo med tema dvema
zavitima oklepajema. Te spremenljivke bodo avtomati�ne in bodo prenehale
obstajati, ko se prenehajo izvajati stavki v zavitem oklepaju. Spremenljivka
stuff se bo torej kreirala in uni�ila osemkrat, enkrat ob vsakem prehodu
skozi zanko.
VE� O AVTOMATSKIH SPREMENLJIVKAH
Oglejte si funkcijo head1() v vrstici 30, ki izgleda nekoliko �udno, saj je beseda void uporabljena dvakrat. Smisel uporabe te besede bo razlo�en kasneje. Funkcija vsebuje spremenljivko index, ki z spremenljivko index iz main() funkcije nima ni�esar skupnega, razen tega, da sta obe avtomtski spremenljivki. Ko program ne izvaja stavkov te funkcije, spremenljivka index sploh ne obstaja. Ko pokli�emo funkcijo head1(), se spremenljivka generira, ko pa funkcija izvede vse svoje stavke, pa spremenljivka index iz funkcije head1() preneha obstajati. (Avtomatske spremenljivke se shranijo na sklad, kar bomo obdelali kasneje.) Zapomnite pa si, da to nima nobenega u�inka na spremenljivko index v funkciji main(), saj je ta �isto druga zadeva.
Avtomatske spremenljivke so torej avtomati�no kreirane, ko jih potrebujemo,
nato pa so tudi avtomatsko uni�ene. Pomembna stvar, ki si jo je treba zapomniti
je ta, da moramo po nekem klicu funkcije, ko jo kli�emo �e enkrat, ponovno
inicializirati avtomatske spremenljivke, saj se njihove vrednosti ne ohranijo.
KAJ SO STATI�NE SPREMENLJIVKE?
Sedaj moramo omeniti �e en tip spremenljivk, stati�ne spremenljivke. S tem, ko pred deklaracijo spremenljivke v funkciji postavimo rezervirano besedo static, postane ta spremenljivka oziroma te spremenljivke stati�ne, kar pomeni, da bodo obstajale od enega klica do drugega. Stati�na spremenljivka je inicializirana enkrat, ob nalo�itvi programa, in se med inicializacijo programa nikoli ne reinicializira.
�e pa rezervirano besedo static postavimo pred zunanjo spremenljivko,
to je tisto, ki nastopa izven vseh funkcij, jo naredimo privatno in je
ni mo�no uporabljati v drugih datotekah. (To je popolnoma druga�na uporaba
enake rezervirane besede.) To nakazuje, da je mo�no zunanje spremenljivke
uporabljati v drugih, posebej prevedenih datotekah, kar je res mo�no. Primeri
take uporabe bodo podani v poglavju 14. Ne bodo pa prikazani tukaj.
PONOVNA UPORABA ISTEGA IMENA
Preidite na funkcijo head2(). Vsebuje drugo definicijo spremenljivke
count. �eprav je bil count �e definiran kot globalna spremenljivka v vrstici
7, ni ni�esar narobe z uporabo enakega imena spremenljivke v tej funkciji.
To je popolnoma nova spremenljivka, ki nima nobene zveze s tisto globalno,
povzro�i pa, pa globalna spremenljivka count ni dosegljiva v tej funkciji.
To omogo�a pisanje programov, kjer pri pisanju funkcij ni potrebno
skrbeti, �e je ime �e bilo uporabljeno za kak�no od globalnih spremenljivk,
saj ne more priti do imenskega konflikta. Morate le poskrbeti za spremenljivke,
ki potem s to funkcijo komunicirajo.
KAJ JE REGISTRSKA SPREMENLJIVKA?
Da izpolnimo prej dano obljubo, bomo sedaj definirali register
tip spremenljivke. Ra�unalnik lahko podatke hrani v registrih ali pa v
pomnilniku. Registri so veliko hitrej�i, vendar pa je le nekaj registrov
na voljo programerju. �e v programu nastopajo spremenljivke, ki se
zelo intenzivno uporabljajo, lahko ra�unalniku naro�ite, da bo te spremenljivke
shranil v registre in tako nekoliko pospe�ite delovanje programa. Kako
to storite, je prikazano v vrstici 11. Va� prevajalnik vam verjetno omogo�a
deklaracijo ene ali ve� registrskih spremenljivk, �e pa jih zahtevate ve�,
pa bo nadaljne zahteve ignoriral. V dokumentaciji za prevajalnik
bi moralo pisati, koliko registrskih spremenljivk omogo�a. Prav tako bi
moralo pisati, katere tipe spremenljivk lahko shranite v register. �e pa
prevajalnik ne omogo�a uporabe registrskih spremenljivk, se bo zahteva
po hranjenju v registru preprosto ignorirala.
KAJ JE UPORABA PROTOTIPOV?
Prototip je nek model resni�ne stvari in ko programirate v C-ju, imate mo�nost definirati model vsake funkcije za va� prevajalnik. Le-ta lahko uporabi modele, da preveri vse klice funkcij in tako ugotovi, �e ste uporabili pravilno �tevilo argumentov v klicu funkcije in �e so ti pravilnega tipa. Z uporabo prototipov, dose�ete, da prevajalnik nekoliko bolj preverja, �e so v programu kak�ne napake. ANSI-C standard vsebuje prototipe kot del priporo�ljivega standarda. Vsak ANSI-C prevajalnik ima mo�nost uporabe prototipov, zato bi bilo dobro, da bi se jih nau�ili uporabljati. Veliko ve� o prototipih bomo spoznali kasneje.
�e se vrnem na vrstice 3,4 in 5 v SCOPE.C, najdemo prototipe za vse tri funkcije, ki jih program vsebuje. Prvi void v vsaki vrstici sporo�a prevajalniku, da te funkcije ne vra�ajo nobenih vrednosti, tako, da bi prevajalnik stavek index = head1(); ozna�il kot napako, saj funkcija ne vra�a ni�esar, kar bi lahko priredili spremenljivki index. Beseda void v oklepaju pove prevajalniku, da ta funkcija ne potrebuje nobenih parametrov in, �e bi bila tu zapisana spremenljivka, bi bila to napaka, prevajalnik pa bi javil opozorilo. �e bi torej napisali stavek head1(index); bi to bila napaka. To vam omogo�a, da izvajate preverjanje tipov podobno kot pri programiranju v Pascalu, Moduli-2 ali Adi, �eprav je preverjanje tipov v C-ju relativno �ibko.
�e zdaj bi morali za�eti uporabljati prototipe za preverjanje za vse funkcije, ki jih definirate. Va� prevajalnik ima morda tudi mo�nost, ki bo zahtevala prototip za vsako funkcijo. Preglejte va�o dokumentacijo, kako to storite. Uporaba prototipov bo uporabljena skozi celoten te�aj. �e prevajalnik ne podpira prototipov in moderne metode definiranja funkcij, boste morali spremeniti preostale primere. Veliko bolj�a re�itev pa bi bila nabava novega prevajalnika. .
Vrstica 2 programa SCOPE.C pove sistemu, da naj gre v standardni direktorij,
kjer so shranjene vklju�itvene datoteke in vzame kopijo datoteke stdio.h,
ki vsebuje prototipe za standardne vhodne in izhodne funkcije, da jih boste
lahko preverili, �e vsebujejo pravilne tipe spremenljivk. Ne skrbite �e
preve� glede include stavka, razlo�en bo pozneje. Zagotovo prevedite
in po�enite ta program. .
STANDARDNE FUNKCIJSKE KNJI�NICE
Vsak prevajalnik dobite skupaj z nekaj standardnimi, �e definiranimi
funkcijami, ki so pripravljene za uporabo. To so ve�inoma vhodno/izhodne
funkcije, funkcije za znakovno manipulacijo ter manipulacijo z nizi, in
pa matematicne funkcije. Veliko od teh funkcij si bomo ogledali v poznej�ih
poglavjih. Prototipi so �e definirani s strani avtorja prevajalnika za
vse funkcije, ki ste jih dobili poleg prevajalnika. Ve�ina prevajalnikov
ima �e definirane �e neke dodatne funkcije, ki omogo�ajo programerju, da
dobi od svojega ra�unalnika, kar je najve� mogo�e. V primeru IBM-PC in
kompatibilnih ra�unalnikov so to funkcije, ki omogo�ajo uporabo BIOS-ovih
servisov ali pisanje direktno na zaslon monitorja ali pa na katerokoli
mesto v pomnilniku. Te funkcije tu ne bodo podrobneje predelane, saj boste
te edinstvene lastnosti lahko obdelali sami. Nekateri primeri teh funkcij
pa so uporabljeni v primerih v poglavju 14.
KAJ JE REKURZIJA?
Primer programa ------> RECURSON.C
Rekurzija je �e ena izmed tistih programskih tehnik, ki se vam na za�etku zdijo zelo nerazumljive na prvi pogled, �e pa si ogledate program RECURSON.C, pa bomo to tehniko podrobno spoznali. To je verjetno najbolj enostaven rekurzijski program, kar se jih da napisati, in je v resni�ni praksi neuporaben program, za namen prikaza pa je odli�en.
Rekurzija ni ni� drugega kot funkcija, ki kli�e samo sebe. Zato je v zanki, ki mora imeti nek na�in, kako naj se kon�a. V program, ki ga trenutno gledate, v vrstici9 spremenljivki index priredimo vrednost 8, in jo uporabimo kot argument funkcije count_dn(). Funkcija enostavno dekrementira spremenljivko, jo izpi�e skupaj z nekim sporo�ilom, in �e je spremenljivka ve�je od ni�, pokli�e samo sebe, zopet dekrementira spremenljivko, jo izpi�e itd. Nazadnje bo spremenljivka dosegla vrednost ni� in funkcija bo prenehala s klicanjem same sebe. Namesto tega se bo vrnila na prej�nji klic, nato �e na prej�njega, dokler nas ne bo nazadnje vrnila v main() funkcijo in od tam v operacijski sistem.
Za namen razumevanja si lahko mislite, da imate na voljo osem kopij
funkcije count_dn() in kli�ete vsako posebej tako, da vodite evidenco,
katera je trenutno na vrsti. To ni �isto enako temu, kar se je v resnici
zgodilo, je pa precej dobra ilustracija, da bi razumeli, kar se je zgodilo.
KAJ JE REKURZIJA NAREDILA?
Vseeno je potrebna bolj�a razlaga, kaj se je zgodilo. Ko ste poklicali funkcijo iz sebe, je vse spremenljivke in vse notranje zaznamke, ki jih potrebuje, shranila nekam v nek sklop. Ko je naslednji� poklicala samo sebe, je storila isto, shranila naslednji sklop vsega, kar potrebuje, da konca klic funkcije. Nadaljevala je z kreiranjem in shranjevanjem teh sklopov, dokler ni dosegla zadnjega klica, ko je zacela te sklope dobivati nazaj in jih uporabljati za kompletiranje vseh funkcijskih klicev. Sklopi so se shranili v notranji del ra�unalnika, ki se imenuje sklad. To je del pomnilnika skrbno organiziranega za hranjenje tako opisanih podatkov. Izven dosega tega programa je podrobno opisovanje sklada, bilo pa bi v dobro va�ih programerskih izku�enj, da si preberete nekaj �tiva o skladu. Sklad se v skoraj vseh modernih racunalnikih uporablja za notranja "gospodinjska" dela.
Pri uporabi rekurzije, boste morda �eleli napisati program, ki uporablja posredno rekurzijo, ki je nasprotje neposredne rekurzije uporabljene tukaj. Pri posredni rekurziji bi funkcija A poklicala funkcijo B, ki bi spet poklicala funkcijo A,itd. To je popolnoma legalno, sistem bo poskrbel, da po postavil potrebne stvari na sklad in jih z njega spet jemal, ko bodo potrebne. Ni razloga, da ne bi imeli tri funkcije, ki bi druga drugo klicala v krogu, ali tri ali �tiri. C-jevski prevajalnik bo namesto vas poskrbel za vse podrobnosti. .
Stvar, ki si jo morate pri rekurziji zapomniti, da mora nekaj v nekem
trenutku postati ni�, ali dose�i neko prej definirano to�ko, kjer se bo
zanka kon�ala. �e tega ne boste storili, boste dobili neskon�no zanko,
sklad se bo napolnil, povzro�il napako in ustavil program nekoliko burno.
�E EN PRIMER REKURZIJE
Primer programa ------> BACKWARD.C
Program BACKWARD.C vsebuje �e en primer rekurzije, zato ga na�ite in si ga oglejte. Program je podoben zadnjemu, le da uporablja znakovno polje. Vsak zaporedni klic funkcije forward_and_backwards() povzro�i izpis enega znaka. Prav tako se po en znak izpisuje vsaki�, ko se funkcija kon�a, tokrat v obratnem vrstnem redu, ko sledimo nizu rekurzivne funkcije.
Ta program uporablja moderno metodo definiranja funkcij in vklju�uje vse definicije prototipov. Moderna metoda definiranja funkcij premakne tipe spremenljivk v oklepaj skupaj z samim imenom spremenljivke. Kon�ni rezultat je, da izgleda taka vrstica podobno kot ustrezne vrstica v jezikih, ki imajo mo�nej�e preverjanje tipov kot so Pascal, Modula-2, ali Ada. Prototip v vrstici 5 je enostavno kopija glave funkcije v vrstici 20, sledi pa mu �e podpi�je. Razvijalci C-ja so celo omogo�ili, da v oklepaj prototipa postavite ime spremenljivke, ki ga prevajalnik sicer ignorira, vendar pa iz takega zapisa vidite, kako spremenljivka deluje, ter ima tako vlogo komentarja.
Ne obremenjujte se z znakovnim poljem ali drugim novim gradivom predstavljenim tukaj. Ko boste predelali sedmo poglavje, vam bo ta program popolnoma jasen. Bilo je namrec va�no, da se prika�e �e en primer rekurzije, zato je ta primer vklju�en tu. Opazili boste, da program naredi nekaj uporabnega z rekurzijo, vendar pa bi program z lahkoto napisal brez rekurzije. Pozneje si bomo ogledali nekaj programov, kjer je rekurzija nujno potrebna.
Prevedite in po�enite ta program in opazujte rezultate.
PROGRAM KVADRIRANJA �TEVIL S PLAVAJO�O VEJICO S PROTOTIPI
Primer programa------> FLOATSQ2.C
Nalo�ite in si oglejte program FLOATSQ2.C, ki je natan�na kopija programa FLOATSQ.C, ki smo si ogledali prej, le da ima dodane prototipe. Uporaba prototipov je zadeva, ki je priporo�ljiva za u�enje vsem C-jevskim programerjem.
Nekaj stvari je pri tem programu treba poudariti. Prvi�, besede float na za�etku vrstic 32 in 41 so znak prevajalniku, da so to funkcije, ki vra�ajo vrednosti tipa float. Prav tako, ker so prototipi funkcij zapisani pred main( ) funkcijo, jih v vrstici 12 ni potrebno definirati, kot smo to storili v vrstici 9 v programu FLOATSQ.C, na za�etku tega poglavja. Bodite pozorni, da je tudi tip spremenljivke inval zapisan v oklepaju v vrsticah 4 in 32.
Ko boste prevedli in pognali ta program, zanemarjujo� vsa opozorila,
zbri�ite parameter iz vrstice 17 in poglejte kak�no sporo�ilo napake boste
dobili.
NEJASEN PROBLEM, KI SE V�ASIH POJAVI
Recimo, da bi v program FLOATSQ.C zapisali naslednjo vrstico kode;,
printf(" ... ", sqr(5.0), glsqr());Morda je presenetljivo, vendar pa je vrstni red klicanja funkcij, kar se ti�e ANSI-C standarda, nedefiniran. Nek prevajalnik bo morda najprej poklical sqr() funkcijo, drugi pa funkcijo glsqr(), obe metodi sta namre� pravilni. V tem primeru ni pomembno, katera se pokli�e najprej, v nekaterih primerih pa to je pomembno, recimo, da bi nekaj �eleli izpisati iz obeh funkcij. Rezultat vsakega klica bo uporabljen na pravi lokaciji, vrstni red izvajanja pa je nedefiniran. Bodite prepri�ani, da se bo to vpra�anje prej ali slej pojavilo tudi v va�em programiranju, zato se ga morate zavedati.
�E VEC STILSKIH PREDLOGOV
Primer programa ------> STYLE2.C
Primer imenovan STYLE2.C je podan kot ilustracija razli�nih na�inov
formatiranja funkcije. Opazili boste razli�ne nacine definiranja vhodnega
parametra. Primera tri in �tiri oba uporabljata enak stil, vendar �etrti
primer prikazuje stil, ko funkciji ni�esar ne podajamo, niti nam ni�esar
ne vra�a. Slog pisanja zelo jasno nakazuje, da funkcija ni�esar ne potrebuje
in ni�esar ne vra�a, zato tega ne moremo razlagati kot to, da smo nekaj
izpustili. Porabite nekaj �asa, da preu�ite te primere, nato pa za�nite
razvijati slog, ki ga boste uporabljali. �e ste kot ve�ina programerjev,
boste razvili slog, ki ga nameravate uporabljati vse svoje �ivljenje, nato
pa ga boste zamenjali vsakih nekaj mesecev ali pa ob vsakem novem
projektu.