Funktioner Istllet fr att frska lsa ett stort

  • Slides: 52
Download presentation
Funktioner • Istället för att försöka lösa ett stort problem på en gång, kan

Funktioner • Istället för att försöka lösa ett stort problem på en gång, kan man dela upp det i mindre delproblem. • ”top-down” metod för att lösa problemen – Försök dela upp programmet i mindre och mindre delproblem. • När delproblemen är enkla nog, använd funktioner för att lösa delproblemen (och därmed hela problemet). • Program är ofta uppdelade på flera källkodsfiler där varje fil kan innehålla noll eller flera funktioner. • En funktion måste dock alltid finnas (main()) Datavetenskap för teknisk kemi 10 p, moment 1 1

Funktionsdefinition • C-källkoden, som beskriver vad en funktion gör, kallas funktionsdefinition. Den ska inte

Funktionsdefinition • C-källkoden, som beskriver vad en funktion gör, kallas funktionsdefinition. Den ska inte misstas för funktionsdeklarationen (också kallad funktionsprototyp). • Funktionsdefinition ser ut så här i den generella formen type functionname( parameter list ) { declarations statements } • Allting innan första krullparentesen kallas för funktionshuvud. • Allting mellan krullparenteserna kallas för funktionskropp. • Parameterlistan är en komma-separerad lista med deklarationer. Datavetenskap för teknisk kemi 10 p, moment 1 2

