Programmeringsteknik DAVA07
Målsättning Målet är att den som gått igenom kursen skall: självständigt klara av att utforma ett program i C för lösning av problem. ha förståelse för de grundläggande delarna inom programmering, såsom datatyper, sekvens, iteration, underprogram och moduler, algoritmer samt datastrukturer. vara insatt i begreppen rekursion, pekare och filhantering. 2
Vad är programmering? Exempel på tavlan… 3
Byggstenar
Byggstenar Nyckelord Syntax Variabler Konstanter Operatorer Tecken 5
Nyckelord Reserverade ord (Keywords) Varje ord har en speciell betydelse Ex if, delete, return, new Kompilatorn känner igen dem Case sensitive Se fig 2.2 i Deitel FÖRE SLIDE: Vår tolk som ska tolka mellan engelska och kinesiska förstår inte allt man kan säga på engelska, han är t ex inte så bra på slang och dialekter. Faktiskt så har han ett begränsat ordförråd och om man använder något ord som han inte känner till säger han bara ”Jag förstår inte det ordet”. På samma sätt måste man använda en viss uppsättning av ord när man pratar med kompilatorn. SLIDE SKRIV PÅ TAVLAN: main() { cout<<”Hello”; } Utskrift: Hello 6
Tecken ( ) visar bl a en funktion { } delar in ett program i delar, t ex var main börjar och slutar ” ” avgränsar en textsträng ; avgränsar en sats // kommentar FÖRE SLIDE För att återigen gå tillbaks till vår kinesiske tolk så är han också väldigt känslig när han ska översätta skrivet material. Om vi skriver: SKRIV: Hello i am going to the beach do you want to come så förstår han inte det utan vi måste sätta ut punkter odyl ÄNDRA: Hello! I am going to the beach. Do you want to come? På samma sätt måste man använda vissa tecken när man pratar med kompilatorn för att han ska förstå vad saker börjar och slutar och vad de betyder SLIDE Tecknen hänvisar till ex på tavlan Vi kommer att prata mer om << (som är en operator) lite senare Om vi vill skriva ut fler saker kan vi lägga till det: main() { cout<<”Hello ”; cout<<”World!”; } Utskrift: Hello World! Om vi vill att det ska stå på två rader så att utskriften blir: Hello World! Så kan vi lägga till ett specialtecken: cout<<”Hello \n”; LÄGG TILL KOMMENTAR: //Mitt första program i C++ 7
Syntax Grammatik Måste skriva korrekt, exempel: main måste följas av ( ) för att skriva ut något måste man skriva cout<< och sedan det man vill skriva ut en sats tex cout<<”Hello”; måste avslutas med ; FÖRE SLIDE Vår kinesiske tolk är som sagt inte så bra på engelska, om man använder en felaktig grammatik så förstår han inte, om man t ex säger ”The button press” istället för ”Press the button” så säger tolken, jag förstår inte, du måste ha gjort något grammatiskt fel” På samma sätt talar kompilatorn om ifall vi har skrivit något som är syntaktiskt fel. SLIDE 8
Standardbibliotek Prototyper som innehåller kod Måste inkluderas först i koden Ex #include <iostream> Om man glömt inkludera ett bibliotek säger kompilatorn att den inte känner till funktionen man försöker använda För att kunna skriva ut till skärmen dvs för att kompilatorn ska förstå satsen cout<<”Hello”; måste man inkludera iostream.h Dessa är egentligen inga bibliotek utan prototyper men kallas i dagligt tal bibliotek LÄGG TILL I EX: #include <iostream.h> 9
Variabler En variabel har ett Namn t ex summa, x, efternamn ett Värde t ex 5, 7.2, ”karlsson” en Typ t ex heltal, decimaltal, sträng en Position i minnet En konstant har också namn, typ och position men ett värde man inte kan förändra Rita på tavlan: Minne, ett värde i minnet, ett namn och en referens till minnet 10
Typer Anges med nyckelord Några av typerna: Svenska Engelska C++ int Heltal Integer int Flyttal (decimaltal) Floating point number float Tecken (t ex en bokstav) Character char PÅ TAVLAN: int tal = 7; float kvot = 3.6; char bokstav = ’a’; 11
Programexempel #include <iostream> main() { int tal; //Variabeln tal deklareras som heltal cout << "Mata in ett tal: "; //Text skrivs ut cin >> tal; //Värdet på tal läses in cout << tal; //Värdet på tal skrivs } Mata in ett tal: 5 5 Utskriften blir: 12
Programexempel #include <iostream> main() { int tal; //Variabeln tal deklareras som heltal cout<<"Mata in ett tal: "; //Text skrivs ut cin>>tal; //Värdet på tal läses in cout<<"Du matade in: "<<tal <<endl; //Värdet på tal skrivs ut } Mata in ett tal: 5 Du matade in: 5 Utskriften blir: 13
Operatorer Olika sorters operatorer, t ex aritmetiska t ex + - / * tilldelning = jämförelse t ex < > == andra t ex >> ( ) [ ] Tilldelning har vi sett på tavlan int tal = 7; int tal1, tal2, summa; tal1 = 5; tal2 = 3; summa = tal1 + tal3; //summa är 8 14
Programexempel //Addera två tal #include <iostream> main() { int tal1, tal2, summa; cout << "Mata in första talet: "; cin >> tal1; cout << "Mata in andra talet: "; cin >> tal2; summa = tal1 + tal2; cout << tal1 << ” + ” << tal2 << ” = ” << summa << endl; } Utskriften blir: Mata in första talet: 10 Mata in andra talet: 4 10 + 4 = 14 15
Köra program Spara programmet i en fil: <filnamn>.cc Kompilera (översätt till maskinkod) g++ <filnamn>.cc Starta programmet: ./a.out Skriv ex på tavlan: Tex spara: addera.cc Kompilera: g++ addera.cc Säg att prg döps till a.out om inget annat anges Berätta att ./ endast är för att ange vilken katalog vo står i 16
Köra program forts Man kan själv bestämma vad programmet ska heta g++ -o <namn> <filnamn>.cc tex g++ -o add addera.cc Starta programmet: ./add 17
Skärmdump på addera 18
Operatorer Olika grupper av operatorer De vanligaste grupperna: aritmetiska t ex + - / * tilldelning t ex = inkrement/dekrement t ex ++ -- jämförelse t ex < > == logiska t ex ! && Olika prioritet t ex så har * högre prioritet än + Se appendix A i Deitel 19
Aritmetiska operatorer Fig. 1.10 i Deitel 20
Prioritet för Aritmetiska operatorer +, -, * och / fungerar på samma sätt som i matematik vad gäller prioritet t ex 5 + 3 * 2 = 11 (5 + 3) * 2 = 16 4 + 6 / 2 = 7 (4 + 6) / 2 = 5 Fig. 1.11 i Deitel 21
Division och Modulus Division med heltal (integer) 9 / 2 = 4 8 / 3 = 2 Division med flyttal (float) 9 / 2 = 4.5 8 / 3 = 2.667 Modulus: ger resten vid en heltalsdivision 9 % 2 = 1 (9 / 2 = 4 + resten 1) 8 % 3 = 2 (8 / 3 = 2 + resten 2) Modulus brukar anses svårt, förklara även på tavlan, skriv ex och fråga klassen vad det blir 22
Tilldelningsoperatorer Vanlig tilldelning: = tal1 = 5; summa = tal1 + 5; ”Höger–till–vänster” association Tilldelning med addition: += tal1 += 2 är samma som: tal1 = tal1 + 2 tal1 = 5; tal1 += 2; samma som: tal1 = 5 + 2; Finns även -=, *=, /= och %= 23
Inkrement/Dekrement operatorer Ökar respektive minskar en variabel med 1 a = 5 ; a++; //a = 6 b = 4 ; b--; //b = 3 Spelar roll om de står före eller efter a++ är inte samma sak som ++a 24
Inkrement/Dekrement forts ++a returnerar värdet av a + 1 a++ returnerar värdet av a Ex: a = 2, b = 2; c = ++a * 5; //a = 3, c = 15 d = b++ * 5; //b = 3, d = 10 Förklara på tavlan också! ++a ger 2+1 = 3 och sedan gånger 5 = 15 b++ ger 2 och sedan gånger 5 = 10 och så ökar vi på b också 25
Jämförelseoperatorer Jämförelse om lika eller ej: == resp != a == b a == 3 a != c a != 5 OBS! ett = används för tilldelning, för jämförelse använd två == Vid jämförelse av flyttal, titta på skillnaden mellan två tal, använd inte == eller != Jämförelse om större/mindre än eller lika a < 7 b <= 3 c > 2 c >= 5 SKRIV: Float tal1 = 7.2 Om tal1 == 7.2 nej Om tal1 – 7.2 mindre än 0.00001 ja! Pga att datorn räknar numeriskt Vad säga mer?? 26
Jämförelseoperatorer forts Fig. 1.13 i Deitel 27
Logiska operatorer Samma som i matematik Logiskt ”icke” (NOT): ! Logiskt ”och” (AND): && Logiskt ”eller” (OR): || Kan kombineras med andra operatorer Exempel: a == 3 && b > 9 c <= 7 || d > 5 28
Teckenuppsättningar Olika standarder, tex Ascii, unicode Varje tecken representeras av ett heltal tex A = 65 29
Del av Acsii Charcter Set 1 2 3 4 5 6 7 8 9 < = > ? @ A B C D E F G H I J K L M N O P Q R S T Y V W X Z [ \ ] ^ _ ´ a b c 10 d e f g h i j k l m 11 n o p q r s t u v w 12 x y z { | } ~ del 30
Ascii exempel char teck1 = 'a', teck2 = 'G'; cout << teck1 << " " << static_cast<int>(teck1) << endl; teck2++; cout << teck2 << endl; a 97 H Utskriften blir: 31
Kommentarer till exemplet teck1 och teck2 är variabler av typen char kan bara innehålla ett enda tecken A = 65, G = 71, H = 72, a = 97, b = 98 osv ++ operatorn fungerar på char och det gör även -- static_cast<int> (teck1) ger ett tillfälligt heltalsvärde som skrivs ut, Deitel kap 21.3 Exempel på tavlan också – visa ascii-tabellen igen 32
Siffrors ASCII-värden Siffersymbolerna 0, 1, 2, …, 9 har ASCII-värden 48, 49, 50, …, 57 Om man har en siffra i form av en char fås värdet på följande sätt: char siffra = ’4’; int varde; varde = siffra - ’0’; // 52 - 48 blir 4 33
Design av program Namngivning Konstruera med pseudokod och diagram Konstruktion före kodning ger Bättre struktur Lättare att programmera Lättare att hitta fel 34
Namngivning Bra, logiska namn åt variabler, konstanter och andra programdelar gör koden lätt att förstå Variabler: gemener i början och versaler vid nytt ord, inte å, ä och ö summa, sistaPos, fornamn 35
Pseudokod Programkod som skrivs för att bara förstås av människor - använd vanlig svenska Pseudokod: Be användaren mata in ett tal Ta emot ett inmatat tal och spara det Skriv ut det inmatade talet C++ kod: #include <iostream> main() { int tal; cout << "Mata in ett tal: "; cin >> tal; cout << tal; } 36
Diagram Visa grafiskt hur ett program fungerar Många olika typer av diagram tex flödesdiagram, JSP Vi kommer att använda den typ av flödesdiagram som används i boken 37
Flödesdiagram Start och slut representeras med en cirkel Operationer (händelser) representeras med en rektangel Start Operation Slut 38
Alla program byggs av: Sekvens – operationer utförs i följd Selektion – villkor styr programvägar Iteration – upprepning, slinga i koden 39
Sekvens Satserna utförs i den ordning de står i koden De exempel vi sett hittills har varit sekventiella Deklarera tal Skriv ut text Läs in tal Skriv ut tal #include <iostream> main() { int tal; cout << "Mata in ett tal: "; cin >> tal; cout << tal; } Tex koka kaffe, häll i vatten, mät upp kaffe, tryck på knappen, händelser som sker efter varandra 40
Selektion
Selektion Villkor styr exekveringen, dvs vilka vägar programmet tar Villkor kan evalueras till sanna eller falska 10 kronor är mer än fem kronor sant jag är längre än Michael Jordan falskt Tre varianter if/else switch villkorsoperaton ?: Hur kan man härleda till kaffe-ex på ett vettigt sätt? 42
Selektion exempel om minimum poäng på en tenta för att få godkänt är 60 om studentens poäng är högre än eller lika med 60 studenten är godkänd Om villkoret är sant så är studenten godkänd Om villkoret är falskt så är studenten inte godkänd 43
Selektion exempel Om villkoret är sant så skrivs ”Godkänd” ut om studentens poäng är högre än eller lika med 60 Skriv ut “Godkänd” Om villkoret är sant så skrivs ”Godkänd” ut Om villkoret är falskt så görs ingenting C++ kod: grade >= 60 true if ( grade >= 60 ) cout << “Passed”; print “Passed” false Fig. 2.3 i Deitel 44
Flödesdiagram Sekvens/Selektion Tidigare exempel på sekvens Deklarera tal Skriv ut text Läs in tal tal >= 0 Skriv ut: ”Talet är positivit” sant falskt Exempel på selektion Deklarera tal Skriv ut text Läs in tal Skriv ut tal 45
Exempel med Sekvens/Selektion Tidigare exempel på sekvens Exempel på sekvens med if-sats #include <iostream> main() { int tal; cout << "Mata in ett tal: "; cin >> tal; cout << tal; } #include <iostream> main() { int tal; cout<<"Mata in ett tal: "; cin >> tal; if (tal >= 0) cout<<“Talet är positivt”; } 46
if / else tre varianter, den vi sett hittills: villkor kan bli sant eller falskt satser kan vara en eller flera, vid flera avgränsa med { } if (villkor) satser if (villkor) { sats 1 … sats n } 47
Varianter på if / else if (villkor) satser if (villkor 1) satser 1 … else if (villkor n) satser n else satser n+1 if (villkor) satser 1 else satser 2 Säg att if – else if – else kan uppnås med nästlade if -satser 48
Selektion exempel Om villkoret är sant så skrivs ”Godkänd” ut om studentens poäng är högre än eller lika med 60 Skriv ut “Godkänd” annars Skriv ut “Underkänd” Om villkoret är sant så skrivs ”Godkänd” ut Om villkoret är falskt så skrivs ”Underkänd” ut 49
Selektion exempel C++ kod: if ( grade >= 60 ) true false print “Failed” print “Passed” grade >= 60 Fig. 2.4 i Deitel C++ kod: if ( grade >= 60 ) cout << “Passed”; else cout << “Failed”; 50
Nästlade if/else - satser Om vi lägger till ”Väl Godkänd” (90 eller mer) betyg >=60 true false Skriv ut: ”Underkänd” betyg >=90 false true Skriv ut: ”Godkänd” Skriv ut: ”Väl Godkänd” 51
Nästlade if/else - satser Exemplet uttryckt med text: om studentens poäng är högre än eller lika med 60 //studenten är godkänd men kolla om VG om studentens poäng är högre än eller lika med 90 Skriv ut ”Väl Godkänd” annars Skriv ut ”Godkänd” Skriv ut ”Underkänd” 52
Nästlade if/else - satser Exemplet uttryckt med kod: if ( betyg >= 60 ) { if ( betyg >= 90 ) cout << “Väl Godkänd”; else cout << ”Godkänd”; } cout << “Underkänd”; 53
Nästlade if/else - satser Enklare sätt att göra på: om studentens poäng är högre än eller lika med 90 Skriv ut “Väl Godkänd” eller om studentens poäng är högre än eller lika med 60 Skriv ut “Godkänd” annars Skriv ut “Underkänd” Var noga med ordningen Ordningen, ställ frågan ”Vad händer om vi byter plats på första och andra villkoret”? Rita och förklara på tavlan. Poängtera ändå att det finns många tillfällen när man inte bör använda else if utan använda nästlade if-satser istället 54
Nästlade if/else - satser if ( betyg >= 90 ) cout << “Väl Godkänd”; else if ( betyg >= 60 ) cout << “Godkänd”; else cout << “Underkänd”; C++ kod: betyg >=90 falskt sant betyg >=60 falskt sant Skriv ut: ”Väl Godkänd” Skriv ut: ”Underkänd” Skriv ut: ”Godkänd” 55
Exempel på Selektion med if #include <iostream> main() { int tal; cout<<"Mata in ett tal: "; cin>>tal; if ( tal > 0 ) cout<<“Talet är positivt”; else if ( tal < 0 ) cout<<“Talet är negativt”; cout<<“Talet är 0”; } 56
Exempel på Selektion med if #include <iostream> main() { int tal; cout<<"Mata in ett tal: "; cin>>tal; if ( tal > 0 ) cout<<“Talet är positivt”; else if ( tal < 0 ) cout<<“Talet är negativt”; else cout<<“Talet är 0”; } 57
Selektion - switch switch (uttryck) { case värde1: satser1; break; … case värdeN: satserN; break; default: satser; } måste vara char, int eller enum, kan inte använda jämförelse Poängtera att man inte kan skriva tex a > 5 58
Exempel på switch Kapitel i en bok För varje kapitel finns en titel och ett nummer om kapitel är 1 skriv ut ”Introduction” om kapitel är 2 skriv ut ”Control Structures” om kapitel är 3 skriv ut ”Functions” ... annars skriv ut ”kapitlet finns ej” Som ni ser kan man göra detta med if-satser också 59
Exempel på switch sant Skriv ut ”Introduction” kapitel 1 break falskt ”Control Structures” kapitel 2 break falskt Skriv ut ”Functions” kapitel 3 break falskt Skriv ut ”kapitlet finns ej” 60
Exempel på switch #include <iostream> main() { int kapitel; cout << "Mata in ett kapitel: "; cin >> kapitel; switch(kapitel) case 1 : cout<< “Introduction”; break; case 2 : cout<< “Control Structures”; break; case 3 : cout<< “Functions”; break; … default: cout<<“kapitlet finns ej”; } //slut switch }//slut programmet Int används ! 61
Exempel på switch Barn som lär sig alfabetet För varje bokstav skrivs ett ord ut, tex a ger apa, b ger björn, c ger cykel om bokstaven är a skriv ut ”apa” om bokstaven är b skriv ut ”björn” om bokstaven är c skriv ut ”cykel” ... annars skriv ut ”finns ej i alfabetet” 62
Skriv ut ”finns ej i alfabetet” Exempel på switch sant bokstav a Skriv ut ”apa” break falskt bokstav b Skriv ut ”björn” break falskt bokstav c Skriv ut ”cykel” break falskt Skriv ut ”finns ej i alfabetet” 63
Exempel på switch #include <iostream> main() { char bokstav; cout << "Mata in en bokstav: "; cin >> bokstav; switch(bokstav) case ‘a’ : cout<< “apa”; break; case ‘b’ : cout<< “björn”; break; case ‘c’ : cout<< “cykel”; break; … default: cout<<“finns ej i alfabetet ”; } //slut switch }//slut programmet Char används 64
Iteration
Iteration Repetition, upprepning, slinga Vardagsexempel: så länge ingen svarat när jag ringer ring upp igen så länge det finns sidor kvar i min bok läs sidan vänd blad så länge jag inte nått slutet på skivan lyssna på nästa låt 66
Iteration forts villkor evalueras till sant eller falskt fortsätter så länge villkoret är sant satser kan vara en eller flera, vid flera inneslut med { } tre olika varianter: while do/while for 67
while while (villkor) satser while – så länge villkoret är sant Villkoret kan se ut på många sätt counter > 0 val != 0 68
Exempel while Leta rätt på det första talet 2x som är större än 1000 Pseudokod: initiera produkten till 2 Så länge som produkten är mindre än eller lika med 1000 multiplicera produkten med 2 69
Exempel while C++ kod: int product = 2; while ( product <= 1000 ) product = 2 * product true false Fig. 2.4 i Deitel int product = 2; while ( product <= 1000 ) product = 2 * product; C++ kod: 70
Exempel while C++ kod: int tal = 10; while ( tal > 0 ) { Skriv ut talet Minska talet sant falskt C++ kod: int tal = 10; while ( tal > 0 ) { cout << tal; tal = tal -3; } Vad blir utskriften RITA på tavlan: 10, 7, 4, 1 Vad blir utskriften om vi sätter tal = 9 RITA på tavlan: 9, 6, 3, och inte 0 71
Iteration – samtliga varianter Initialt värde för kontroll-variabeln, tal = 10 Villkoret som testar om slutvärdet för kontroll-variabeln har uppnåtts tal > 0 Öka eller minska kontroll- variabeln tal = tal – 3 Slutvärdet måste kunna uppnås! Exempel int tal = 10; while(tal>0) { cout<< tal; tal= tal-3; } Poängtera att dessa saker gäller för all typ av iteration 72
do/while testar villkoret efter loopen utförs alltid minst en gång do satser while (villkor) ; OBS! 73
Exempel do/while C++ kod: int tal = 10; do { cout << tal; tal = tal -3; } while ( tal > 0 ); Skriv ut talet Minska talet tal > 0 sant falskt Vad blir utskriften RITA på tavlan: 10, 7, 4, 1 Vad blir utskriften om vi sätter tal = 9 RITA på tavlan: 9, 6, 3, och inte 0 Jämfr med OH med while (56) 74
for-loop for(uttryck1 ; uttryck2 ; uttryck3) Satser Uttryck1 – initierar loop-variabeln Uttryck2 – kontrollerar om loopen är klar Uttryck3 – förändrar loop-variabeln Lägg på OH med ”Viktiga saker att tänka på” igen och visa att for-loopen byggt in alla dessa tre saker 75
for-loop: initialt värde Initialt värde – man kan använda en variabel som är deklarerad tidigare eller deklarera en ny som endast används i loopen for(summa = 0; …. for(int antal = 5; 76
for-loop: kontroll Ska vara ett villkor som evalueras till sant eller falskt for(summa = 0; summa < 20; … for(int antal = 5; antal > 0; … Måste vara ett villkor som kan bli falskt så att vi inte fastnar i en oändlig loop 77
for-loop: förändring av variabeln Förändring av loop-variabeln så att slutvillkoret kan uppnås Inkrement eller dekrement for(summa = 0; summa < 20; summa++) for(int antal = 5; antal > 0; antal--) Kan förändras med flera steg for(sum = 0; sum < 20; sum = sum + 4) Vanligt ex: for(int i = 0; i < MAX; i++) 78
Exempel for-loop C++ kod: int tal; Skriv ut talet Minska talet sant falskt tal = 10 C++ kod: int tal; for(tal = 10; tal >10; tal = tal – 3) { cout << tal; } Vad blir utskriften RITA på tavlan: 10, 7, 4, 1 Vad blir utskriften om vi sätter tal = 9 RITA på tavlan: 9, 6, 3, och inte 0 79
Modularitet
Modularisering Enklare att: Konstruera Koda Testa Underhålla 81 50 rader styck 900 rader 81
Moduler Varje modul kan vara En funktion per fil (*.cc) Flera funktioner i en fil (*.cc) Definitioner av biblioteksfunktioner (*.h) 82
Funktion ”Gå och skriv ut den här strängen på skärmen!” ”Räkna ut hur mycket det här talet i kvadrat är, och ge mig tillbaka svaret!” ”Vänta tills någon har skrivit på tangentbordet och ge mig tecknet!” ”Dela upp den här strängen i smådelar och lägg varje del i den här vektorn!” 83
Vad är en funktion i C++? Ett separat ”program” som (kanske) får indata från huvudprogrammet (inparametrar) (kanske) använder indata till att utföra något eller beräkna något (kanske) ger utdata tillbaka till huvudprogrammet (utparametrar) (kanske) returnerar ett värde … men något bör funktionen göra! 84
Exempel s = sin(a); e = pow(s, 2); h= sqrt((sin(a)+tan(b)); funktion parameter parametrar Exempel på anrop av standardfunktioner. Visa på att flera parametrar ges med komma emellan. parameter 85
Exempel /* definition */ int kvadrat(int x){ return x*x; } ... returvärdets typ /* definition */ int kvadrat(int x){ return x*x; } ... /* anrop */ a= 25 + 2 * kvadrat(15) inparameterns typ formell parameter Diskutera kring begreppen i bilden och säkerställ att alla förstått. Ge flera exempel på tavlan om så behövs. Detta är mycket viktigt. Berätta att alla funktioner måste deklareras (definieras) innan de används eller anropas. Om någon student undrar, förklara hur funktionsprototyper används, annars utelämnas dessa. Poängtera skillnaden mellan aktuell och formell parameter. aktuell parameter 86
Returvärden Deklarera typ Ge returvärde i return-sats Om inget returvärde ges, deklarera typen void Om parametrar saknas, skriv void void skrivut(int x){ cout << ”Värde på x = ” << x << ” Värdet från totalValue = ” << totalValue() <<endl; } int totalValue(void){ int sum = 42; return sum; Översätt engelskans ”void” till svenska ”tom”. Lägg emfas på att verkligen använda void då inget returvärde ges. (Nämn inte ens att int är defauilt returvärde!) Kommentera gärna att parentesen kring ”i+1” är en säkerhet som säkerställer i vilken ordning saker och ting görs, return är inte en funktion som behöver dessa parenteser. I bilden ges exempel på en funktion som har returvärde men ingen parameter och en funktion som tar en parameter men inte har något returvärde. Det finns en skillnad mellan C och C++ här: C++: foo() betyder ”inga parametrar” C++: foo(void) betyder också ”inga parametrar” C++: foo(...) betyder ”obestämt antal parametrar” C: foo() betyder ”obestämt antal parametrar” C: foo(void) betyder ”inga parametrar” 87
Lokala variabler Funktionen är en skyddad verkstad, där du kan ha variabler som inte syns utanför float fishy(int x){ int i; float temp=0; for(i=1;i<x;i++) { temp= temp+sin(1/i); } return temp; lokala variabler (Exemplet är krystat, jag ser gärna ett bättre! /Per) Lokala icke-statiska variabler skapas vid anrop av funktionen och förstörs vid returhopp. Ge gärna följande exempel på användning av en statisk variabel: void counter(){ static int antal=0; antall++; printf(”anropad %d gång(er)\n”, antal); } counter(); Detta ger utskriften anropad 1 gång(er) anropad 2 gång(er) osv Om vi tar bort ”static” ger det osv. 88
Lokala variebler void a(float x){ int y; for(y=0;y<100;y++) ... } Blanda inte ihop funktionens lokala variabler med de utanför! void a(float x){ int y; for(y=0;y<100;y++) ... } float y=4.56; int x=0; a(y); Inte samma ”y”! Detta kommer att förvirra, men vill klargöra att funktionen har ett eget namnuniversum. Om namnet finns både i och utanför funktionen gäller alltid den inre definitionen. Detta gäller universellt. Inte samma ”x”! 89
Inparametrar Räkna upp dem med typ, hur många som helst Värdet av inparametrar skickas in funktionen Inparametrar kan inte ändras av funktionen, så att det syns utanför Klargör att det egentligen inte finns något i C som heter inparametrar, det är just värdeanropet som gör dem till icke förändringsbara och därmed kan de endast användas till inparametrar. 90
Utparametrar Skicka en låda med snöre till funktionen att lägga värden i &-tecken framför parametern i funktionen void dubbel(int x, int & ){ y = x + x; } y Lådan med snöre är tänkt att beskrivas så här: ”För att funktionen ska kunna förändra en variabel måst vi skicka hela variabeln, inte bara värdet av den, till funktionen. För att vi ska hämta tillbaka den, fäster vi ett snöre i lådan så att vi så att säga kan släpa den tillbaka när funktionen är färdig med den. För att markera att det är en låda vi skickar, markeras variabeln med ett &-tecken. Inuti funktionen markeras lådan dock med en asterisk.” Liknelsen haltar givetvis, snöret är ju ingen riktig bra avbildning av en adress, men det kan kanske underlätta för någon. Låt liknelsen sjunka in och beskriv sedan vad det egentligen är som händer: ”*y” blir ett duplikatnamn på ”resultat” därför att adressen till resultat-variabeln skickas till funktionen. Rita gärna en bild på tavlan som föreställer y med en adress i som pekar på cellen resultat, och beskriv att ”*y” hoppar direkt till minnescellen resultat. Lugna studenterna om de tycker detta är krångligt och betona i stället regeln som anges i andra punkten i bilden. dubbel(15, resultat); 91
Anropssätt Vid anrop av en funktion kan man skicka med: Parametrarnas värden ”Call by value” Parametrarnas adresser ”Call by reference” Det finns ett antal olika sätt att anropa funktioner och sätta parametrar som vi sett. Vi kommer att behandla fler, men dessa tre är de viktigaste. Det är bra att komma ihåg deras engelska namn, de svenska varierar. 92
Call by value Den enklaste Räkna ut (evaluera) parametrarna och sätt parametrarna till dessa värden i funktionen Parametrarna kan ändras i funktionen men det syns inte utanför Användning: inparametrar Denna och nästa OH är mycket viktig, lägg ordentligt med tid här. Skriv upp följande exempelprogram på tavlan. void plus(int t){ t= t+1; } ... int apa; apa= 42; plus(apa); printf(”%d\n”,apa); plus(apa+12); Stega igenom programmet och rita variablerna apa och t som lådor. Skriv in värdena i lådvariablerna och sudda i lådorna vartefter. Gör detta noggrant och poängtera vikten av att förstå. 93
Call by reference Använder ”samma” variabler i funktionen som utanför Adressen skickas (istället för värdet) Ändring av variabelvärden syns utanför Används för utparametrar I C++ uttrycks detta med & framför formella parametern i listan, f.ö. som värdeanrop (I C uttrycks detta som ”*” i parameterlistan och i funktionen; ”&” i anropet.) Texten nedan gäller endast C, modifiera för C++! Ge samma exempel som nyss, men modifiera för referensanrop, berätta vad som måste ändras: funtkionsparamtern deklareras och används med stjärna anropet ska ha ett och-tecken (använd uttrycket ”adress för”) void plus(int * t){ *t= *t+1; } ... int apa; apa= 42; plus(&apa); printf(”%d\n”,apa); Stega igenom programmet och variablerna apa och t som lådor (samma låda! rita etiketten t och en pil till apa-lådan så att man ser att det är sama variabel). Skriv in värdena i lådvariablerna och sudda i lådorna vartefter. Gör detta noggrant och poängtera vikten av att förstå. Fråga studenterna vad de tror händer med detta anrop! plus(apa+12); 94
Dela upp filer
Allt i ett #include <iostream.h> void funk1() { ... } int main() { funk1(); funk2(); } 96
Problem vid kompilering #include <iostream.h> void funk1() { funk2(); } void funk2() { funk1(); } int main() { funk1(); funk2(); } 97
Lösning Infoga prototyper #include <iostream.h> void funk1(); { ... } void funk2() int main() { .. 98
Separat h-fil #include <iostream.h> const int ANTAL = 10; // event konstanter void funk1(); // funktionsprototyper void funk2(); Sparas som exempelvis funktioner.h 99
cc.fil inkluderar h-fil #include ”funktioner.h” void funk1() // funktionsdefinitioner { ... } void funk2() int main() { funk1(); funk2(); } 100
Kompilering
Programdelar Förbearbetning inkluderar hela filer #include <strings.h> #include ”minafunktioner.h” #include ”lib/fintlib.h” standardbibliotek söks efter på standardställen egen programkod söks efter ”bredvid” huvudprogrammet Beskriv att förbearbetningen utförs av vad som oftast kalla en preprocessor Nämn skillnaden mellan hakar och citattecken: hakar används då man inkluderar standardbibliotek, citattecken för ”egna” filer, men notera att allt dessvärre är beroende av implementation. Egna filer eftersöks i aktuell katalog, inte nödvändigtvis i samma katalog som huvudprogrammet. Det går fint att lägga filerna i egen katalog, se exemplet i figuren. Berätta att inkluderingen (tillsammans med andra #-direktiv) utförs innan kompileringen börjar. 102
Kompilera? Källkod kompileras till objektkod objektkod länkas till körbart program Steget 2. görs automatiskt om ”main” finns i källkoden Kompileringen kan tydas som att översätta från text till (körbar) programkod. Berätta att denna del av programutveckling är mycket beroende av vilken dator (OS) som används, men att exemplen är Unix. 103
Länka in bibliotek Systemfunktioner (printf, sin,etc) kan finnas i operativsystemet Undvik direktanrop till OS:et C:s standardbibliotek #include <finfil.h> Ett specialbibliotek #include <annanfinfil.h> gcc fintprog.c -lbiblioteksnamn Unix OS har ett antal ganska råa funktioner. clib som har lite mer lättanvända versioner av dessa funktioner. clib länkas med som standard, men inluderingsfiler kan behövas. Mansidorna berättar vilka inkluderingsfiler som behövs. man 2 intro ger information om os-anropen man 3 intro ger info om anropen i clib och dess släktingar Om man vill använda funktioner som inte finns i clib måste ett bibliotek länkas med. Två svårigheter finns: Dessvärre visar inte alltid mansidan vilket bibliotek som behövs ”-l” måste anges sist. Detta beror på att länkaren inte vet vilka symboler som behöver lösas upp. 104
Exempel dubbel.c innehåller funktionen dubbel program.c innehåller huvudprogram som anropar ”dubbel” Kompilera dubbel.c och bilda dubbel.o: $ gcc -c dubbel.c Kompilera program.c och länka med dubbel.o: $ gcc -o prog program.c dubbel.o $ ./prog 5 dubblerat blir 25 ”$” antyder kommandotolk i Unix. ”gcc” är Gnus c-kompilator –c förhindrar länkningssteget –o namnger utfilen gcc tolkar .c-filer som källkod som måste kompileras och .o-filer som ska skickas till länkaren för ihoplänkning til färdigt program. Berätta att detta kan göras i (mycket) stor skala, det är vanligt med hundratals .o-filer som kompileras för sig när de ändras och länkas ihop till ett färdigt program. Visa bilden med de 18 programdelarna igen och berätta att man kan kompilera om bara de delarna som förändras. 105
Make Kompilera bara det som behövs Svårt att veta exakt vad som måste kompileras om Lösningen heter make Komplett syntax, se t.ex. http://www.gnu.org/manual/make-3.79.1 Make behövs så fort programmet upptar mer än några få c-filer. Man måste givetvis inte ha det, man kan kompilera om allt varje gång, men det spar tid. Berätta om att många program, speciellt i unixvärlden, kommer komplett med en makefil som fungerar som bygginstruktion. Dessa makefiler måste typiskt modifieras för att passa den lokala omgivningen. Unix svar på Windows setup-dialoger. 106
Ett exempel # Kommentar prog : program.o dubbel.o cc -o prog program.o dubbel.o program.o: program.c funk.h cc -c program.c dubbel.o: dubbel.c funk.h cc -c dubbel.c prog består av: program.c och dubbel.c, i kompilerad form program.c och dubbel.c inkluderar funk.h Obs! <TAB> Rita på tavlan de två programmen dubbel.c och program.c, åtminstone de viktiga delarna. program.c: #include <stdio.h> #include "funk.h" int main () { int k,l; l=5; dubbel(l,&k); printf("%d dublerat är %d\n",l,k); } dubbel.c: void kvadrat(int x, int * y){ *y= x + x; funk.h void dubbel(int x, int * y); (här finns andra funktionshuvuden) Beskriv följande Kommentarer är allt som början med ”#” prog beror direkt av objektfilerna, inte källfilerna objektfilerna, däremot beror av källfilerna och ev. inkluderingsfiler kommandoraden måste börja med ett TAB-tecken 107
Kör make $ make cc -c program.c cc -c dubbel.c cc -o prog program.o dubbel.o <ändra program.c, kör igen> $ make cc -c program.c cc -o prog program.o dubbel.o $ make make: ‘prog' is up to date. Första gången vi kör make är prog, dubbel.o och program.o gamla, så vi måste skapa om dem. När vi ändrat i program.c behövs bara den koden kompileras om och länkas ihop med den färska k.o Fråga studendetrna vad som händer om vi ändrar i funk.h: vad måste då göras? 108
Make syntax <mål>: <komp. målet beror av> ... <TAB> <kommando> <TAB> <kommando> <mål>: <komp. målet beror av> ... <TAB> <kommando> <TAB> <kommando> ... Diskutera vad mål och komponent kan vara. Utifrån tidigare OH bör studenterna kunna ge egna exempel. Ett mål är typiskt en fil som skapas av ett program, eller något som ska utföras (”phoney target”). 109
Genvägar i make ”cc –c <prog>.c” behöver inte skrivas ut överallt: .SUFFIXES: .o .c .c.o: cc -c $*.c ”:SUFFIXES” betyder att punkt-o och punkt-cfiler ska behandlas separat och regeln därefter säger att .o skapas ur .o med kommandot. dollar-stjärna ersätts av namnet före suffixet. Vårt exempel kan bli litet kortare (om man undantar att vi måste skriva reglerna) prog : program.o k.o cc -o prog program.o k.o program.o: program.c funk.h k.o: dubbel.c funk.h Notera att vi fortfarande måste ha ett kommand för att skapa ”prog”, namnet har ju inget suffix och det går inte enkelt att skapa en regel för dylika fall. Notera också att vårt exempel är för litet för att visa på vinsterna med dylika regler, men exemplet är litet för att inte skymma sikten. Egentligen behövs inte ens denna regel, make vet hur man kompilerar c-program, men det är ett pedagogiskt exempel på en regel. 110
Finesser Variabler Kommandon utan villkor (pseudomål) OFILES = program.o dubbel.o CCFLAGS = -c -static -ansi ... prog: $(OFILES) gcc $(CCFLAGS) -o prog $(OFILES) clean: rm $(OFILES) Berätta att man typiskt gör så här i stora system för att slippa pilla inuti makefilen, ändringar görs typiskt bara genom att lägga till eller ta bort i fillistor eller kompileringsflaggor. Variabler får heta vad som helst, men konventionen säger versaler av enkelt alfabet Objektet ”clean” kommer inte att skapas om man gör denna makefil, det finns ingen koppling. I stället måsta men explicit köra ”make clean” för att tvinga make att försöka skapa objektet och därmed exekvera kommandot. Pseuodmål (clean i detta fall) kan deklareras om så önskas, ifall risken finns att det finns en fil med detta namn. Detta görs i så fall med syntaxen: .PHONY: <målnamn> 111
Fördefinierade variabler $@ Namnet på aktuellt mål, inklusive suffix. $* Namnet på aktuellt mål, utan suffix. $? De komponenter som är nyare än målet. $< Den första villkorskomponenten. 112
Och sen då? Använd make! Modifiera en befintlig makefile från nätet om du tycker att det är för besvärligt att bygga en egen. Ta hjälp av google.com, ”Groups”-avdelningen, sök på ”make” + något vettigt Denna bild ska försöka gjuta mod i de studenter som tycker att make är skrämmande. Uppmana dem att söka, make är för kraftfullt för att bli oanvänt. 113
Typer
Typer vi använt i kursen typ möjliga värden int heltalsvärden, t ex -2, 0, 8, 356 float värden med decimaler, t ex 0.75, -7.86 char ett enda tecken, t ex ’A’, ’n’, ’9’, ’+’ 115
C++ inbyggda typer (1) I C++ finns många datatyper och dessa har dessutom en inbyggd hierarki från högsta till lägsta. Typerna är i ordning long double double float unsigned long int long int unsigned int 116
C++ inbyggda typer (2) int unsigned short int short int unsigned char bool Se Fig. 3.5 i Deitel 117
Minneskrav Varje variabel av en viss typ kräver ett visst antal bytes som minnesutrymme, men det är systemberoende och kan undersökas med operatorn sizeof: int tal; cout << ”tal behöver ” << sizeof(tal) //tal eller int << ”bytes” << endl; long int >= int >= short osv gäller för sizeof 118
Operationer med olika typer Man skall undvika att blanda olika typer men ibland är det oundvikligt. Då kommer den med högst prioritet att dominera. Problem ? Resultatet är systemberoende int a = 5, sum1, sum2; float b = 5.9, c = 5.9E15, fsum; sum1 = a + b; // Problem ! sum2 = c; // Problem !! fsum = a + c; // OK 119
Möjliga värden De typer som är unsigned kan lagra tal från 0 och upp till ett maximalt tal som är beroende på antalet bytes som typen använder De som inte är unsigned kan lagra både negativa och positiva tal bool kan bara antaga två värden false = 0 och true = 1 Läs om max- och minvärden i /usr/include/limits.h (climits) resp float.h (cfloat) 120
Kontraktsprogrammering
Programmera med kontrakt Samma som i vardagen Två parter (minst), bägge följer sin del Vi ska börja med att titta på lite exempel på sådana exempel ur vardagen Be studenterna ge exempel 122
Bilköp Krav Förtjänst Kund Betala varje månad Få en bil Försäljare Ge kunden en bil och serva den en viss tid Få pengar varje månad En person (kunden) köper en bil på avbetalning hos en bilfirma. Kunden förbinder sig att betala en viss summa varje månad, i gengäld får kunden en bil. Bilfirman förbinder sig att ge kunden en bil, och serva den under viss en tidsperiod, i gengäld får firman pengar varje månad. Om kunden inte betalar vet man inte vad som händer, firman kanske hämtar hem bilen eller ringer kronofogden. Om firman inte ger kunden någon bil eller låter bli att serva den får han Sverker på halsen. 123
Boka biljett Krav Förtjänst Resenär Betala biljetten och vara på flygplasten i tid Få åka till Hawaii Resebyrå Flyga resenären till Hawaii Få pengar En person (resenären) bokar en flygresa till Hawaii Resenären förbinder sig att betala innan ett visst datum samt att infinna sig på flygplatsen minst en timme före avgång, i gengäld får resenären åka med planet till Hawaii Resebyrån förbinder sig till att ta kunden till Hawaii på bestämt datum. I gengäld får resebyrån pengar av resenären. Om resenären inte betalar i tid eller inte kommer i tid så får han inte åka med planet. Om resebyrån inte flyger ner resenären får resenären pengarna tillbaka (förhoppningsvis). 124
Två sidor av kontraktet Från ”insidan” Vad kräver jag vid anrop av mig Vad ger jag tillbaka till anroparen Från ”utsidan” Vad krävs för att anropa modulen Vad får jag tillbaka Rita på tavlan, bild av insida och utsida 125
Division Krav Förtjänst Matematiker Nämnaren får ej vara noll Får kvoten mellan täljare och nämnare Funktion för att dividera Dividera täljare med nämnare och returnera kvoten Slipper kontrollera om täljaren är noll När man utför division får nämnaren inte vara noll, en matematiker använder en funktion för att beräkna division. Matematikern förbinder sig att inte anropa funktionen med en nämnare som är noll, i gengäld får han tillbaka ett korrekt resultat som är kvoten mellan täljare och nämnare. Funktionen förbinder sig att returnera en korrekt kvot mellan täljare och nämnare, i gengäld behöver den inte kontrollera nämnaren innan den utför beräkningen. Om matematikern anropar funktionen med en nämnare som är noll så är resultatet odefinierat, dvs det kan bli vad som helst 126
Förvillkor och Eftervillkor Förvillkor – vad som ska gälla när funktionen anropas, om det inte är uppfyllt är resultatet odefinierat Eftervillkor – vad som ska gälla när funktionen är klar, under förutsättning att förvillkoret var uppfyllt Vi kan beskriva detta ur matematikerns perspektiv, dvs vad som krävs och vad han får i gengäld: Förvillkor: nämnaren får inte vara noll Eftervillkor: kvoten mellan täljare och nämnare har returnerats 127
Funktion för division //pre: nämnare != 0 //post: kvoten mellan taljare och //namnare har returnerats float dividera(float taljare, float namnare) { return taljare/namnare; } För och eftervillkor anges som kommentarer i koden och därför bryr sig kompilatorn inte om de raderna utan man tittar i koden när man vill se för- och eftervillkor för en funktion Gå igenom för och eftervillkor för exemplena med bilköp och biljett-bokningen 128
Bank-program Saldo – en variabel, hur mycket pengar vi har sattInPengar – en funktion som sätter in pengar (dvs ökar saldo) taUtPengar – en funktion som tar ut pengar (dvs minskar saldo) 129
sattInPengar & taUtPengar void sattInPengar(float &saldo, float in) { saldo = saldo + in; } void taUtPengar(float &saldo, float ut) saldo = saldo - ut; 130
Variant av taUtPengar void taUtPengar(float &saldo,float ut) { if(ut <= saldo) saldo = saldo – ut; else ? } Det är ju inte så bra om vi kan ta ut mer pengar än vi har på kontot (eller rättare sagt det är ju inte bra för banken) PÅ TAVLAN: void main() { float saldo = 0; sattInPengar(saldo, 100); taUtPengar(saldo, 200); } Vad ska vi göra om det inte finns pengar? Hur ska användaren veta om uttaget är gjort eller inte? Vi kan skicka ett returvärde från funktionen: Två sätt att lösa det, modifiera taUtPengar 131
Variant av taUtPengar boolean taUtPengar(float &saldo, float ut) { if(ut <= saldo) saldo = saldo – ut; return true; } else return false; 132
Returvärde Användaren måste kolla returvärdet: boolean togUt; togUt = taUtPengar(saldo, 200); if(togUt == false) cout << ”Du har inte tillräckligt med pengar!” << endl; 133
Kontrakt för taUtPengar Förvillkor på taUtPengar: man får inte ta ut mer än man har pre: ut <= saldo Eftervillkoret på taUtPengar: man har tagit ut pengar post: saldo har minskats med ”ut” kronor Ett enklare och BÄTTRE sätt att göra det på: Ta något annat ex på att man inte skulle försöka göra något utan att först kolla, tex när man kommer in i föreläsningssalen så tittar man ju var det är ledigt och sedan sätter man sig ner, man testar ju inte att sätta sig på en plats och ser om det går eller inte dvs om det var ledigt eller inte. Eftervillkoret på taUtPengar: då alltid att man har tagit ut pengar och man behöver inte göra någon koll i taUtPengar. 134
Kontrakt för taUtPengar //pre: ut <= saldo //post: saldo = saldo – ut void taUtPengar(float &saldo, float ut) { saldo = saldo - ut; } Kollar före anrop till funktionen taUtPengar if( saldo >= 200) taUtPengar(saldo, 200); 135
Kontrakt för sattInPengar Förvillkor på sattInPengar: man får inte sätta in en negativ summa pre: in >= 0 Eftervillkoret på sattInPengar: man har satt in pengar post: saldo har ökats med ”in” kronor Ett enklare och BÄTTRE sätt att göra det på: Ta något annat ex på att man inte skulle försöka göra något utan att först kolla, tex när man kommer in i föreläsningssalen så tittar man ju var det är ledigt och sedan sätter man sig ner, man testar ju inte att sätta sig på en plats och ser om det går eller inte dvs om det var ledigt eller inte. Eftervillkoret på taUtPengar: då alltid att man har tagit ut pengar och man behöver inte göra någon koll i taUtPengar. 136
Kontrakt för sattInPengar //pre: in >= 0 //post: saldo = saldo + in void sattInPengar(float &saldo, float in) { saldo = saldo + in; } Användaren kollar innan han anropar funktionen if( in >= 0) sattInPengar(saldo, 200); Förvillkoret för sattInPengar kan vara att man inte får sätta in en negativ summa (det skulle ju vara samma sak som att ta ut pengar) 137
Kod för ”Bankprogrammet” #include <iostream.h> //pre: in >= 0 //post: saldo = saldo + in void sattInPengar(float &saldo, float in) { saldo = saldo + in; } //pre: ut <= saldo //post: saldo = saldo - ut void taUtPengar(float &saldo, float ut) saldo = saldo - ut; 138
Kod för ”Bankprogrammet” int main() { float saldo = 0; float summaIn; float summaUt; //Insättning cout<<"Hur mycket pengar vill du sätta in?"<<endl; cin>>summaIn; if(summaIn >= 0) sattInPengar(saldo, summaIn); else cout<<"Du kan inte sätta in en negativ summa!"<<endl; //Uttag cout<<"Hur mycket pengar vill du ta ut?"<<endl; cin>>summaUt; if(summaUt <= saldo) taUtPengar(saldo, summaUt); else cout<<"Du har inte så mycket pengar på ditt konto!"<<endl; //Saldo cout<<"Du har nu “<<saldo <<" kronor på ditt konto."<<endl; return 0; } 139
Grad av pålitlighet Butik litar inte på folk, gör kreditupplysning Vi litar inte på slutanvändare – låg pålitlighet Egna programdelar – hög pålitlighet Andras programdelar – medel pålitlighet Pålitlighet Låg Hög Användare av programmet Användare av din modul Typ av användare: ”Maska bort fel” Kräv uppfyllda förvillkor Åtgärd: 140
Varför använda kontrakt Mer logisk kod Klarare ansvarsfördelning Lättare att debugga Kortare kod Mindre redundans (upprepning av samma sak) Färre fel i färdig produkt 141
Pekare
Pekare Vad är en pekare? Varför använder vi pekare? Hur används pekare? Hur deklarerar vi pekare i C? Hur kommer vi åt pekarvärdet? Alla programdelar har en minnesadress En pekare är en variabel som innehåller adressen till en annan variabel 143
Vad är en pekare ? En pekare är en variabel som innehåller adressen till en annan variabel. Se bilden ovan som ett försök att visa på att pekaren inte har något eget ”reellt värde”, utan används som en hjälp för att under programmets gång kunna referera olika minnesplatser av samma typ… 144
Varför använder vi pekare? Används i programmering bl.a. för att: länka ihop datastrukturer (se senare om poster) föra över parametervärden kunna referera olika minnesplatser dynamiskt , dvs. under körning av ett program pekare har en nära koppling till strängar Detta kan man nog skriva på ett mer pedagogiskt sätt…. 145
Pekare Alla variabler i ditt program har en adress i minnet. Denna adress kallas pekarvärde I C kan du få reda på värdet för en minnesadress med hjälp av minnesoperatorn ”&” 146
Deklaration/initiering av pekare Ex. int *ip, *ip2, i3, i4; i3 = 78; ip = &i3; &i3 Ex. int *ip, *ip2, i3, i4; /* initiering av heltalspekare och heltalsvariabler*/ i3 = 78; /* sätter värdet till 78*/ ip = &i3; /* Här sätts den andra pekaren att peka på adressen för som variabeln i3 har */ OBSERVERA att * hör till variabel namnet vid deklarationen /* Här sätts den andra pekaren att peka på adressen för som variabeln g har = referensparameter*/ Skriv exemplet på tavlan och kommentera de olika delarna ip i3 78 147
Pekare Minnesrepresentation Minnesadress Variabel 2028 78 2032 2036 i4 2040 i3 ………… ………… Minnesrepresentation av föregående OH 2088 2040 *ip 2092 *ip2 148
Användande av pekare ip2 = ip; i4 = 70; &i3 ip i3 78 ip2 70 i4 149
Användande av pekare Forts. Ex ip = &i4; i3 ip 70 ip2 78 i4 150
Pekare Vad är skillnaden mellan byt_1 och byt_2? void byt1(int *px, int *py) { int temp; temp = *px; *px = *py; *py = temp; } Exemplet går över tre sidor 151
Pekare void byt2(int x, int y) { int temp; temp = x; x = y; y = temp; } Här görs inga förändringar på originalet 152
Pekare int main() { int i, p; p = 8; i = 5; byt1(&i,&p); printf(”i = %d, p = %d \n”); byt2(i,p); } Vad blir utskrifterna ?? 153
Pekare Px: i main() p: i: i byt1() px: py: 154
Pekare Pekare som inte används bör peka på 0 varför? vilka risker finns med pekare? Används i programmering bl.a. för att: -länka ihop datastrukturer -parameteröverföring -”hjälpa” kompilatorn att generera effektivast möjliga kod Om man använder en pekare som inte initierats….. 155
Hur kommer vi åt pekarvärdet? Exempel: int main() { int *p1; int i = 7, g = 19; p1= &i; g = *p1 printf(”Värdet är %d \n”, g); } g = *p1 /*Här kommer jag åt pekarvärdet, jag får ut värdet som pekaren pekar på istället för adressen genom att använda * */ Detta tror jag kräver ytterligare ett ex. på tavlan… 156
Vektorer/Strängar
Vektorer I minnet hos datorn ligger elementen i vektorn i sekvens, dvs. efter varandra Samtliga element i vektorn måste vara av samma typ OBS! Första positionen i strängen är position 0 158
Vektorer Ex. int my_vektor[6]={3,7,19,-3,44,9}; int 3 7 19 -3 44 9 1 2 4 5 position Det namn du ger din vektor är en pekare till första positionen i vektorn 159
Vektorer Viktigt Se till att du har tillräcklig storlek på din vektor! int my_vektor[6]={3,7,19,-3,44,9,321,2}; ? my_vektor Detta leder till kompileringsfel Under körning kan detta leda till ”segmentation fault”. Det kan leda till ospecificerade fel… 2 int 3 7 19 -3 44 9 1 2 4 5 position 321 160
Vektorer/strängar En sträng är en vektor som kan lagra tecken OBS! Reservera plats för ’\0’ (strängslut) char my_vektor[6]={’O’,’l’,’l’,’e’,’\0’}; Strängslut OBS! Allokera alltid plats för ’\0’ . Detta bör förklaras, \0 lagras som ett tecken som andra, men det kan ej läsas, utan är ett ”specialtecken char ’O’ ’l’ ’l’ ’e’ ’\0’ position 1 2 3 4 5 161
Vektorer/strängar Initiering av strängar Ex: char namn[7] = {’B’,’e’,’n’,’g’,’t’}; enklare char namn[7] = ”Bengt”; char ’B’ ’e’ ’n’ ’g’ ’t’ ’\0’ position 1 2 3 4 5 6 162
Pekare och vektorer/strängar Vad har pekare och vektorer gemensamt ? När vill man använda en vektor? Hur skapar man en sträng? En vektor är en rad av förekomster av samma typ, ex. heltal, tecken, eller bilar. Den kan vara bra att använda när du har t.ex. en lång rad av värden av ex. heltal. Istället för att dessa skall lagras i separat skapade enheter av samma typ. Det går enkelt att komma åt ett värde i en vektor med indexering. Fördelar: programmering enklare, traversering enklare, sortering enklare, sökning enklare, Vektorer är viktiga inom programmering och används ofta, om man inte hade dessa att tillgå skulle det bli mycket att hålla reda på. En vektor representeras av ett pekarvärde till första elementet i strängen 163
Pekare och vektorer char *p; resp. char p[5]; Är detta samma sak, eller vad skiljer? Visa exempel på tavlan Initierad resp allokerad 164
vektorer/strängar Exempel: Vad blir utskriften av nedanstående? int main() { int test[3], i ; /* dekl. en sträng och en var */ test[1] = 5; test[2]= 77; for( i = 0; i < 3; i++) printf(”På plats %d ligger värdet %d\n”, i , test[i]); return 0; } Diskutera vad som händer. Går det här, vad händer med position 0? 165
Matriser En vektor går i en dimension Det går att skapa strukturer i flera dimensioner, matriser I princip går det också att skapa strukturer i ännu fler dimensioner, men det blir svårare att tänka sig… 166
Strängar/Matriser Ex. resultat i en tävling med flera omgångar int result[3][6]; Omgång 7 19 3 10 2 6 Tävlande 5 4 31 2 6 9 2 1 4 6 8 2 Matriser kan vara viktiga för ex. matematiska beräkningar, samt ex. för att lagra resultat som är relaterade i mer än ett plan…. MAtriser nämns bara, det kommer ej att ingå i kursens laborationer 167
Strängar Hur jämför du två strängar ? Ex….. Hur lägger du ihop två strängar ? Hur kopierar du en sträng ? Fråga studenten: Ex. längd typ innehåll … Operatorerna 168
Strängfunktioner #include <string.h> strcpy(x,y); strcmp(x,y); strcat(x,y); Förklara och ge exempel på tavlan För att på ett enkelt sätt kunna bearbeta strängar finns visa strängoperationer i systemet, använd: #include <string.h> strcpy(x,x); strcmp(x,x); strcat(x,x); 169
Strängfunktioner char * strcpy(char * s1, const char s2); /* resultatet är att s2 har kopierats till s1*/ int strcmp(char * s1, char * s2); /* jämför s1 och s2 om de är lika*/ char * strcat(char * s1, char * s2); /* slår ihop s1 och s2 så att s1 blir en sammnaslagen sträng med s1->s2*/ Här skall ett exempel som illustrerar strcpy, strcat, strcmp illustreras Gå igenom exemplen på tavlan, visa vilka returvärden som ges. Hänvisa till man-sidorna 170
Allokering Allokera: tilldela och anvisa plats Allokering innebär att göra en minnesplats tillgänglig för användning Allokering sker för enkla datatyper automatiskt ex. int i; 171
malloc() //kräver: #include <stdlib,h> char *duplicera(char *s) { char *p; p = (char *)malloc(strlen(s)+1); if(p !=NULL) strcpy(p,s); return p; } Här finns det en hel del att kommentera…… OBS Minnet är inte initierat till något särskilt 172
calloc() //kräver: #include <stdlib,h> char *duplicera(char *s) { char *pp; pp = (int *)calloc(sizeof(s)+1,sizeof(char)); if(pp !=NULL) strcpy(pp,s); return pp; } OBS Minnet är initierat till noll 173
Avallokering Deallokering innebär motsatsen till allokering, dvs. att ”lämna tillbaka” den minnespalts man tidigare tog i anspråk till systemet. free(p); free(pp); Detta är fortsättningen på exemplen innan 174
Allokering kopplat till pekare och arrayer char *p; resp. char p[10]; char p[10] innebär att ett minnesutrymme för 10 tecken är allokerat char *p innebär att en pekare är deklarerad, men inget användbart minnesutrymme är allokerat. 175
Allokering/Pekare och vektorer Exempel: char test[7]; char *p char ’a’ ’b’ ’f’ ’P’ ’g’ \0 1 2 3 4 5 6 position p ? Det här är en pekare till första pos för en ännu ej allokerad sträng I detta fall är minnesutrymmet för vektorn allokerat Strängslut 176
Pekare som parametrar int sum(const char * arr, int storl) { int i , s = 0; for(i = 0; i < storl; i++) s += arr[i]; return s; } int main() int i = 5 ; summa; int v1[i]={1,2,3,4,5}; summa =sum(v1,i); return 0; Detta borde kanske ligga tidigare…… int sum(const char * arr, int storl) /* Kommentera const { int i , s = 0; for(I = 0; I < storl; i++) s += arr[i]; return s; } int main() int i = 5 ; summa; int v1[i]={1,2,3,4,5}; summa =sum(v1,i); return 0; 177
Sammansatta datatyper
Sammansatta datatyper Hur identifierar jag en människa ? Ålder Namn Längd …. Försök att få studenten aktiv Starta med ett exempel på något bekant. Rita på tavlan Alla dessa data kan vi vilja ha för att beskriva en människa 179
Lagring av sammansatt data Hur lagrar jag informationen om en person? int alder; char *namn; float langd; Dessa parametrar gäller för en person. Vi vill lagra dem tillsammans. 180
Post För att lagra sammansatt data använder vi i C en post. Posten består av (ett eller oftast) flera fält Vi kan själva bestämma hur vår post skall se ut Förklara att post = struct En post är till skillnad från en enkel datatyp en enhet där vi kan lagra värden av olika typ. 181
Post Exempel deklaration: struct person{ char namn[25]; /*fält*/ int alder; /*fält*/ float langd; /*fält*/ }p; Här har vi deklarerat en variabel p av typen struct person Här hat 182
Post Den post du nu skapat är en datatyp, som kan användas som andra typer, de kan användas separat, lagras i en vektor, mm. Ett vanligt sätt är att ha en pekare till den egna typen som ett fält i posten. Med hjälp av detta kan man skapa länkad data. 183
Typdeklaration Man kan deklarera egna typer genom att använda det reserverade ordet typedef framför. Exempel typedef int storlek_t; /* Här har vi skapat ett alternativt namn, storlek, som är samma som en int*/ /* Vi kan skriva: */ storlek_t s= 10; Detta blir en utvikning för att få med typedef i detta sammanhang Jag tycker att man skall avråda från att använda typedef för vanliga typer, eftersom det kan bli förvirrande. Dok OK för struct 184
Post Typedef är av värde vid deklaration av poster: Ex: struct person /*Visar hur posten ska se ut*/ { char *namn; int alder; }; typedef struct person personPost_p; personPost_p min_person; struct person /*Visar hur posten ska se ut*/ { char *namn; int alder; }; typedef struct person personPost_p; /* Skapar ett alias till post person*/ ……….. personPost_p min_person; /* Nu kan vi enklare deklarera nya poster i programmet*/ 185
Post Exempel på länkad lista med poster struct person 186 …… Namn Age Langd Person * NULL …… 186
Punktnotation Hur anropar jag ett fält i en struct? Punktnotation: struct person { char * namn; int alder; float langd; }; typedef struct person personPost_p; . personPost_p Bengt; Bengt.alder = 44; 2 olika sätt, pil- och punktnotation Bengt.alder = 44; /* Du anropar fältet med: <Postens namn>.<fält> */ 187
Pilnotation När vi har pekare pekare använder vi pilnotation för att referera olika fält i en post. Ex. Person->namn; Person Namn Age Langd Person * NULL …… 188
Sortering
Sortering Vad skall sorteras? På vilket sätt kan jag sortera? 190 Strängar Sortera så enkelt och effektivt som omständigheterna kräver 190
Bubblesort Exempel #define SIZE 10 . int numbers[SIZE] , i , j, tmp; for(i = 0; i<SIZE; i= i+1) for(j = 0; j < SIZE-1; j= j+1) if(numbers[j] < numbers[j+1]) { tmp = numbers[j]; numbers[j]= numbers[j +1]; numbers[j +1]= tmp; } Hmmmmm 191
Grunderna i filhantering
Filhantering Filer kan användas för permanent lagring av data Hårddisk, disketter, CD-R/W, band Variabler och arrayer Försvinner när du avslutar programmet Sparas i datorns arbetsminne (internminne) Sparas i det fysiska minnet för att överleva mellan programkörningarna. Jämför med lagring av variabler och arrayer Obeständig data; försvinner när du avslutar programmet / stänger av datorn Sparas i datorns arbetsminne (internminne) 193
Uppbyggnad av filer 194 Visa på hur en enkel fil skulle kunna se ut. Nämn (skriv upp på tavlan) förkortningarna eol (end of line – byt rad), eof (end of file - slut på filen). Bör även ta upp att dessa inte skrivs dit av användaren utan att det sker automatiskt. Nedersta bilden så syns dessa naturligtvis inte i filen utan de är där för att illustrera vad som händer. 194
Data hierarkin Repetera hierarkin och varför man har abstraherat upp förståelsenivån från maskinspråk... Bit -> byte (tecken) -> fält -> strukturer -> fil kan vara en samling tecken, en samling fält eller en samling strukturer. En fil är en sekvensiell ström av bytes som slutar med en EOF-flagga. 195
Positionering i filer I en fil börjar man alltid att räkna från 0 Aktuell position hålls ordning på mha en filpekare Kan ses som en ström av tecken som far förbi, ex i form av tecken skrivna på ett band som rullar förbi ett fönster så att vi bara kan se ett tecken i taget... 196
Filpekaren Filpekaren är ett antal bytes sett från början av filen (offset)! Värdet ändras automatiskt när man läser eller skriver i filen Men först måste man... Filvariabel - Egentligen filobjektet, men det får skyfflas undan. Filpekaren är därmed ett heltalsvärde som anger positionen i filen som ett antal bytes sett från början av filen (offset)! 197
Öppna en fil (1) Koppla samman filvariabeln (internt i minnet) med den fysiska filen Öppnar en kommunikationskanal för läsning, skrivning eller båda Bilden skall illustrera hur filvariabeln (internt i minnet) måste kopplas till den fysiska filen. 198
Öppna en fil (2) Varje fil som är öppen har en filpekare När en fil öppnas sätts filpekaren (om inget annat nämns) automatiskt till att peka först i filen Öppnar man en fil för både läsning och skrivning så får man en filpekare för läsning och en för skrivning. 199
Skapa eller tömma filen Filpekaren hamnar först i filen Start = EOF Filpekaren kan påverkas genom standardfunktioner, börjar ta exempel på dessa 200
Skrivning till filen Värdet skrivs till filpekarens aktuella position Filpekaren flyttar sig efter skrivningen Ett värde, i det här fallet ”7”, skrivs till filen 201
Flytta på filpekaren Ex. Flytta filpekaren till första positionen i filen (återställer filpekaren) 202
Läsning från filen Filpekaren läser värdet från sin aktuella position och flyttar sedan fram ett steg 203
Jämförelse filer och arrayer Både arrayer och filer börjar från 0 Arrayer kan vi direkt tilldela/avläsa ett element via ett index, i en fil måste man flytta filpekaren Arrayer har en fast angiven storlek, en fil har ingen största storlek förutom den som sätts av minnet Båda kan lagra godtyckliga datatyper 204
Filhantering i C++ Hur fungerar det i C++? Ingen struktur: bara en sekvens av bytes som slutar med en EOF-flagga.Programmeraren måste strukturera upp filen så att den matchar När en fil öppnas skapas en variabel och en kommunikationskanal associeras med variabeln. I C++ finns det ingen struktur på själva filerna (de är bara en sekvens av bytes som slutar med en EOF-flagga) Detta innebär att det är upp till programmeraren att strukturera upp filen så att den matchar programmets krav När en fil öppnas skapas en variabel och en kommunikationskanal associeras med variabeln. 205
Pseudo-kod för filhantering Skapa filvariabel Öppna filen Koppla ihop filvariabeln med den fysiska filen för att få en ”kommunikationskanal” Ange om filen skall vara läsbar/skrivbar eller båda Kontrollera om filen gick att öppna Läs/skriv till filen Stäng filen 206
Bibliotek Vilka bibliotek behövs? Header-biblioteken <iostream> och <fstream> Rita upp och förklara uppbyggnaden i fig 14.3 arvshierarkin (C++ 3 ed s. 761). ifst 207
Biblioteket Fstream Biblioteket <fstream> innehåller deklarationer för att kunna skapa variabler av ifstream: för läsning från en fil ofstream: för skrivning till en fil fstream: för läsning och skrivning till en fil 208
Öppna en fil för enbart läsning Lägg till alternativet (egentligen samma sak i detta fall, men det kan vara bra att veta att det är default) inFile.open(”fil.txt”, ios::in) och förklara vad det innebär 209
Öppna en fil för enbart skrivning 210
Alternativ vid skrivning ios::app ios::ate ios::out ios::trunc När man öppnar en fil för skrivning finns det flera alternativ som kan vara bra att känna till... Förklara vad dessa innebär... (s. 763 i C++ 3 ed) och vilket som är default om man inte anger något annat. Lägg betoning på att default (ios::out) kommer att tömma filen; vanligt programmeringsfel! 211
Öppna för läsning och skrivning 212
Representation av data i C++ Sparas antingen binärt ios::binary anges vid öppning för läsning/skrivning eller via ASCII-kodning 213
Kontrollera om filen öppnades Det kan hända att öppningen av en fil misslyckas, därför bör man alltid testa! 214
Skrivning med << operatorn (1) Som i cout fast till filvariabeln istället Skriver bara så mycket som behövs outFile << age; kan skriva allt från 1 siffra till 11 (s 773) 215
Skrivning med << operatorn (2) 216
Skrivning med << operatorn (3) 217
Skrivning med write (1) Skriver alltid ned en fast storlek (oavsett om hela utrymmet är utnyttjat eller inte) 218
Skrivning med write (2) 219
Läsning från filer Kompletterande mot skrivningen ” >> ” read(reinterpret_cast<char *> (&p), sizeof(person)) 220
Sekvensiella filer vs. direktfiler Två typer av filer Sekventiella filer Lagras ofta efter en ordning angiven av ett nyckelvärde Använder oftast ” << ” och ” >> ” för att skriva och läsa Direktfiler Alla strukturer måste ha samma längd! read och write används När << och >> används är det svårt att göra uppdatering eftersom man riskerar att skriva över nästföljande post i filen av misstag. Poster (och därmed strukturer) kan här variera i storlek efter behov. Svårt att lokalisera en speciell post, man måste stega sig igenom tills den hittas. I direktfiler har alla strukturer samma längd vilket gör att man kan beräkna vart man skall i filen. Data kan läggas in och uppdateras utan att förstöra den andra datan i filen. Kan liknas med ett godståg där några av vagnarna har innehåll och vissa inte. 221
Positionera filpekaren (1) Positionera för läsning / flytta läspekaren seekg(long int) ios::beg, ios::cur, ios::end //Flytta 7 bytes framåt från filens början inFile.seekg(7); //inFile.seekg(7, ios::beg); //Flytta fram 3 bytes från aktuell filposition inFile.seekg(3, ios::cur); //Flytta filpekaren 2 steg från filens slut inFile.seekg(2, ios::end); Ge exempel på hur dessa används och när... Fråga vart man hamnar om man anger inFile.seekg(0, ios::end)? 222
Positionera filpekaren (2) Positionera för skrivning / flytta skrivpekaren seekp(long int) Samma som för seekg fast för skrivning Hämta aktuell filposition för läspekaren tellg() Hämta aktuell filposition för skrivpekaren tellp() Tjuvkika på nästa tecken utan att flytta filpekaren peek() Kolla om filpekaren står på EOF-flaggan eof() 223
Stängning av filen Till sist: Det är god ton (och ökar prestandan) att explicit stänga filen så fort du är färdig med den close() The end. Innehållet i oh-bladen visar bara på ett mindre exempel, ett större bör därmed visas på tavlan (för större överskådlighet). Bör ta upp hur man läser och skriver flera element till/från filen. Gärna exempel som tar upp skillanderna mellan att använda peek() och eof() för att kontrollera om det är färdigläst. 224
Vidare information om filhantering För större exempel och mer detaljer, se kapitel 14 i Deitel & Deitel 225
Rekursion
Rekursion Rekursion Innebär att man arbetar enligt det berömda mottot ”Söndra och härska” (divide and conquer) 227
Arbetssätt för rekursion Huvudproblem ???????? ! Delproblem ??? ! Delproblem ! Lösbart delproblem Meningen är att bilden skall illustrera... Problemet (eller strukturen) delas upp i mindre delar (som liknar huvudproblemet) tills dess att delproblemet är lätt lösbart. Sedan använder man den dellösningen för att lösa huvudproblemet! Rekursion löses genom att dela upp problemet i en del inte är lösbar och en del som kan lösas. Problemet som den inte kan lösas skickas vidare ett varv till tills dess att problemet är lätt att lösa. Heureka! 228
Rekursion handlar om självanrop Man löser problemet genom att anropa ”sig själv” med en mindre, eller mindre komplicerad, version 229
De tre delarna i rekursion Första anrop till den rekursiva funktionen Basfall, dvs brytpunkten för rekursionen Rekursionsfall, dvs självanrop med en mindre del av problemet (strukturen) Basfall Första anrop Rekursionsfall 230
Användning av rekursiv funktion Första anrop Som vanlig funktion Därefter Anropar sig själv (antingen direkt eller indirekt via en annan funktion) 231
Basfall Funktionen vet endast hur man löser det enklaste fallet av problemet Kallas för rekursionens basfall och vänder på rekursionen En funktion kan ha ett eller flera basfall 232
Rekursionsfall Den del av problemet som funktionen inte vet hur den skall lösa och därför skickar vidare Innebär att funktionen måste närma sig basfallet för varje anrop Ändliga rekursionsfall! Med ändlig menas att rekursionen måste nå fram till basfallet inom en rimlig tidsrymd (oändlig är alltså inte accepterbart) 233
Fakultet-problemet (1) Lös fakultet-problemet n! = n * ( n – 1 ) * ( n – 2 ) * … * 1 Rekursivt förhållande ( n! = n * ( n – 1 )! ) 5! = 5 * 4! 4! = 4 * 3!… Basfall (1! = 0! = 1) 234
Fakultet-problemet (2) Rekursionsfall för fakultet (factorial) 5! 5 * 4! 4 * 3! 3 * 2! 2 * 1! 1 235
Fakultet-problemet (3) Värdena som returneras tillbaka för varje rekursivt anrop i fakultet Slutligt värde: 120 5! 120 returneras 5 * 4! 24 returneras 4 * 3! 6 returneras 3 * 2! 2!=2 * 1=2 returneras 2 * 1! 1 returneras 1 236
Fakultet-problemet (4) Pseudo-kod för fakultet Om basfallet (0 eller 1): returnera 1 Annars rekursionsfall Multiplicera med aktuella talet Räkna ned det aktuella talet och anropa mig själv igen int factorial(int number) { if(number >= 0 && <= 1) return 1; else return number * factorial(number - 1); } Visa även hur funktionerna ligger i minnet och hur de försvinner efter att varje rekursivt anrop löst sitt basfall. Ta upp det faktum att ett rekursionssteg innehåller ett return, eftersom dess resultat kommer att kombineras med den del av programmet som funktionen vet hur den skall lösa. 237
Rekursion vid strukturer (1) Räkna elementen i en lista Dela upp en struktur Lista = huvud + svans | tom Huvud = element Svans = lista 238
Rekursion vid strukturer (2) Pseudo-kod för räkning av element i en lista Basfall (listan är tom): returnera 0 Rekursionsfall: Addera + 1 Minska listan med huvudet och anropa mig själv med svansen int countElement(En lista) { if(tom lista) return 0; else return 1 + countElement(lista - huvudet); } 239
Repetition av rekursiva funktioner Anropar sig själv Kan bara lösa ett basfall Delar upp problem/strukturer i rekursionsfall Skapar en nu kopia av sig själv för att bearbeta det mindre problemet och sakta närma sig basfallet Gör ett anrop till sig själv inuti return uttrycket Till sist löses basfallet och det värdet (dellösningen) arbetar sig upp för att lösa hela problemet 240
Rekursion vs. Iteration Iteration: explicita loopar Rekursion: upprepade funktionsanrop Terminering Iteration: loopvillkoret misslyckas Rekursion: basfallet känns igen Båda kan ha oändliga loopar Balans mellan prestanda (iteration) och bra mjukvaruutveckling (rekursion) Att ta upp: iteration – iteration, räknare rekursion – selektion, funktionsanrop med mindre versioner Alla problem som kan lösas mha rekursion har också en iterativ lösning. Rekursion väljs när den rekursiva lösningen på ett naturligt sätt avspeglar problemet. Hur skulle den iterativa lösningen av factorial se ut? factorial = 1; for(int counter = number; counter >=1; counter--) factorial *= counter; 241