Presentation laddar. Vänta.

Presentation laddar. Vänta.

Datavetenskap för teknisk kemi 10p, moment 11 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.

Liknande presentationer


En presentation över ämnet: "Datavetenskap för teknisk kemi 10p, moment 11 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."— Presentationens avskrift:

1 Datavetenskap för teknisk kemi 10p, moment 11 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())

2 Datavetenskap för teknisk kemi 10p, moment 12 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.

3 Datavetenskap för teknisk kemi 10p, moment 13 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.

4 Datavetenskap för teknisk kemi 10p, moment 14 Exempel 2 void wrt_adress(void) { printf(”%s\n%s\n%s\n%s\n\n”, ” **********************”, ” ** 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();

5 Datavetenskap för teknisk kemi 10p, moment 15 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); }

6 Datavetenskap för teknisk kemi 10p, moment 16 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 int a = 33; int main(void) { int b = 77; printf(”%d\n”, a + b); }

7 Datavetenskap för teknisk kemi 10p, moment 17 return •return satsen kan ha ett uttryck eller vara utan. return_statement ::= return; | return expression; return; 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.

8 Datavetenskap för teknisk kemi 10p, moment 18 Funktionsprototyper •En funktion bör deklareras innan den används. ANSI C tillhandahåller en deklarationssyntax som kallas funktions- prototyp. •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.

9 Datavetenskap för teknisk kemi 10p, moment 19 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 )

10 Datavetenskap för teknisk kemi 10p, moment 110 Funktions- deklarationer •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.

11 Datavetenskap för teknisk kemi 10p, moment 111 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.

12 Datavetenskap för teknisk kemi 10p, moment 112 Exempel #include #define N 7 void prn_heading(void) {.... } void power(int m, int n) {.... } int main(void) { prn_heading(); printf(”%d\n”, power(7,3)); }

13 Datavetenskap för teknisk kemi 10p, moment 113 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.

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

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

16 Datavetenskap för teknisk kemi 10p, moment 116 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.

17 Datavetenskap för teknisk kemi 10p, moment 117 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”

18 Datavetenskap för teknisk kemi 10p, moment 118 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.

19 Datavetenskap för teknisk kemi 10p, moment 119 pgm.h #include #define N 3 /* funktionsprototyper */ void fct1(int k); void fct2(void); void wrt_info(char *);

20 Datavetenskap för teknisk kemi 10p, moment 120 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) fct1(i); printf(”Bye!\n”); return 0; }

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

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

23 Datavetenskap för teknisk kemi 10p, moment 123 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...

24 Datavetenskap för teknisk kemi 10p, moment 124 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 int f(int a, int b) { assert(a!=4 && b!=0); return a/b; } int main() { f(2, 0); /* assertion will fail! */ }

25 Datavetenskap för teknisk kemi 10p, moment 125 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() !!!

26 Datavetenskap för teknisk kemi 10p, moment 126 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...

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

28 Datavetenskap för teknisk kemi 10p, moment 128 Exempel { int a = 1, b = 2, c = 3; printf(”%3d%3d%3d\n”, a, b, c); { int b = 4; float c = 5.0; printf(”%3d%3d%5.1f\n”, a, b, c); a = b; { int c; c = b; printf(”%3d%3d%3d\n”, a, b, c); } printf(”%3d%3d%5.1f\n”, a, b, c); } printf(”%3d%3d%3d\n”, a, b, c); }

29 Datavetenskap för teknisk kemi 10p, moment 129 Parallella och nästlade block •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. { 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 */ }

30 Datavetenskap för teknisk kemi 10p, moment 130 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 = %d\n”, ++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.

31 Datavetenskap för teknisk kemi 10p, moment 131 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.

32 Datavetenskap för teknisk kemi 10p, moment 132 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.

33 Datavetenskap för teknisk kemi 10p, moment 133 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.

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

35 Datavetenskap för teknisk kemi 10p, moment 135 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.

36 Datavetenskap för teknisk kemi 10p, moment 136 file1.c #include int a = 1, b = 2, c = 3; int f(void); int main(void) { printf(”%3d\n”, f()); printf(”%3d%3d%3d\n”, a, b, c); return 0; }

37 Datavetenskap för teknisk kemi 10p, moment 137 file2.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.

38 Datavetenskap för teknisk kemi 10p, moment 138 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.

39 Datavetenskap för teknisk kemi 10p, moment 139 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 register- variabler. •Om ingen typ anges, antas typen vara int register i; är samma sak som register int i;

40 Datavetenskap för teknisk kemi 10p, moment 140 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 */ }

41 Datavetenskap för teknisk kemi 10p, moment 141 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”.

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

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

44 Datavetenskap för teknisk kemi 10p, moment 144 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.

45 Datavetenskap för teknisk kemi 10p, moment 145 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 int main(void) { printf(” The universe is never ending! ”); main(); return 0; /* kommer aldrig att nås! */ }

46 Datavetenskap för teknisk kemi 10p, moment 146 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 sum(3)3 + sum(2) eller sum(4)4 + sum(3) eller

47 Datavetenskap för teknisk kemi 10p, moment 147 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)); }

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

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

50 Datavetenskap för teknisk kemi 10p, moment 150 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, f i+1 = f i + f i-1 för i = 1, 2,...

51 Datavetenskap för teknisk kemi 10p, moment 151 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 */

52 Datavetenskap för teknisk kemi 10p, moment 152 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.


Ladda ner ppt "Datavetenskap för teknisk kemi 10p, moment 11 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."

Liknande presentationer


Google-annonser