Exempel 1 int factorial (int n) { int i, product = 1; for (i

Exempel 1 int factorial (int n) { int i, product = 1; for (i = 2; i <= n; ++i) product *= i; return product; } • Den första int säger att värdet som funktionen returnerar kommer att konverteras (om det behövs) till int. • Parameterlistan består av deklarationen int n. Detta säger åt kompilatorn att funktionen tar ett argument av typen int. • Ett uttryck som factorial(7) gör att funktionen anropas med argumentet 7. Den lokala variabeln n sätts till värdet 7 innan funktionen börjar. Datavetenskap för teknisk kemi 10 p, moment 1 3

Exempel 2 void wrt_adress(void) { printf(”%sn%snn”, ” ***********”, ” ** SANTA CLAUS **”, ”

Exempel 2 void wrt_adress(void) { printf(”%sn%snn”, ” ***********”, ” ** SANTA CLAUS **”, ” ** NORTH POLE **”, ” ***********”); } • Denna funktion returnerar ingenting (void). Den tar inte heller några parametrar. Den anropas med uttrycket wrt_adress(). För att anropa den tre ggr: for (i = 0; i < 3; i++) wrt_adress(); Datavetenskap för teknisk kemi 10 p, moment 1 4

Exempel 3 void nothing(void) { } /* does nothing */ double twice(double x) {

Exempel 3 void nothing(void) { } /* does nothing */ double twice(double x) { return (2. 0 * x); } int all_add(int a, int b) { int c; . . . return (a + b + c); } Datavetenskap för teknisk kemi 10 p, moment 1 5

Variabler • Variabler i en funktion är lokala för den funktionen. Ändringar av de

Variabler • Variabler i en funktion är lokala för den funktionen. Ändringar av de variablerna kommer inte att påverka andra variabler utanför funktionen som har samma namn. • En variabel kan också deklareras utanför en funktionskropp och blir då global. Normalt är globala variabler inte att rekommendera. #include <stdio. h> int a = 33; int main(void) { int b = 77; printf(”%dn”, a + b); } Datavetenskap för teknisk kemi 10 p, moment 1 6

return • return satsen kan ha ett uttryck eller vara utan. return_statement : :

return • return satsen kan ha ett uttryck eller vara utan. return_statement : : = return; | return expression; return ++a; return (a * b); • Uttrycket som returneras kan omges av parenteser, men detta krävs ej. • När en return sats påträffas så avbryts exekveringen (körningen) av funktionen och kontrollen ges åter till den anropande miljön. Om return satsen innehåller ett uttryck, så skickas värdet av uttrycket (efter eventuell konvertering) tillbaks till den anropande miljön. Datavetenskap för teknisk kemi 10 p, moment 1 7

Funktionsprototyper • En funktion bör deklareras innan den används. ANSI C tillhandahåller en deklarationssyntax

Funktionsprototyper • En funktion bör deklareras innan den används. ANSI C tillhandahåller en deklarationssyntax som kallas funktionsprototyp. • En funktionsprototyp berättar för kompilatorn antalet argument och av vilken typ argumenten är. Den berättar dessutom vilken typ av värde (om något) som funktionen returnerar. double sqrt(double); • Detta berättar för kompilatorn att sqrt() är en funktion som tar ett enda argument av typen double och returnerar double. Datavetenskap för teknisk kemi 10 p, moment 1 8

Exempel void f(char c, int i); är samma sak som void f(char, int); •

Exempel void f(char c, int i); är samma sak som void f(char, int); • Identifierarna c och i används inte av kompilatorn. Deras enda syfte är att ge dokumentation till programmeraren. • Funktionsprototyper låter kompilatorn kontrollera källkoden bättre och lättare hitta fel. Dessutom kommer värden till funktioner att bli korrekt omvandlade. • T. ex. om funktionen sqrt() har definerats, så kommer ett anrop sqrt(4) att fungera. Kompilatorn kommer att omvandla 4 till 4. 0 (double) Datavetenskap för teknisk kemi 10 p, moment 1 9

Funktionsdeklarationer • Om ett funktionsanrop f(x) påträffas innan någon deklaration eller prototyp gjorts, så

Funktionsdeklarationer • Om ett funktionsanrop f(x) påträffas innan någon deklaration eller prototyp gjorts, så förutsätter kompilatorn en standard deklaration av formen int f(); • Inget förutsätts om parameterlistan till funktionen. • Funktionsdefinitioner och prototyper har vissa begränsningar. Lagringsklassen kan vara endera extern eller static men inte båda. • Om inget anges, så är lagringsklassen extern • Typerna ”array of. . . ” och ”function returning. . . ” kan ej returneras av en funktion. Däremot kan en pekare till en array eller en funktion returneras. Datavetenskap för teknisk kemi 10 p, moment 1 10

Alternativ funktionsdefinition • Antag att vi vill skriva ett stort program i en enda

Alternativ funktionsdefinition • Antag att vi vill skriva ett stort program i en enda källkodsfil. Normalt så lägger vi en #include i början av filen där vi har våra funktionsprototyper. • Ett alternativt sätt att lägga funktionsdeklarationerna överst i filen innan funktionen anropas. main()-funktionen läggs sist av alla. • Detta fungerar eftersom att en funktionsdeklaration också fungerar som en funktionsprototyp. • Det är att föredra att använda det traditionella sättet med funktionsprototyper, main() först och sedan funktionsdeklarationer. Datavetenskap för teknisk kemi 10 p, moment 1 11

Exempel #include <stdio. h> #define N 7 void prn_heading(void) {. . } void power(int

Exempel #include <stdio. h> #define N 7 void prn_heading(void) {. . } void power(int m, int n) {. . } int main(void) { prn_heading(); printf(”%dn”, power(7, 3)); } Datavetenskap för teknisk kemi 10 p, moment 1 12

Funktionsanrop • Programmet börjar alltid med ett anrop till main(). När en funktion anropas,

Funktionsanrop • Programmet börjar alltid med ett anrop till main(). När en funktion anropas, ges kontroll till den funktionen. Efter att funktionen är klar med sitt jobb, ges kontroll tillbaka till den anropande funktionen. • Om en funktionsprototyp har getts, kontrollerar kompilatorn att typerna på argumenten är kompatibla. • Argumenten skickas ”call-by-value”. • Detta betyder att varje argument utvärderas och värdet av argumentet skickas till funktionen. Värdena lagras i den korresponderande lokala parametern. • Alltså, om en variabel skickas till en funktion så ändras inte värdet på variabeln i den anropande miljön. Datavetenskap för teknisk kemi 10 p, moment 1 13

Exempel #include <stdio. h> int compute_sum(int n); int main(void) { int n = 3,

Exempel #include <stdio. h> int compute_sum(int n); int main(void) { int n = 3, sum; printf(”%dn”, n); sum = compute_sum(n); printf(”%dn”, sum); } /* forts. nästa slide */ Datavetenskap för teknisk kemi 10 p, moment 1 14

Exempel (forts) /* forts. från förra slide */ int compute_sum(int n) { int sum

Exempel (forts) /* forts. från förra slide */ int compute_sum(int n) { int sum = 0; for (; n > 0; --n) sum += n; return sum; } Datavetenskap för teknisk kemi 10 p, moment 1 15

Funktionsanrop • Funktionsanrop innebär: – Varje uttryck i argumentlistan utvärderas – Värdet på uttrycket

Funktionsanrop • Funktionsanrop innebär: – Varje uttryck i argumentlistan utvärderas – Värdet på uttrycket konverteras, om nödvändigt, till typen på den formella parametern och det värdet ges till den formella parametern i början av funktionskroppen. – Funktionskroppen exekveras (körs). – Om en return-sats påträffas, så ges kontrollen tillbaka till den anropande miljön – Om return-satsen innehåller ett uttryck, utvärderas uttrycket och konverteras, om nödvändigt, till returtypen och det värdet skickas till den anropande miljön. – Om en return-sats inte innehåller ett uttryck, skickas inget användbart värde tillbaka till den anropande miljön. Datavetenskap för teknisk kemi 10 p, moment 1 16

Funktionsanrop • Funktionsanrop innebär: (forts. ) – Om ingen return-sats påträffas, ges kontrollen tillbaka

Funktionsanrop • Funktionsanrop innebär: (forts. ) – Om ingen return-sats påträffas, ges kontrollen tillbaka till den anropande miljön när slutet på funktionskroppen påträffas. Inget användbart värde returneras. – Alla argument skickas ”call-by-value” Datavetenskap för teknisk kemi 10 p, moment 1 17

Programutveckling • Normalt skrivs ett stort program i ett separat bibliotek som en samling.

Programutveckling • Normalt skrivs ett stort program i ett separat bibliotek som en samling. h och. c filer, där varje. c-fil innehåller en eller flera funktionsdefinitioner. • Varje. c-fil kan kompileras igen endast när det är nödvändigt och därmed sparas tid både för kompileraren och programmeraren (se användningen av make, s. 532) • Antag att vi utvecklar ett stort program ”pgm”. I början av varje. c-fil så lägger vi raden #include ”pgm. h” • När preprocessorn påträffar detta direktiv, söker den först i det aktuella biblioteket efter filen ”pgm. h”. Om den finns, så läggs den in där #include påträffades. Om den inte finns, söker preprocessorn i system-biblioteken. Datavetenskap för teknisk kemi 10 p, moment 1 18

pgm. h #include <stdio. h> #include <stdlib. h> #define N 3 /* funktionsprototyper */

pgm. h #include <stdio. h> #include <stdlib. h> #define N 3 /* funktionsprototyper */ void fct 1(int k); void fct 2(void); void wrt_info(char *); Datavetenskap för teknisk kemi 10 p, moment 1 19

main. c #include ”pgm. h” int main(void) { char ans; int i, n =

main. c #include ”pgm. h” int main(void) { char ans; int i, n = N; printf(”%s”, ”This program does not do very much. n” ”Do you want more information? ”); scanf(”%c”, &ans); if (ans == ’y’ || ans == ’Y’) wrt_info(”pgm”); for (i=0; i < n; ++i) fct 1(i); printf(”Bye!n”); return 0; } Datavetenskap för teknisk kemi 10 p, moment 1 20

fct. c #include ”pgm. h” void fct 1(int n) { int i; printf(”Hello from

fct. c #include ”pgm. h” void fct 1(int n) { int i; printf(”Hello from fct 1()n”); for (i=0; i < n; ++i) fct 2(); } void fct 2(void) { printf(”Hello from fct 2()n”); } Datavetenskap för teknisk kemi 10 p, moment 1 21

wrt. c #include ”pgm. h” void mrt_info(char *pgm_name) { printf(”Usage: %snn”, pgm_name); printf(”%sn”, ”This

wrt. c #include ”pgm. h” void mrt_info(char *pgm_name) { printf(”Usage: %snn”, pgm_name); printf(”%sn”, ”This program illustrates how one can write a programn” ”in more than one file. In this example, we have an” ”single. h file that gets included at the top of ourn” ”three. c files. Thus, the. h file acts as the ”glue”n” ”that binds the program together. nn” ”Note that the functions fct 1() and fct 2() when calledn” ”first says ”hello”. When writing a serious program, then” ”programmer sometimes does this in a first working versionn” ”the code. n”); } /* } on this line to save space only! */ Datavetenskap för teknisk kemi 10 p, moment 1 22

Vad utgör ett stort program? • För en vanlig programmerare så kan ett par

Vad utgör ett stort program? • För en vanlig programmerare så kan ett par hundra rader utgöra ett stort program. • Vilka rader räknas? – READ_ME –. c och. h filer • I kommersiella applikationer (program) skrivs program av flera programmerare och ett stort program kan bestå av flera hundra tusen rader. • På 70 -talet hos IBM fick programmerarna betalt efter antalet ”k-lines” de skrev (1000 rader). Självklart blev programmen större än nödvändigt. . . Datavetenskap för teknisk kemi 10 p, moment 1 23

Assertions • Header-filen assert. h innehåller makrot assert(). • Det är bra programmeringsvana att

Assertions • Header-filen assert. h innehåller makrot assert(). • Det är bra programmeringsvana att använda sig av assert() för att kontrollera att argumenten till en funktion är korrekta. #include <assert. h> int f(int a, int b) { assert(a!=4 && b!=0); return a/b; } int main() { f(2, 0); } /* assertion will fail! */ Datavetenskap för teknisk kemi 10 p, moment 1 24

Assertions • Om ett argument till assert() är falskt, kommer programmet att skriva ut

Assertions • Om ett argument till assert() är falskt, kommer programmet att skriva ut ett felmeddelande, t. ex. ”Assertion failed on line 23” och programmet kommer att avslutas. • Assertions är enkla att skriva och gör källkoden robustare. • Andra läsare av källkoden kan dessutom lättare förstå innehållet. • Använd assert()!!! Datavetenskap för teknisk kemi 10 p, moment 1 25

Räckvidd (scope) • Grundregeln är att identifierare är bara tillgängliga inne i det block

Räckvidd (scope) • Grundregeln är att identifierare är bara tillgängliga inne i det block där de deklarerades. • De finns inte utanför blocket. • Detta låter som en enkel regel, men programmerare väljer ofta att använda samma identifierare på olika variabler. – Frågan uppstår då vilken objekt identifieraren refererar till. . . Datavetenskap för teknisk kemi 10 p, moment 1 26

Exempel { int a = 2; /* outer block a */ printf(”%dn”, a); {

Exempel { int a = 2; /* outer block a */ printf(”%dn”, a); { int a = 5; /* inner block a */ printf(”%dn”, a); } printf(”%dn”, ++a); /* back to the outer block a */ } • Vad skrivs ut? Datavetenskap för teknisk kemi 10 p, moment 1 27

Exempel { int a = 1, b = 2, c = 3; printf(”%3 d%3

Exempel { int a = 1, b = 2, c = 3; printf(”%3 d%3 d%3 dn”, a, b, c); { int b = 4; float c = 5. 0; printf(”%3 d%3 d%5. 1 fn”, a, b, c); a = b; { int c; c = b; printf(”%3 d%3 d%3 dn”, a, b, c); } printf(”%3 d%3 d%5. 1 fn”, a, b, c); } printf(”%3 d%3 d%3 dn”, a, b, c); } Datavetenskap för teknisk kemi 10 p, moment 1 28

Parallella och nästlade block { int a, b; { /* inner block 1 */

Parallella och nästlade block { int a, b; { /* inner block 1 */ float b; . . . /* int a is known, but not int b */ } { /* inner block 2 */ float a; . . . /* int b is known but not int a. */ /* nothing in inner block 1 is known */ } } • Huvudsyftet med att använda block är att spara minne. Minne reserveras bara när variabeln behövs. Vid andra tillfällen kan minnet användas till annat. Datavetenskap för teknisk kemi 10 p, moment 1 29

Debugging • Ett annat vanligt användningsområde för block är debugging (avlusning) • Antag att

Debugging • Ett annat vanligt användningsområde för block är debugging (avlusning) • Antag att variabeln v missköter sig { static int cnt = 0; printf(”*** debug: cnt = %d v = %dn”, ++cnt, v); } • cnt är nu lokal till blocket och kommer inte att störa resten av programmet. • Den är dessutom deklarerad som static, vilket betyder att den initialiseras (i detta fall till noll) och behåller sedan sitt gamla värde. Datavetenskap för teknisk kemi 10 p, moment 1 30

Lagringsklasser • Varje variabel och funktion i C har två attribut; typ och lagringsklass.

Lagringsklasser • Varje variabel och funktion i C har två attribut; typ och lagringsklass. • De fyra lagringsklasserna är auto, extern, register och static. • Den vanligaste lagringklassen är auto, men en programmerare måste känna till de andra lagringsklasserna. • Alla fyra lagringsklasser har viktiga användningsområden. Datavetenskap för teknisk kemi 10 p, moment 1 31

Lagringklassen auto • Om man deklarerar en variabel som vanligt, så blir den auto.

Lagringklassen auto • Om man deklarerar en variabel som vanligt, så blir den auto. • En sammansatt sats med variabel deklarationer kallas för ett block. • Nyckelordet auto kan användas för att explicit specifiera lagringklassen auto int a, b, c; auto float f; • Eftersom en variabel automatiskt blir auto om ingen annan lagringsklass anges, så är det sällan lagringsklassen anges explicit som ovan. Datavetenskap för teknisk kemi 10 p, moment 1 32

Lagringsklassen extern • Ett sätt att överföra information mellan block och funktioner är att

Lagringsklassen extern • Ett sätt att överföra information mellan block och funktioner är att använda externa variabler. • När en variabel deklareras utanför en funktion så är lagringen permanent och dess lagringsklass blir extern. • En sådan variabel är global för alla funktioner som deklareras efter variabeldeklarationen. • Normalt är globala (eller externa) variabler inte bra för programmets korrekthet. • Även funktioner kan deklareras till att vara externa. Datavetenskap för teknisk kemi 10 p, moment 1 33

Exempel #include <stdio. h> int a = 1, b = 2, c = 3;

Exempel #include <stdio. h> int a = 1, b = 2, c = 3; int f(void); int main(void) { printf(”%3 dn”, f()); printf(”%3 d%3 d%3 dn”, a, b, c); return 0; } int f(void) { int b, c; a = b = c = 4; return (a + b + c); } Datavetenskap för teknisk kemi 10 p, moment 1 34

extern • Nyckelordet extern kan användas vid deklarationen av externa variabler, men krävs ej.

extern • Nyckelordet extern kan användas vid deklarationen av externa variabler, men krävs ej. • En extern variabel kan ej ges lagringsklasserna auto eller register. • Den kan ges static, men då blir användningen speciell (se senare OH). • extern kan också användas för att säga åt kompilatorn att söka någon annanstans efter värdet på variabeln. Datavetenskap för teknisk kemi 10 p, moment 1 35

file 1. c #include <stdio. h> int a = 1, b = 2, c

file 1. c #include <stdio. h> int a = 1, b = 2, c = 3; int f(void); int main(void) { printf(”%3 dn”, f()); printf(”%3 d%3 d%3 dn”, a, b, c); return 0; } Datavetenskap för teknisk kemi 10 p, moment 1 36

file 2. c int f(void) { extern int a; /* look for it elsewhere

file 2. c int f(void) { extern int a; /* look for it elsewhere */ int b, c; a = b = c = 4; return (a + b + c); } • Detta ger samma effekt som det tidigare program-exemplet. • Externa variabler försvinner aldrig. De kan användas för att överföra information mellan funktioner. Ofta är detta inte bra. • Externa variabler ”försvinner” (tillfälligt) när identifieraren omdefineras. Datavetenskap för teknisk kemi 10 p, moment 1 37

Lagringklassen register • Denna lagringsklass säger åt kompilatorn att variablerna ska lagras i processorns

Lagringklassen register • Denna lagringsklass säger åt kompilatorn att variablerna ska lagras i processorns interna register. • Dessa register är mycket snabbare än det vanliga minnet. • När man deklarerar en variabel som register, så ger man en rekommendation till kompilatorn. Den kan välja att ignorera din begäran. • Många register i processorn är dessutom reserverade för system-ändamål och kan inte användas för vanliga program. • Men om det finns lediga register, kan programmet snabbas upp betydligt. Datavetenskap för teknisk kemi 10 p, moment 1 38

Exempel { register int i; for (i = 0; i < LIMIT; ++i) {.

Exempel { register int i; for (i = 0; i < LIMIT; ++i) {. . . } } /* block exit will free register */ • En vanlig variabel att deklarera som register är loopvariabler. • Dessa används ofta och tjänar mest på att bli registervariabler. • Om ingen typ anges, antas typen vara int register i; är samma sak som register int i; Datavetenskap för teknisk kemi 10 p, moment 1 39

Lagringklassen static • Statiska deklarationer har två viktiga användningsområden. – De låter en lokal

Lagringklassen static • Statiska deklarationer har två viktiga användningsområden. – De låter en lokal variabel behålla sitt gamla värde – De kan också användas vid externa deklarationer (se senare OH) void f(void) { static int cnt = 0; ++cnt; if (cnt % 2 == 0). . /* do something */ else. . /* do something different */ } Datavetenskap för teknisk kemi 10 p, moment 1 40

Statiska externa variabler • Varför ska man använda statiska externa variabler? Externa variabler behåller

Statiska externa variabler • Varför ska man använda statiska externa variabler? Externa variabler behåller ju redan sitt gamla värde. • En viktig princip inom programmering är modularitet. Genom att separera olika delar av ett program så underlättar man debugging. • Om en extern variabel deklareras som static, kommer dess räckvidd att begränsas till filen som den deklarerades i och bara vara tillgänglig i funktioner som deklareras nedanför i filen. • Även om en annan fil försöker komma åt den externa variabeln med nyckelordet extern så kommer detta att misslyckas. • Det fungerar alltså som en ”privacy-mechanism”. Datavetenskap för teknisk kemi 10 p, moment 1 41

Exempel #define INITIAL_SEED 17 #define MULTIPLIER 25173 #define INCREMENT 13849 #define MODULUS 65536 #define

Exempel #define INITIAL_SEED 17 #define MULTIPLIER 25173 #define INCREMENT 13849 #define MODULUS 65536 #define FLOATING_MODULUS 65536. 0 static unsigned seed = INITIAL_SEED; /* external but private for this file */ random(void) { seed = (MULTIPLIER * seed + INCREMENT) % MODULUS; return seed; } double probability(void) { seed = (MULTIPLIER * seed + INCREMENT) % MODULUS; return (seed / FLOATING_MODULUS); } Datavetenskap för teknisk kemi 10 p, moment 1 42

Exempel • En funktion kan också deklareras som static och blir därmed ”privat” för

Exempel • En funktion kan också deklareras som static och blir därmed ”privat” för den filen. static int g(void); void f(int a) {. . /* funktionsprototyp */ /* funktionsdefinition */ /* g() är tillgängligt här, */ } /* men inte i andra filer */ static int g(void) { /* funktionsdefinition */ . . } Datavetenskap för teknisk kemi 10 p, moment 1 43

Initialisering • Normala variabler (auto och register) innehåller skräpvärden om de inte har initialiserats.

Initialisering • Normala variabler (auto och register) innehåller skräpvärden om de inte har initialiserats. • Däremot så initialiseras externa och statiska variabler till noll om inte programmeraren anger ett värde. • Vissa C-kompilerare sätter dock värdet på auto-variabler till noll om programmeraren inte anger något annat. • Detta kan dock skilja sig åt och som programmerare bör man inte lita på detta utan istället explicit sätta värden till noll. Datavetenskap för teknisk kemi 10 p, moment 1 44

Rekursion • En funktion är rekursiv om den anropas sig själv, direkt eller indirekt.

Rekursion • En funktion är rekursiv om den anropas sig själv, direkt eller indirekt. • Alla funktioner kan anropas rekursivt. • I sin enklaste form är rekursion enkel att förstå. #include <stdio. h> int main(void) { printf(” The universe is never ending! ”); main(); return 0; /* kommer aldrig att nås! */ } Datavetenskap för teknisk kemi 10 p, moment 1 45

Exempel • För att summera de fem första heltalen kan man skriva int sum(int

Exempel • För att summera de fem första heltalen kan man skriva int sum(int n) { if (n <= 1) return n; else return (n + sum(n-1)); } sum(1) 1 sum(2) 2 + sum(1) eller 2 + 1 sum(3) 3 + sum(2) eller 3 + 2 + 1 sum(4) 4 + sum(3) eller 4 + 3 + 2 + 1 Datavetenskap för teknisk kemi 10 p, moment 1 46

fakultet. c • Matematiskt så lyder definitionen av fakultet som följer 0! = 1,

fakultet. c • Matematiskt så lyder definitionen av fakultet som följer 0! = 1, n! = n(n-1). . . 3*2*1 för n > 0 eller ekvivalent 0! = 1 n! = n((n-1)!) för n > 0 • I C kan det skrivas rekursivt som int factorial(int n) { if (n <= 1) /* antar att n inte är negativt */ return 1; else return (n* factorial(n-1)); } Datavetenskap för teknisk kemi 10 p, moment 1 47

Iterativ motsvarighet • Funktionen kan också skrivas iterativt int factorial(int n) { int product

Iterativ motsvarighet • Funktionen kan också skrivas iterativt int factorial(int n) { int product = 1; for (; n > 1; --n) product *= n; return product; } Datavetenskap för teknisk kemi 10 p, moment 1 48

wrt_backwards. c #include <stdio. h> void wrt_it(void); int main(void) { printf(”Input a line: ”);

wrt_backwards. c #include <stdio. h> void wrt_it(void); int main(void) { printf(”Input a line: ”); wrt_it(); printf(”nn”); return 0; } void wrt_it(void) { int c; if ((c = getchar()) != ’n’) wrt_it(); putchar(c); } Datavetenskap för teknisk kemi 10 p, moment 1 49

Effektivitet • Många algoritmer har både rekursiva och iterativa lösningar. • Normalt så är

Effektivitet • Många algoritmer har både rekursiva och iterativa lösningar. • Normalt så är den rekursiva formuleringen vackrare och använder färre variabler för att göra samma beräkning. • Vissa datorspråk använder bara rekursion för att åstadkomma upprepning (dvs. de har inte t. ex. while eller for). • Rekursion orsakar att datorn lägger gamla värden av variabler i en stack för att komma ihåg dom. • Ofta kan rekursion orsaka många funktionsanrop. • Fibonacci-sekvensen defineras som följer f 0 = 0, f 1 = 1, fi+1 = fi + fi-1 för i = 1, 2, . . . Datavetenskap för teknisk kemi 10 p, moment 1 50

fibonacci. c int fibonacci(int n) { if (n <= 1) return n; else return

fibonacci. c int fibonacci(int n) { if (n <= 1) return n; else return (fibonacci(n-1) + fibonacci(n-2)); } /* n fibonacci(n) antalet funktionsanrop som läggs på stacken 0 0 1 1 2 1 3 42 267914296 866988873 43 433494437 1402817465 . . . . */ Datavetenskap för teknisk kemi 10 p, moment 1 51

Rekursion vs. iteration • Vissa programmerare anser att rekursion inte ska användas p. g.

Rekursion vs. iteration • Vissa programmerare anser att rekursion inte ska användas p. g. a. de många funktionsanropen => ineffektivitet. • Rekursion har dock många fördelar – de är ofta enklare att skriva – lättare att förstå – lättare att underhålla • Därför kan det vara motiverat att använda rekursion trots deess nackdelar. Datavetenskap för teknisk kemi 10 p, moment 1 52