E N D
Enkelt program med funktion /* two_func.c - a program that uses two functions in one file *//* from Stephen PrataC Primer Plus ISBN 1-57169-161-8 */#include <stdio.h> #include <stdlib.h> void butler(void); /* ANSI C function prototype */ int main( void) { printf("I will summon the butler function.\n"); butler(); printf("Yes. Bring me some tea.\n"); system("PAUSE"); return 0; } void butler(void) /* start of function definition */{ printf("You rang, sir?\n");}
Funktionernågot in och något annat ut Parametrar Funktion Returvärde
Funktionerger en klarare bild • tyvärr så klarar inte människan att ”hålla hur många bollar (hattar) i luften som helst” förmågan att se samband och konsekvenser mellan samtidiga skeénden är begränsad. Fundera t ex på hur många tal du kan memorera om någon räknar upp dem för dig. • kanske klarar du 7 st men ofta hamnar man på 3-4 st. • med funktioner kan man dela upp sinkällkod i del- (under-) program för att få överblick, se samband och konsekvens • varje delprogram ( funktion ) löseren avgränsad deluppgift
Funktioner nu kör vi ränteberäknings-programmet igen. De här bilderna har du sett förut! Exempel
Ett program växer fram ...förbättringar - program med funktions-moduler /* Beräknar kapitaltillväxt på 10 år framåt eller bakåt */ #include <stdio.h> #define RANTESATS 8.5 #define ANTAL_AR 10 int main ( void ) { float kapital ; int ar ; printf("Insatt kapital? "); scanf("%f", &kapital); printf("\n År Saldo\n == =====\n"); for ( ar = 1; ar <= ANTAL_AR ; ar++ ) { if ( kapital > 0 ) kapital = kapital * ( 1 + RANTESATS/100 ); else kapital = kapital * 1/( 1 + RANTESATS/100 ); printf("%3d%11.2f\n", ar,kapital>0 ? kapital:-kapital); } system("PAUSE"); return 0; } många satser efter varandra gör programmet oöverskådligt - dela upp koden i funktioner
Att konstruera en funktion Funktionskonstruktion.Dela upp programmet m h a del- (under-) program.
Klipp ut! /* Beräknar kapitaltillväxt på 10 år framåt eller bakåt */ #include <stdio.h> #define RANTESATS 8.5 #define ANTAL_AR 10 int main ( void ) { float kapital ; int ar ; printf("Insatt kapital? "); scanf("%f", &kapital); printf("\n År Saldo\n == =====\n"); for ( ar = 1; ar <= ANTAL_AR ; ar++ ) { if ( kapital > 0 ) kapital = kapital * ( 1 + RANTESATS/100 ); else kapital = kapital * 1/( 1 + RANTESATS/100 ); printf("%3d%11.2f\n", ar,kapital>0 ? kapital:-kapital); } system("PAUSE"); return 0; } Klipp ut!
Kvar i main … /* Beräknar kapitaltillväxt på 10 år framåt eller bakåt */ #include <stdio.h> #define RANTESATS 8.5 #define ANTAL_AR 10 int main ( void ) { float kapital ; int ar ; printf("Insatt kapital? "); scanf("%f", &kapital); system("PAUSE"); return 0; } OK!
Klistra in! Definiera den nya funktionen! klistra in printf("\n År Saldo\n == =====\n"); for ( ar = 1; ar <= ANTAL_AR ; ar++ ) { if ( kapital > 0 ) kapital = kapital * ( 1 + RANTESATS/100 ); else kapital = kapital * 1/( 1 + RANTESATS/100 ); printf("%3d%11.2f\n", ar,kapital>0 ? kapital:-kapital); }
Definiera den nya funktionen. Definiera den nya funktionen! lägg till! void TabellPaSkarmen( int antalAr , float kapital ) { int ar ; printf("\n År Saldo\n == =====\n"); for ( ar = 1; ar <= antalAr; ar++ ) { if ( kapital > 0 ) kapital = kapital * ( 1 + RANTESATS/100 ); else kapital = kapital * 1/( 1 + RANTESATS/100 ); printf("%3d%11.2f\n", ar,kapital>0 ? kapital:-kapital); } return; } ändra!
Funktionens delar Definiera den nya funktionen! funktionens returtyp - utdatatyp void TabellPaSkarmen( int antalAr , float kapital ) { int ar ; printf("\n År Saldo\n == =====\n"); for ( ar = 1; ar <= antalAr; ar++ ) { if ( kapital > 0 ) kapital = kapital * ( 1 + RANTESATS/100 ); else kapital = kapital * 1/( 1 + RANTESATS/100 ); printf("%3d%11.2f\n", ar,kapital>0 ? kapital:-kapital); } return; } funktionsprototyp,funktionshuvud funktionens formella parametrar (argument) - indata funktionens namn
Funktionens delar funktionens egen variabel, okänd utanför funktions-kroppen Definiera den nya funktionen! void TabellPaSkarmen( int antalAr , float kapital ) { int ar ; printf("\n År Saldo\n == =====\n"); for ( ar = 1; ar <= antalAr; ar++ ) { if ( kapital > 0 ) kapital = kapital * ( 1 + RANTESATS/100 ); else kapital = kapital * 1/( 1 + RANTESATS/100 ); printf("%3d%11.2f\n", ar,kapital>0 ? kapital:-kapital); } return; } indatavariablerna, som bara är kända i funk-tionen används i funktionen
Funktionsdeklaration och funktionsanrop /* Beräknar kapitaltillväxt på 10 år framåt eller bakåt */ #include <stdio.h> #define RANTESATS 8.5 #define ANTAL_AR 10 void TabellPaSkarmen( int , float ); int main ( void ) { float kapital ; int ar ; printf("Insatt kapital? "); scanf("%f", &kapital); TabellPaSkarmen( ANTAL_AR, kapital ); return 0; } i stommen, main()- funktionen lägg till funktions-deklaration och funktions-anrop här skall funktions-definitionen in
Parameter i stället för konstant /* Beräknar kapitaltillväxt på x år framåt eller bakåt */ #include <stdio.h> #define RANTESATS 8.5 #define ANTAL_AR 10 void TabellPaSkarmen( int , float ); int main ( void ) { float kapital ; int ar , antalAr; printf("Insatt kapital och antal år ?(-->1000 10)--> "); scanf("%f%d", &kapital, &antalAr); TabellPaSkarmen( antalAr, kapital ); return 0; } Ändra detta, man kan nu ange antal år vid exekveringen. här skall funktions-definitionen in
Översikt – hela programmet /* Beräknar kapitaltillväxt på 10 år framåt eller bakåt */ #include <stdio.h> #define RANTESATS 8.5 void TabellPaSkarmen( int , float ); int main ( void ) { float kapital ; int antalAr; printf("Insatt kapital och antal år ?(-->1000 10)--> "); scanf("%f%d", &kapital, &antalAr); TabellPaSkarmen( antalAr, kapital ); return 0; } void TabellPaSkarmen( int antalAr , float kapital ) { int ar ; printf("\n År Saldo\n == =====\n"); for ( ar = 1; ar <= antalAr; ar++ ) { if ( kapital > 0 ) kapital = kapital * ( 1 + RANTESATS/100 ); else kapital = kapital * 1/( 1 + RANTESATS/100 ); printf("%3d%11.2f\n", ar,kapital>0 ? kapital:-kapital); } system(”PAUSE”); return; } en översiktsbild av hela programmet stommen funktionen
Översikt, funktionsdeklaration och funktionsdefinition en översiktsbild av hela program- met /* Beräknar kapitaltillväxt på 10 år framåt eller bakåt */ #include <stdio.h> #define RANTESATS 8.5 void TabellPaSkarmen( int , float ); int main ( void ) { float kapital ; int antalAr; printf("Insatt kapital och antal år ?(-->1000 10)--> "); scanf("%f%d", &kapital, &antalAr); TabellPaSkarmen( antalAr, kapital ); return 0; } void TabellPaSkarmen( int antalAr , float kapital ) { int ar ; printf("\n År Saldo\n == =====\n"); for ( ar = 1; ar <= antalAr; ar++ ) { if ( kapital > 0 ) kapital = kapital * ( 1 + RANTESATS/100 ); else kapital = kapital * 1/( 1 + RANTESATS/100 ); printf("%3d%11.2f\n", ar,kapital>0 ? kapital:-kapital); } return; } funktionsdeklaration, för att kompilatorn skall kunna kontrollera att man använder funktionen rätt funktionsdefinition
En hatt i taget … /* Beräknar kapitaltillväxt på 10 år framåt eller bakåt */ #include <stdio.h> #define RANTESATS 8.5 void TabellPaSkarmen( int , float ); int main ( void ) { float kapital ; int antalAr; printf("Insatt kapital och antal år ?(-->1000 10)--> "); scanf("%f%d", &kapital, &antalAr); TabellPaSkarmen( antalAr, kapital ); return 0; } void TabellPaSkarmen( int antalAr , float kapital ) { int ar ; printf("\n År Saldo\n == =====\n"); for ( ar = 1; ar <= antalAr; ar++ ) { if ( kapital > 0 ) kapital = kapital * ( 1 + RANTESATS/100 ); else kapital = kapital * 1/( 1 + RANTESATS/100 ); printf("%3d%11.2f\n", ar,kapital>0 ? kapital:-kapital); } return; } Å va bra!Nu tar jag en hatt åt gången!
Funktionsanrop • Hur anropas en funktion? • Vad händer då en funktion anropas och exekveras?
Funktionsanropexempel /* Beräknar kapitaltillväxt på x år framåt eller bakåt */ #include <stdio.h> #define RANTESATS 8.5 void TabellPaSkarmen( int , float ); int main ( void ) { float kapital ; int antalAr; printf("Insatt kapital och antal år ?(-->1000 10)--> "); scanf("%f%d", &kapital, &antalAr); TabellPaSkarmen( antalAr, kapital ); system("PAUSE"); return 0; }
Vad händer då man definierar ett minne ? /* Beräknar kapitaltillväxt på 10 år framåt eller bakåt */ #include <stdio.h> #define RANTESATS 8.5 void TabellPaSkarmen( int , float ); int main ( void ) { float kapital ; int antalAr; printf("Insatt kapital och antal år ?(-->1000 10)--> "); scanf("%f%d", &kapital, &antalAr); TabellPaSkarmen( antalAr, kapital ); return 0; }
tid Main’s aktiveringspost på ”stacken” Bytes Maskinkod programmet • main() exekveras int main ( void ) { float kapital ; int antalAr; printf("Insatt kapital och antal år ? "); printf("(-->1000 10)--> "); scanf("%f%d", &kapital, &antalAr); TabellPaSkarmen( antalAr, kapital ); return 0; } Heap main’s ”egna” variabler skapas på stacken - aktiveringspost kapital=100 Stack main() antalAr=1
Hur måste TabellPaSkarmen()se ut ? void TabellPaSkarmen( int antalAr , float kapital ) { int ar ; printf("\n År Saldo\n == =====\n"); for ( ar = 1; ar <= antalAr; ar++ ) { if ( kapital > 0 ) kapital = kapital * ( 1 + RANTESATS/100 ); else kapital = kapital * 1/( 1 + RANTESATS/100 ); printf("%3d%11.2f\n", ar,kapital>0 ? kapital:-kapital); } return; } dessa variabelnamn kan vara lika men behöver inte vara det. int main ( void ) { float kapital ; int antalAr; printf("Insatt kapital och antal år ? "); printf("(-->1000 10)--> "); scanf("%f%d", &kapital, &antalAr); TabellPaSkarmen( antalAr, kapital ); return 0; } funktionen anropas, (aktuella parametrar)
tid Aktuella och formella parametrar Bytes Maskinkod programmet void TabellPaSkarmen(int antalAr , float kapital) { int ar ; • TabellPaSkarmen() exekveras Heap TabellPaSkarmen() antalAr=1 kapital=100 ar=?? de aktuella para-metrarna anpassas och kopieras till funktionens formella parametrar kapital=100 kapital=100 Stack main() antalAr=1 antalAr=1
Bytes Maskinkod programmet Heap Stack tid Funktionens aktiveringspost • TabellPaSkarmen() exekveras for ( ar = 1; ar <= antalAr; ar++ ) kapital = kapital * ( 1 + RANTESATS/100 ); satserna i funktionen utförs TabellPaSkarmmen() antalAr=1 antalAr=1 antalAr=1 kapital=100 kapital=108.5 kapital=108.5 ar=?? ar=1 ar=2 kapital=100 kapital=100 kapital=100 main() main() kapital=100 antalAr=1 antalAr=1 antalAr=1 antalAr=1
Bytes Maskinkod programmet Heap Stack tid Aktiveringsposterna tas bort • TabellPaSkarmen() dör • main() dör - exekvering slut TabellPaSkarmen() antalAr=1 kapital=108.5 ar=2 kapital=100 kapital=100 main() main() antalAr=1 antalAr=1
Värdeöverföring • Talen 1 och 100 har värdeöverförts, kopierats in i funktionen TabellPaSkarmen() • Att nu förändra kopian ändrar inte på originalet antalAr=1 TabellPaSkarmen() kapital=100 ar=?? main() kapital=100 antalAr=1
Fakultetsfunktionen – ett klassiskt exempel Värdeöverföringen, ”kopiorna”, möjliggör rekursion … 5! = 5 4 3 2 1 5! = 5 4! 4! = 4 3! 3! = 3 2! 2! = 2 1! 0! = 1 int nfak( int n ) {if (n<=0)return (1); elsereturn ( n * nfak( n-1));} anropar sig själv med n-1 slut
Rekursionn-fakultet, ett klassiskt exempel #include <stdio.h> int nfak( int ) ; int main( void ){ int fak , svar ; printf( "Ge fakultet --> " ); scanf("%d", &fak); svar = nfak(fak); printf("\nSvar: %d! = %d ", fak , svar ); system("PAUSE") return 0; } int nfak( int n ) { if (n<=0) return (1); else return ( n * nfak( n-1)); }
Vad är det som händer? Bytes primärminnet Heap Stack fak=3, svar=? fak3 main() tid
Vad är det som händer? Bytes 3 Heap 3 nfak(3) Stack n=3 fak=3, svar=? fak=3, svar=? main() main() tid
Vad är det som händer? Bytes Heap 2 Heap 2 nfak(2) n=2 nfak(3) nfak(3) Stack n=3 n=3 fak=3, svar=? fak=3, svar=? fak=3, svar=? main() main() main() tid
Vad är det som händer? Bytes Heap 1 Heap 1 nfak(1) n=1 nfak(2) nfak(2) n=2 n=2 nfak(3) nfak(3) nfak(3) Stack n=3 n=3 n=3 fak=3, svar=? fak=3, svar=? fak=3, svar=? fak=3, svar=? main() main() main() main() tid
Vad är det som händer? Bytes nfak(1) n=1 nfak(2) n=2 nfak(3) n=3 fak=3, svar=? main() tid
Vad är det som händer? Bytes 0 Heap nfak(0) n=0 nfak(1) nfak(1) n=1 n=1 nfak(2) nfak(2) n=2 n=2 nfak(3) nfak(3) n=3 n=3 fak=3, svar=? fak=3, svar=? main() main() tid
Vad är det som händer? Bytes nfak(0) n=0 1 nfak(1) nfak(1) n=1 n=1 nfak(2) nfak(2) n=2 n=2 nfak(3) nfak(3) n=3 n=3 fak=3, svar=? fak=3, svar=? main() main() tid
Vad är det som händer? Bytes 1 1 nfak(0) n=0 1 nfak(1) nfak(1) n=1 n=1 n=1 1 nfak(2) nfak(2) nfak(2) n=2 n=2 n=2 nfak(3) nfak(3) nfak(3) n=3 n=3 n=3 fak=3, svar=? fak=3, svar=? fak=3, svar=? main() main() main() tid
Vad är det som händer? Bytes 2 1 nfak(0) n=0 1 nfak(1) n=1 n=1 1 nfak(2) nfak(2) nfak(2) n=2 n=2 n=2 2 nfak(3) nfak(3) nfak(3) n=3 n=3 n=3 fak=3, svar=? fak=3, svar=? fak=3, svar=? main() main() main() tid
Vad är det som händer? Bytes 3 2 n=1 1 nfak(2) nfak(2) n=2 n=2 2 nfak(3) nfak(3) nfak(3) n=3 n=3 n=3 6 fak=3, svar=? fak=3, svar=? fak=3, svar=? main() main() main() tid
Vad är det som händer? Bytes 3 6 3 2 nfak(2) n=2 2 nfak(3) nfak(3) n=3 n=3 6 fak=3, svar=? fak=3, svar=? fak=3, svar=6 main() main() main() program-slut tid
Rekursionn-fakultet, ett klassiskt exempel #include <stdio.h> int nfak( int ) ; int main( void ) { int fak , svar ; printf( "Ge fakultet --> " ); scanf("%d", &fak); svar = nfak(fak); printf("\nSvar: %d! = %d ", fak , svar ); return 0; } int nfak( int n ) { if (n<=0) return (1); else return ( n * nfak( n-1)); } variabeln svar behövs inte nfak(fak)
Rekursiontillämpning #include <stdio.h> void SkrivBaklanges( int ); int main( void ){ printf("Skriv tecken ( avsluta med Enter )--> "); SkrivBaklanges( getchar() ); system("PAUSE"); return 0; } void SkrivBaklanges( int tecken){ if (tecken != '\n') { SkrivBaklanges( getchar() ); putchar( tecken ); } return ; } • man kan använda rekursion för att vända på dataföljder
Provkör på övningen … /* backwards.c Reprints what you type but backwards *//* recursive function */#include <stdio.h>#include <stdlib.h>void SkrivBaklanges( int);int main(void){ printf( "Skriv tecken ( avsluta med Enter ) --> "); SkrivBaklanges( getchar() ); printf("\n"); system("PAUSE");return 0;} void SkrivBaklanges( int tecken){if (tecken != '\n') SkrivBaklanges( getchar()); putchar( tecken );}