![]() ![]() ![]() | Funktioner |
Vi ser i dette kapitel på procedurer og funktioner generelt, og på funktionsbegrebet i C som dækker begge af disse.
12.1. Procedurer og funktioner
Indhold Op Forrige Næste Slide Aggregerede slides Stikord Programindeks Opgaveindeks
Her følger kort vore definitioner af en procedure og en funktion:
|
Indkapsling er et helt basalt element i både procedurer og funktioner.
Et antal kommandoer sammensættes (aggregeres) i en procedure, og disse kan efterfølgende benyttes som én kommando i et procedurekald. Sammensætningen sker via en blok, som vi så på i kapitel 7.
I en funktion indkapsles ét udtryk, og indkapslingen spiller selv rollen som et udtryk, i et funktionskald.
|
Så vi ser at et procedurekald er en kommando. Som sådan forvents kaldet af en procedure at ændre det kørende programs tilstand. Vi ser også at et funktionskald er et udtryk. Som sådan forventes et funktionskald ikke at ændre på programmets tilstand. Derimod vil et funktionskald give en værdi, som efterfølgende kan bruges på mange forskellige måder (skrive det ud, overføre det til en funktion, overføre det til en procedure, etc.)
Genbrugelighed og generalitet fremmes ved brug af parametre i funktioner. Vi ser konkrete eksempler på dette i afsnit 12.4 og de efterfølgende afsnit. Selve parametermekanismen diskuteres i afsnit 12.7.
12.2. Funktionsdefinitioner i C
Indhold Op Forrige Næste Slide Aggregerede slides Stikord Programindeks Opgaveindeks
Både procedurer og funktioner, som defineret i afsnit 12.1 kaldes funktioner i C.
C skelner ikke skarpt mellem procedurer og funktioner I C kaldes begge abstraktionsformer funktioner |
Her følger den essentielle syntaks for en funktion i C:
| |||
|
De formelle parametre er de parametre, som findes i selve funktionsdefinitionen. Når vi senere kalder funktionen angives aktuelle parametre, som erstatter de formelle parametre på en måde, som vi vil se nærmere på i forbindelse med eksemplerne i afsnit 12.4 - afsnit 12.7.
|
Mange C funktioner er reelt procedurer, som returnerer en eller anden værdi. Den returnerede værdi anvendes ofte til at signalere, om de indkapslede kommandoer 'gik godt' eller 'gik skidt'. I denne sammenhæng betyder returværdien 0 ofte, at alt er OK, medens en ikke-nulværdi som resultat er tegn på en eller anden fejl.
12.3. Funktionskald i C
Indhold Op Forrige Næste Slide Aggregerede slides Stikord Programindeks Opgaveindeks
Når man kalder en funktion aktiveres kommandoerne i kroppen af funktionen på det vi kalder de aktuelle parametre. Et kald af funktionen står altså for de indkapslede kommandoer, hvor de aktuelle parametres værdier erstatter de formelle parametre. Dette kalder vi parameteroverførsel, og vi beskrive dette nærmere i afsnit 12.7.
| |||
|
|
12.4. Eksempel: Temperaturomregninger
Indhold Op Forrige Næste Slide Aggregerede slides Stikord Programindeks Opgaveindeks
Vi ser først på et eksempel på en ægte funktion. Hermed mener vi altså en funktion i den forstand vi definerede i afsnit 12.1, og som modsvarer det matematiske funktionsbegreb.
Funktionen fahrenheit_temperature tager som input en celcius temperatur, f.eks. 100 grader (kogepunktet ved normale forhold). Med dette output returnerer funktionen den tilsvarende Fahrenheit temperatur, 212 grader. Dette er den normale temperaturangivelse i Amerikanske lande, f.eks. USA.
Der udføres ingen kommandoer i C funktionen fahrenheit_temperature. Funktionen dækker med andre ord blot over en formel. Vi kalder ofte en formel for et udtryk, jf. afsnit 2.1.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | #include <stdio.h> double fahrenheit_temperature(double celcius_temp){ return (9.0 / 5.0) * celcius_temp + 32.0; } int main(void){ printf("Freezing point: %6.2lf F.\n", fahrenheit_temperature(0.0)); printf("Boiling point: %6.2lf F.\n", fahrenheit_temperature(100.0)); return 0; } | |||
|
I programmet ser vi øverst, med fed sort skrift definitionen af fahrenheit_temperature. Bemærk udtrykket (9.0 / 5.0) * celcius_temp + 32.0 , hvis værdi returneres fra funktionen med return. Bemærk også anvendelsen af navnet celcius_temp; Dette er den formelle parameter af funktionen.
I main ser vi to kald af fahrenheit_temperature. Dette er de røde og blå dele af program 12.1. Bemærk at disse dele er udtryk, og at de forekommer som parametre til printf.
Herunder, i figur 12.1 illustrerer vi det røde og blå kald af fahrenheit_temperature i program 12.1.
Kontrollen i main forløber som følger (følg pilene):
Figur 12.1 To kald af fahrenheit_temperature funktionen |
Herunder, i program 12.2 viser vi et eksempel på brug af den omvendte funktion, som konverterer fahrenheit grader til celcius grader. Konkret programmerer vi en nyttig temperatur konverteringstabel. De første linier i udskriften er vist i program 12.3.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | #include <stdio.h> double celcius_temperature(double fahrenheit_temp){ return (5.0 / 9.0) * (fahrenheit_temp - 32.0); } int main(void){ double f; printf("%-20s %-20s\n", "Fahrenheit degrees", "Celcius degrees"); for (f = 1.0; f <= 100.0; f++) printf("%-20.2lf %-20.2lf\n", f, celcius_temperature(f)); return 0; } | |||
|
Bemærk kontrolstrengen i printf i program 12.2, såsom %-20.2lf. lf benyttes idet vi udskriver en double. 20.2 angiver antallet af cifre og antallet af cifre efter decimal point. Endelig angiver tegnet - and vi ønsker venstrestilling af output i feltet.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | 1.00 -17.22 2.00 -16.67 3.00 -16.11 4.00 -15.56 5.00 -15.00 6.00 -14.44 7.00 -13.89 8.00 -13.33 9.00 -12.78 10.00 -12.22 11.00 -11.67 12.00 -11.11 13.00 -10.56 14.00 -10.00 15.00 -9.44 16.00 -8.89 17.00 -8.33 18.00 -7.78 19.00 -7.22 20.00 -6.67 21.00 -6.11 22.00 -5.56 23.00 -5.00 24.00 -4.44 25.00 -3.89 26.00 -3.33 27.00 -2.78 28.00 -2.22 29.00 -1.67 30.00 -1.11 31.00 -0.56 32.00 0.00 33.00 0.56 ... ... | |||
|
12.5. Eksempel: Antal dage i en måned
Indhold Op Forrige Næste Slide Aggregerede slides Stikord Programindeks Opgaveindeks
Eksemplet i dette afsnit er en fortsættelse af eksemplet fra program 8.4. Bidraget i dette afsnit er en pæn indpakning af de relevante programdele i en funktion, og en lettere omskrivning, som går på at vi nu tager udgangspunkt i et månedsnummer og et årstal.
Bemærk lige kontrasten mellem program 8.4 og program 12.4. I det første program var vi i stand til at beregne antallet af dage i en måned som en del af main. I det sidste program har vi en veldefineret byggeklods, funktionen daysInMonth, som kan bruges så ofte vi vil. Dette er en meget mere modulær løsning. En løsning der på alle måder er mere tilfredsstillende.
Vi introducerer en funktion i programmet der beregner antal dage i en måned Vi bruger eksemplet til at diskutere overførsel af parametre til funktioner |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | #include <stdio.h> #include <stdlib.h> int daysInMonth(int mth, int yr); int isLeapYear(int yr); int main(void) { int mth, yr; do{ printf("Enter a month - a number between 1 and 12: "); scanf("%d", &mth); printf("Enter a year: "); scanf("%d", &yr); printf("There are %d days in month %d in year %d\n", daysInMonth(mth, yr), mth, yr); } while (yr != 0); return 0; } int daysInMonth(int month, int year){ int numberOfDays; switch(month){ case 1: case 3: case 5: case 7: case 8: case 10: case 12: numberOfDays = 31; break; case 4: case 6: case 9: case 11: numberOfDays = 30; break; case 2: if (isLeapYear(year)) numberOfDays = 29; else numberOfDays = 28; break; default: exit(-1); break; } return numberOfDays; } int isLeapYear(int year){ int res; if (year % 400 == 0) res = 1; else if (year % 100 == 0) res = 0; else if (year % 4 == 0) res = 1; else res = 0; return res; } | |||
|
I program 12.4 bemærker vi først, at vi har prototyper af funktionerne daysInMonth og isLeapYear (fremhævet med fed sort skrift). Dernæst følger main, som kalder daysInMonth (den blå del). Endelig følger definitionen af daysInMonth med rød skrift. Som input tager funktionen parametrene month og year, og som output returneres antallet af dage i den ønskede måned. Læg mærke til denne meget veldefinerede grænseflade mellem funktionen daysInMonth og dets omverden.
Vi har øget genbrugeligheden - og dermed værdien af vort program Vi ønsker som regel at undgå brug af scanf og printf i genbrugelige procedurer og funktioner |
Lad mig udddybe ønsket om at undgå brug af scanf og printf i genbrugelige procedurer og funktioner. Hvis vi foretager indlæsning af data og/eller udskrivning af resultater i vore genbrugelige procedurer og funktioner binder vi procedurerne og funktionerne til bestemt brugsmønstre og brugssammenhænge. Som et eksempel vil det fremgå om vi fører dialogen med brugeren på engelsk eller dansk. Det er derfor bedst at isolere input og output til bestemte dele af programmet, f.eks. til main eller til et lag af funktioner omkring main. Resten af programmet bør skrives uden brug af input og output procedurer.
12.6. Eksempel: GCD
Indhold Op Forrige Næste Slide Aggregerede slides Stikord Programindeks Opgaveindeks
Vi vender tilbage til et andet eksempel fra kapitel 9, nemlig Euclids algoritme, som vi oprindelig mødte i program 9.1. Vi husker at Euclids algoritme finder den største fælles divisor af to tal. Altså det største tal, som både går op i det ene og det andet tal.
Mønstret fra dage-i-måned eksemplet, program 12.4, genfindes klart i program 12.5. Læg mærke til funktionen gcd's grænseflader. På inputsiden er der helt naturligt to heltal, hvoraf vi ønsker at finde den største fælles divisor. På outputsiden resultatet, altså den største fælles divisor.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | #include <stdio.h> int gcd(int, int); int main(void) { int i, j, small, large; printf("Enter two positive integers: "); scanf("%d %d", &i, &j); small = i <= j ? i : j; large = i <= j ? j : i; printf("GCD of %d and %d is %d\n\n", i, j, gcd(large, small)); return 0; } int gcd(int large, int small){ int remainder; while (small > 0){ remainder = large % small; large = small; small = remainder; } return large; } | |||
|
12.7. Parametre til C funktioner
Indhold Op Forrige Næste Slide Aggregerede slides Stikord Programindeks Opgaveindeks
Som afslutning på dette afsnit ser vi lidt mere systematisk på parametre til funktioner i C.
Vi har mødt eksempler på parametre i både program 12.1, program 12.4 og program 12.5. I dette afsnit ser vi på den faktiske mekanisme til parameteroverførsel i C. Dette er de såkaldte værdiparametre, som på engelsk ofte betegnes som "call by value".
Parametre til en funktion bruges til at gøre funktionen mere generelt anvendelig |
|
|