Professional Documents
Culture Documents
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 1 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 2 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
1. Vi börjar programmera
Inledning
De idag mest använda programspråken är kanske Fortran, Pascal, Visual Basic (VB), Ada,
Java, C och C++. De är delvis ganska likartade s k funktionsorienterade språk. Det nyare
språket Java är ett objektorienterat språk och bygger därför delvis på ett annorlunda tänkande
jämfört med de andra språken. Även C++ är objektorienterat, men kan användas på ett
traditionellt sätt. Java bygger till stora delar på C++, så den som är bekant med C++ kommer
lättare igång med javaprogrammering. Många javakurser inleds därför ofta med C++. I denna
kurs kommer vi inledningsvis att använda Microsofts Visual C++ som utvecklingsmiljö för att
lära oss C++. Eftersom många begrepp förväntas vara bekanta kommer genomgångarna i
detta kursmaterial inte alltid att vara lika utförliga som i A- och B-kursen.
2) Välj File/New
4) Klicka på C++ Source File. Du har nu texteditorn framför dig där programkoden skrivs
in.
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 3 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
Följande programrader i C++ visar hur textsträngen Detta är C++ skrivs ut:
#include <iostream.h>
main()
{
cout << "Detta är C++ ";
}
Kommentarer i programkoden föregås av två snedstreck ’//’ eller /* …..*/ om en kommentar
fortsätter på flera rader. Ovanstående programrader har följande innebörd:
#include <iostream.h> /* Biblioteket iostream.h för in- och utmatning inkluderas
till programmet.*/
main() //Huvudprogrammet börjar.
{ //Vänsterklammer är detsamma som begin i Pascal.
cout << "Detta är C++ "; /*Textsträngen matas ut på skärmen utan radmatning.*/
} // Högerklammer är detsamma som end i Pascal.
Den första raden, som inleds med ett #-tecken, innehåller ett s k preprocessordirektiv. Här
finns biblioteksfilen (inkluderingsfilen) iostream.h, som innehåller funktioner för bl a
hantering av in- och utmatning. Andra ord för bibliotek är sidhuvudsfil, inkluderingsfil och
headerfil. Vi kommer att använda ett antal olika sidhuvudsfiler senare. Vill vi åstadkomma
radbrytning efter utmatningen måste raden avslutas med endl, enligt nedan:
cout << "Detta är C++ " << endl;
När vi knappat in programmet i editorn skall vi spara och köra det. Gör då på följande sätt:
1) Skapa förslagsvis mappen Cplusplus på din enhet och spara programmet under namnet
test1. Den sparade källkodsfilen får filslutet .cpp, som anger att det är ett C++-program.
I fortsättningen är det endast ccp- och exe-filerna vi är intresserade av. Observera att exe-filen
är relativt stor (172 kB att jämföra med 20 kB i VB). Vill man skapa ett nytt program görs
detta enklast på följande sätt:
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 4 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
1) Spara ett existerande program med File/Save as under nytt namn Cpluplus-mappen.
3) Öppna det nyss sparade programmet och upprepa punkterna 2 och 3 ovan.
Observera att endast en Debug-mapp skapas i den mapp cpp-filerna finns, oavsett hur många
kompilerade cpp-filer det finns. En minneskrävande variant är att skapa en ny mapp för varje
nytt program (som i VB), men eftersom Debug-mappen upptar totalt 1 MB är detta ingen bra
variant. Vi nöjer oss alltså med att endast spara .exe-filen från det senast körda programmet.
Bloodshed Dev-C++
En nackdel med att använda utvecklingsmiljön Visual C++ i undervisningen är att
programvaran inte är gratis. En alternativ utvecklingsmiljö är Bloodshed Dev-C++ ver 5,
som kan laddas ner fritt från http://www.bloodshed.net/download.html. En fördel med Visual
C++ är att den (med en extra inkluderingsfil) hanterar färger, att utskriften kan styras friare på
skärmen, samt att den hanterar de svenska bokstäverna å, ä, ö. Vi kommer därför i första hand
att använda Visual C++ i undervisningen. Det är dock fullt möjligt att klara kursen med Dev-
C++.
I urklippet ovan visas några syntaxskillnader mellan Visual C++ och Dev-C++:
system(”Pause”) måste anges i Dev-C++ för att stoppa exekveringen för utskrift
I Dev-C++ öppnas ett nytt program via menyvalet Arkiv/Nytt/Källfil (Ctrl-N). Programmet
spara med filtillägget .cpp. Sedan komileras det via menyvalet Exekvera/Kompilera (Ctrl-
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 5 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
F9) och körs med Exekvera/Kör (Ctrl-F10). Alternativt kan både exekvering och körning
göras via menyvalet Exekvera/Kompilera & Kör (F9). Till skillnad mot Visual C++ skapas
endast två filer till ett program; .cpp- och .exe-filen. Exekveringsfilen är stor och upptar c:a
500 kB! Det är därför lämpligt endast spara .cpp-filen.
Övning 1.1:
Skriv ett program som skriver ut följande textsträng på skärmen:
Detta är kul. Detta är kul. Detta är kul.
Övning 1.2:
Skriv ett program som skriver ut följande textsträngar på skärmen:
Detta är kul.
Detta är kul.
Detta är kul.
Övning 1.3:
Skriv ett program som skriver ut följande textsträngar med en tom rad emellan på skärmen:
Detta är kul.
Detta är kul.
Detta är kul.
Inmatning
Följande program läser in ett heltal från tangentbordet och skriver ut talet på skärmen:
#include <iostream.h>
main()
{
int a; //Deklaration av heltalsvariabeln a.
cout << "Ange ett heltal: " ;
cin >> a; //Heltalsvariabeln a läses in från tangentbordet.
cout << "Talet är " << a; //Heltalsvariabeln a skrivs ut på skärmen.
}
Utskriften på skärmen blir då:
Ange ett heltal: 5
Talet är 5
Följande program läser in två heltal från tangentbordet och skriver ut summan:
#include <iostream.h>
main()
{
int a,b; //Deklaration av heltalsvariabeln a.
cout << "Ange två heltal: " ;
cin >> a >> b; //Läser in heltalsvariablerna a och b från tangentbordet.
cout << "Summan av talen är " << a+b; //Summan av a och b skrivs ut på skärmen.
}
Övning 1.4:
Skriv ett program som läser in ett födelseår och sedan skriver ut personens ålder i år (t ex
2000). Utskriften på skärmen skall vara:
Ange ett födelseår: 1981
Du fyller 19 i år.
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 6 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
Heltal
Heltalsvariabler deklareras som datatyperna short (2 bytes, ±32767) och int (4 bytes, ±2.14
miljarder). Vanligtvis används int.
Casting
Följande beräkning görs som heltalsdivision, eftersom täljare och nämnare är heltal:
#include <iostream.h>
main()
{
cout << (5+3)/3 << endl;
}
Värdet blir 2. Vill man emellertid beräkna divisionen rätt måste uttrycket typomvandlas till ett
decimaltal med s k casting, d v s den önskade datatypen skrivs framför beräkningen:
cout << (double)(5+3)/3 << endl;
Detta gäller även om beräkningen görs med variabler:
#include <iostream.h>
main()
{
int a=2, b=6, c=3 ;
cout << (double)(a+b)/c << endl;
}
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 7 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
*Övning 1.10:
Skriv ett program som läser in ett heltal (max 63) och skriver ut det på
binär form, enligt urklippet.
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 8 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
Antal decimaler
Vid utskrift av decimaltal har vi hittills erhållit standardinställningens sex decimaler. Vill vi
själva bestämma antalet decimaler i utskriften får vi göra några tillägg i programmet. Anropen
setiosflags(ios::fixed) anger att utskriften av reella tal skall ske med fast decimalpunkt (inte
på t ex exponentiell form) och setprecision(n) att utskriften skall avrundas till n decimaler.
Dessa båda anrop kräver att vi inkluderar filen iomanip.h i programmet. Tilläggen i förra
programexemplet är markerade med fetstil nedan.
#include <iostream.h>
#include <iomanip.h>
main()
{
double a,b; //Deklaration av decimaltalen a och b.
cout << "Ange två decimaltal: " ;
cin >> a >> b; //Läser in decimaltalen a och b från tangentbordet.
cout << "Kvoten av talen är " << setiosflags(ios::fixed) << setprecision(2) <<a/b;
//Kvoten av a och b skrivs ut på skärmen.
}
Övning 1.11:
Skriv ett program som läser in och beräknar kvoten mellan två decimaltal. Programmet skall
även läsa in hur många decimaler kvoten skall skrivas ut med. Programmet skall ha följande
utskrift:
Ange två tal: 4 3
Ange antal decimaler i utskriften: 5
Kvoten är 1.33333
Matematiska funktioner
C++ innehåller ett flertal matematiska standardfunktioner, bl a följande:
sqrt(x) //ger roten ur x
fabs(x) //ger absolutbeloppet av x
ceil(x) //Avrundar till närmast större heltal
floor(x) //Avrundar till närmast lägre heltal
y
pow(x,y) //ger x (y måste vara ett heltal om x<0)
x
exp(x) //ger e
log(x) //naturliga logaritmen (Ln)
log10(x) //10-logaritmen
sin(x), cos(x), tan(x) //x anges i radianer
asin(x), acos(x), atan(x) //ger vinkeln i radianer
Funktionerna ger ett värde av typen double och argumentet x skall ha typen double.
Funktionerna finns i filen <math.h>, som alltså måste inkluderas i programmet: #include
<math.h>
Övning 1.12:
Skriv ett program som läser in två kateter till en rätvinklig triangel och beräknar dess
hypotenusa med två decimaler. Programmet skall ha följande utskrift:
Ange två kateter: 3 4
Hypotenusan är 5.00
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 9 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
Övning 1.13:
Skriv ett program som läser in två tal, x och y, och beräknar xy. Programmet skall ha följande
utskrift:
Ange två tal: 2 4
Detta blir 16
Övning 1.14:
Skriv ett program som läser in ett sinusvärde och skriver ut
motsvarande vinkel i grader, enligt utskriften till höger.
Observera att talet pi ej är definierat i c++. Deklarera
förslagsvis pi som en konstant i programmet.
Slumptal
Med följande sats genererar datorn ett slumptal (heltal) mellan 0 och 32767:
rand();
Slumptalen ligger dock ordnade i samma ordningsföljd tills följande funktion anropas:
srand(time(0));
Funktionen srand(k) ’blandar’ slumptalen på olika sätt för olika värden på heltalet k. För
samma värden på k ges dock samma slumptalsföljd. Det gäller alltså att välja olika värden på
k inför varje körning av programmet. Standardfunktionen time(0), som ger antalet sekunder
från år 1970 (testa!), ger ett startvärde för beräkningen av slumptalen. Standardfunktionerna
rand och srand finns i filen stdlib.h och funktionen time finns i filen time.h. Filerna måste
alltså inkluderas i programmet.
Med följande sats genererar datorn ett slumptal (heltal) mellan 1 och N:
rand()%N+1;
Följande program skriver ut ett slumptal mellan 1 och 10:
#include <iostream.h>
#include <stdlib.h>
#include <time.h>
main()
{
int a; //Deklaration av heltalsvariabeln a.
srand(time(0));
cout << "slumpalet är " << rand()%10+1;
}
Övning 1.15:
Skriv ett program som genererar fem slumptal mellan 1 och 25. Programmet skall ha följande
utskrift:
Slumptalen är:
24
3
6
19
12
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 10 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
Övning 1.16:
Modifiera föregående övning så att programmet genererar fem slumptal (N) i intervallet
10 N 20.
Övning 1.17:
Modifiera föregående övning så att programmet genererar fem decimala slumptal x i
intervallet 0 < x < 1.
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 11 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
2. Urval
if-satsen
I programmering uppkommer ofta olika valsituationer, t ex att välja ut det största eller minsta
talet, eller att omvandla valutan kronor till dollar eller pund. Detta åstadkoms med en if-sats.
Ett program som läser in två tal och skriver ut det största kan se ut på följande sätt:
#include <iostream.h>
main()
{
double a,b; //Deklaration av decimaltalen a och b.
cout << "Ange två decimaltal: " ;
cin >> a >> b; //Läser in decimaltalen a och b från tangentbordet.
if (a>b)
cout << a << " Är störst";
else
cout << b << " Är störst";
}
Observera att det skall vara parentes runt villkoret efter if. Ett program som omvandlar från
Celsius till Fahrenheit eller omvänt beroende på användarens val kan se ut på följande sätt:
#include <iostream.h>
main()
{
char val; //Deklaration av teckenvariabeln val.
double c, f; //Deklaration av temperaturvariabler.
cout << "Skall omvandling göras från celsius (c) eller från farenheit (f)? " ;
cin >> val; //Läser in vilken omvandling som skall göras.
if (val=='c') //Jämförelseoperatorn lika med är '=='
{
cout <<"Ange en temperatur i Celsius: ";
cin >> c;
cout << "Detta motsvarar " << 1.8*c+32 << " F";
}
else
{
cout <<"Ange en temperatur i Fahrenheit: ";
cin >> f;
cout << "Detta motsvarar " << (f-32)/1.8 << " grader C";
}
}
Observera att det skall vara klamrar efter if och else om det är mer än en sats.
Char
Datatypen char lagrar enstaka tecken. Ett tecken som tilldelas en teckenvariabel skall
omgärdas av apostrofer (se exemplet ovan) och inte citationstecken.
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 12 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
Else if
Ibland kan urvalet förenklas med else if, som i följande exempel:
#include <iostream.h>
main()
{
int a;
cout << "Ange ett heltal!";
cin >> a;
if (a==1)
cout << "Måndag";
else if (a==2)
cout << "Tisdag";
else if (a==3)
cout << "Onsdag";
else
cout << "En annan dag";
}
Den sista else-satsen utförs om ingen av else if-satserna utförs. Else-satsen behöver dock inte
finnas med.
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 13 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
Övning 2.1:
Skriv ett program som läser in ett tal och kollar om talet är större är lika med 10. Programmet
skall ha följande utskrift:
Ange ett tal: 12
Talet är större än 10
Extra uppgift: Om talet är större än 10 skall datorn ge ifrån sig ett ljud. Ett ljud alstras med
satsen:
cout << ”\a”;
Typ av ljud väljs under kontrollpanelens Ljud-ikon och under händelsen Standardljud.
Övning 2.2:
Skriv tre program som läser in ett tal och som kollar om talet ligger i intervallet:
De logiska operatorerna && (OCH) och || (ELLER) skall användas. Skärmen skall visa
följande utskrift:
Ange ett tal:
Talet ligger inom/utanför intervallet.
Övning 2.3:
Skriv ett program som läser in tre heltal och som sedan skriver ut det största av talen.
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 14 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
Övning 2.4:
Skriv ett program som läser in tre heltal och som sedan skriver ut talen i storleksordning med
det minsta först, med följande utskrift:
Ange tre tal: 4 2 8
I ordning: 2 4 8
Övning 2.5:
Skriv ett program som läser in tre heltal och som sedan kollar om något av talen är lika, alla
lika eller alla olika, med följande möjliga utskrifter:
Ange tre heltal: 5 1 4
Alla talen är olika.
Eller:
Ange tre heltal: 5 4 4
Några av talen är lika.
Eller:
Ange tre heltal: 4 4 4
Alla talen är lika.
Övning 2.6:
Skriv ett program som omvandlar från svenska kronor till amerikanska Dollar eller omvänt.
Skärmen skall visa:
Skall omvandling ske från kronor till dollar (D) eller från dollar till kronor (K). Ange bokstaven D eller K:
Ange belopp:
Motsvarande belopp i dollar är: $ (vid val av D)
Motsvarande belopp i kronor är: sKr (vid val av K)
Övning 2.7:
Skriv ett program som ger dig möjlighet att beräkna area och volym hos cylindrar och klot,
med följande utskrift:
Vill du räkna på klot (k) eller cylinder (c)? c
Ange cylinderns radie:
Skall cylinderns mantelarea (a) eller volym (v) beräknas? v
Cylinderns volym är:
Motsvarande utskrift görs om klot (k) väljs.
*Övning 2.8:
Skriv ett program som läser in ett belopp i kronor och som skriver ut beloppet rätt avrundat
för en kassörska. Är beloppet 27,80 kr skall det avrundas till 29,00 kr. Är beloppet 27,60 kr
skall det avrundas till 27.50 kr. Använd följande avrundningsregler:
0 decimal < 0,25: Avrunda till 0
0,25 decimal 0,75: Avrunda till 0,50
0,75 < decimal 1: Avrunda till 1
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 15 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
*Övning 2.9:
Gör en enkel variant av spelet HiLo, d v s låt datorn generera ett slumptal mellan 1 och 100.
Du har sedan 5 chanser på dig att gissa rätt. Utskrifterna är följande:
Gissa första talet:
För lågt!
Gissa andra talet:
För högt!
Gissa tredje talet:
För högt!
Gissa fjärde talet:
För lågt!
Gissa sista talet:
Fel, rätt tal är:
Om du gissar rätt tal skall datorn ge ifrån sig ett ljud och skriva ut Rätt gissat!
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 16 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
While-satsen
Ett program som skriver ut Programmering är roligt på skärmen tio gånger med en while-sats
kan se ut på följande sätt:
#include <iostream.h>
main()
{
int i;
i=0; //Initierar iterationsvariabeln i
while (i<=10)
{
i=i+1;
cout << ”Programmering är roligt” << endl;
}
}
Ett program som skriver ut Programmering är roligt på så länge du vill kan se ut på följande
sätt:
#include <iostream.h>
main()
{
int i;
char val=‟j‟; //Initierar variabeln val
while (val==‟j‟)
{
cout << ”Programmering är roligt” << endl;
cout << ”Vill du skriva ut texten en gång till (j/n): ”;
cin >> val;
}
}
Ett program som beräknar summan av 1+2+3+4+5 kan se ut på följande sätt med en while-
sats:
#include <iostream.h>
main()
{
int sum,i;
sum=0; //Initierar summavariabeln sum
i=1; //Initierar iterationsvariabeln i
while (i<=5)
{
sum=sum+i;
i=i+1;
}
cout << "Summan är " << sum;
}
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 17 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
Do-while-satsen
En variant på while-satsen är do-while. Loopen genomlöps där minst en gång eftersom
avbrottskriteriet ligger sist i loopen. Följande programexempel visar hur det fungerar:
main()
{
double x;
char svar;
do
{
cout << "Ange ett tal: ";
cin >> x;
cout << "Kvadraten är " << x*x << endl;
cout << "Vill du fortsätta? ";
cin >> svar;
}
while (svar=='j');
}
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 18 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
Övning 3.1:
Skriv ett program som läser in två tal och sedan skriver ut summan av talen. Programmet skall
sedan fråga om du vill göra ytterligare en beräkning och hålla på så länge du svarar j.
Programmet skall ha följande utskrifter:
Ange två tal: 5 8
Summan är 13
Vill du fortsätta (j/n): j
Övning 3.2:
Modifiera övning 2.6 ovan med en while-sats så att det går att göra flera omvandlingar.
Programmet skall ha följande utskrifter:
Skall omvandling ske från kronor till dollar (D) eller från dollar till kronor (K)? Ange bokstaven D eller K:
Ange belopp:
Motsvarande belopp i dollar är: $ (vid val av D)
Motsvarande belopp i kronor är: sKr (vid val av K)
Vill du fortsätta (j/n): j
Vill man fortsätta skall programmet hoppa tillbaks till frågan om omvandling skall göras från
kronor till dollar eller omvänt.
Övning 3.3:
Skriv ett program som läser in ett positivt udda heltal n och sedan beräkna summan
1+3+5+…+n. Programmet skall ha följande utskrift:
Ange ett heltal: 5
Summan är 9
Övning 3.4:
Skriv ett program som läser in ett positivt heltal n och sedan beräkna produkten 1*2*3*…*n.
Programmet skall ha följande utskrift:
Ange ett heltal: 4
Produkten är 24
Övning 3.5:
Ett tal i Fibonaccis talföljd fås som summan av de två föregående talen. Talföljdens sju första
tal är: 1, 1, 2, 3, 5, 8, 13. Skriv ett program som läser in ett heltal och sedan beräknar det n:te
talet i Fibonaccis talföljd. Programmet skall ha följande utskrift:
Ange ett heltal: 6
Motsvarande fibonaccital är 8
Övning 3.6:
Skriv ett program som läser in ett heltal och som kollar om talet är ett primtal, d v s om talet
endast är jämnt delbart med 1 respektive med sig själv. Programmet skall ha följande utskrift:
Ange ett heltal: 29
Talet är ett primtal
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 19 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
Övning 3.7:
Skriv ett program som läser in ett heltal mellan 1 och 1000 och som sedan räknar antalet
slumptal mellan 1 och 1000 som måste genereras innan det inmatade talet dyker upp.
Programmet skall ha följande utskrift:
Ange ett heltal: 679
Antal genererade slumptal: 822
Rensa skärmen
Ibland vill man rensa skärmen före en inmatning. Detta görs i Visual C++ med anropet:
system("cls");
Detta kräver inkluderingsfilen stdlib.h:
#include <stdlib.h>
Skärmen kan även rensas med funktionen clrscr:
clrscr();
Detta kräver dock att biblioteket conio+.h inkluderas i början av programmet, d v s:
#include ”conio+.h”
Filen finns i kursmappen cplusplus och skall placeras i mappen C:/Program/Microsoft
Visual Studio/VC98/Include.
Övning 3.8:
Modifiera övning 3.3 så att skärmen raderas innan nästa addition görs.
Övning 3.9:
Modifiera övning 3.2 så att skärmen raderas innan nästa valutaomvandling görs.
Övning 3.10:
Modifiera övning 2.9 (HiLo-spelet) med en while-loop.
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 20 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
For-satsen
Den andra repetitionssatsen i C++ är for-satsen. Den används främst när man i förväg vet
antalet repetitioner som skall göras. Ett program som beräknar summan av 1+2+3+4+5 med
en for-sats kan se ut på följande sätt:
#include <iostream.h>
main()
{
int sum=0;
for (int i=1;i<=5;i++) //Variabeln i deklareras, initieras, jämförs och ökas med 1
sum+=i;
cout << "Summan är " << sum;
}
I C++ är det tillåtet att deklarera variabler nästa var som helst i programmet och inte bara i
början som i VisualBasic. Variabeln i deklareras därför vid for-loopen. Programmet kan även
skrivas på följande kompaktare sätt:
#include <iostream.h>
main()
{
int sum=0;
for (int i=0;i<5;i++,sum+=i); //Summeringen görs i for-loopens fält för ändring.
cout << "Summan är " << sum;
}
Liksom i if-satser och i while-loopar behöver heller inte for-lopen ha klammerparenteser om
den endast innehåller en sats.
Övning 3.11:
Lös övning 3.3 med en for-loop.
Övning 3.12:
Lös övning 3.4 med en for-loop.
Övning 3.13:
Lös övning 3.5 med en for-loop.
Övning 3.14:
Lös övning 3.6 med en for-loop.
Övning 3.15:
1 1 1 1 1
Beräkna summan ... för olika antal termer med fem decimaler, med
2 4 8 16 32
följande inmatning. Vad blir summan om man tar med många termer?
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 21 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
Övning 3.16:
Skriv ett program som med en for-lop beräknar summan SN med fem decimaler:
1 1 1 1 1
SN = 4 1 ... {N är ett udda heltal}
3 5 7 9 N
Obuffrad inmatning
Vid inmatning med cin >> måste enter-tangenten tryckas ned. Inmatning av enskilda tecken
kan emellertid göras med getch() (finns i inkluderingsfilen conio.h) utan att enter-tangenten
trycks ned, d v s exekveringen fortsätter direkt när en tangent trycks ned. Detta kallas
obuffrad inmatning. Det inmatade tecknet syns (ekas) då heller inte på skärmen. En variant är
getche(), som visar tecknet på skärmen. getch() kan även användas som pause. Följande
exempel visar hur getche används vid inläsning av ett tecken och som pause:
#include <iostream.h>
#include <conio.h>
main()
{
char c;
cout << "Ange ett tecken: " << endl;
c=getche(); //inläsning med ‟eko‟
cout << "Du matade in " << c << endl;
getch(); //exekveringen inväntar tangenttryckning
}
Observer att endl måsta vara med för att utskriften skall visas. Det inmatade tecknet hamnar
på följande rad. Används inkluderingsfilen svtecken.h kan endl utelämnas och det inmatade
tecknet hamnar på samma rad som Ange ett tecken:-texten. Följande loop avbryts med ’q’:
#include <iostream.h>
#include "conio+.h"
main()
{
int teck='a';
cout << "Ange tecken, avsluta med 'q':" << endl;
while (teck!='q')
{
teck=getch(); //Inmatat tecken visas ej på skärmen
}
}
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 22 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
Boolesk datatyp
Den booleska datatypen bool kan anta värdena true och false. Följande båda if-satspar är
likvärdiga:
bool finns=true;
if (finns==true)
if (finns)
samt:
if (finns==false)
if (!finns)
Vid inmatning med cin fås också ett boolesk villkor. Med följande sats…
if (cin >> a)
…erhålls värdet false om variabeln a är deklarerad som typen int och ett tecken matas in.
Fördröjning
Fördröjning i t millisekunder erhålls med funktionen Sleep(t) (finns i inkluderingsfilen
conio+.h). Fördröjning i en halv sekund får med följande sats:
Sleep(500);
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 23 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
Tangentfunktionen kbhit()
Funktionen kbhit (finns i inkluderingsfilen conio.h) känner av om en tangent trycks ned. Den
får då värdet true. Funktionen är användbar som avbrottskriterium i while-loopar. I följande
exempel görs en uppräkning av heltal varje sekund:
#include <iostream.h>
#include "conio+.h"
main()
{
int i=0;
while (!kbhit())
{
i++;
Sleep(1000);
cout << i << endl;
}
cout << "Nu är det slut!" << endl;
getch(); //Obs! Inväntar tangenttryckning
}
Övning 3.17:
Skriv ett program som som beräknar hur många hela slumptal mellan 1 och 1000 som måste
genereras innan ett inmatat heltal dyker upp första gången. Programmet skall ha följande
utskrifter:
Ange ett heltal mellan 1 och 1000: 470
Talet 470 dyker upp efter 821 genererade slumptal.
Övning 3.18:
Använd programkoden i exemplet ovan för funktionen kbhit(), ta bort Sleep och cout i loopen
och gör ett program där du kan testa din reaktionsförmåga i termer av antal varv i loopen.
Loopen startar slumpmässigt inom 1-10 s och skriver då ut Tryck nu!. Tiden mäts därifrån tills
en tangent trycks ned. Programmet skall ha följande utskrifter:
Reaktionstest. Tryck på en tangent för att starta reaktionstestet. Tryck sedan igen när Tryck nu! visas.
Tryck nu!
Antal loopar: 28943
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 24 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
4. Textsträngar
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 25 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
Escape-sekvenser
Radframmatningar har vi hittills gjort med satsen endl. Radframmatning kan även
åstadkommas med escape-sekvensen ’\n’, som är ett tecken:
cout << "kalle\n"; //Påbörjar nästa utskrift på ny rad.
cout << "\nkalle"; //kalle skrivs ut i början på en ny rad.
Följande tabell visar några användbara escape-sekvenser:
\n Utskriften fortsätter i början på nästa rad.
\0 Radsluttecken.
\a Ger ett kort ljudsignal (alert).
\b Flyttar utskriftspositionen ett steg bakåt (backspace).
\r Flyttar utskriftspositionen till radens början (return).
\f Flyttar utskriftspositionen till början på nästa sida (form feed).
\t Flyttar utskriftspositionen till nästa tabstopp.
Övning 4.1:
Skriv ett program som läser in ditt förnamn och som sedan skriver ut det igen på följande sätt:
Ange ditt förnamn: Kalle
Du heter Kalle, som börjar på bokstaven K
Övning 4.2:
Skriv ett program som läser in ditt för- och efternamn och som sedan skriver ut det igen på
följande sätt:
Ange ditt för- och efternamn: Kalle Anka
Du heter Kalle Anka
Övning 4.3:
Skriv ett program som läser in ditt förnamn och antalet bokstäver i förnamnet och som sedan
skriver ut bokstäverna på var sin rad:
Ange ditt förnamn: Kalle
Ange antalet bokstäver i namnet: 5
K
a
l
l
e
Övning 4.4:
Skriv ett program som läser in ditt förnamn och antalet bokstäver och som sedan skriver ut
namnet baklänges, på följande sätt:
Ange ditt förnamn: Kalle
Ange antalet bokstäver i namnet: 5
Namnet baklänges blir: ellaK
ASCII-kod
Alla tecken (bokstäver, siffror, frågetecken …) lagrade i datorn har olika s k ASCII-kod (se
t ex webbsidan http://www.asciitabell.com eller hjälpen i Visual C++), d v s ett nummer
mellan 1 och 256. Det är tecknets ASCII-kod som avgör storleken på tecknet vid jämförelse
mellan olika tecken. Exempelvis är A mindre än B därför att A:s ASCII-kod är 65 och B:s 66.
Följande programrad (kallas cast) skriver ut ASCII-koden för tecknet lagrat i variabeln teck:
cout << (int)teck;
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 26 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
Detta fungerar för tecken med ASCII-koder upp till 128. För övriga tecken blir koden
(felaktigt) negativ. Med följande programrad blir det alltid rätt ASCII-kod:
Vill vi skriva ut tecknet för en viss ASCII-kod lagrad i heltalsvariabeln n gör vi på följande
sätt:
cout << (char)n;
Även tangenter utan tecken har (ASCII-)-koder. Här är några exempel:
Enter: 13
Esc: 27
Pil upp: 72
Pil ner: 80
Pil vänster: 75
Pil höger: 77
Övning 4.5:
Skriv ett program som läser in en ASCII-kod (d v s ett heltal mellan 1-256) och som sedan
skriver ut motsvarande tecken i en loop med följande utskrifter:
Ange en ASCII-kod: 88
Motsvarande tecken är: X
Övning 4.6:
Skriv ett program som läser in ett tecken/en tangentnedtryckning i en loop och som sedan
skriver ut motsvarande ASCII-kod med följande utskrifter (lägg tll 256 om koden blir negativ):
Ange ett tecken: a
Motsvarande ASCII-kod är: 97
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 27 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
…
gotoxy(45,12);
setcolor(4);
cprintf(”Hej”);
…
Strängvariabeln namn skrivs ut med %s på följande sätt:
cprintf(”%s”,namn);
Teckenvariabeln teck skrivs ut med %c på följande sätt:
cprintf(”%c”,teck);
Heltalsvariabeln hel skrivs ut med %d på följande sätt:
cprintf(”%d”,hel);
Decimaltalsvariabeln dec skrivs ut med %3.1f på följande sätt:
cprintf(”%3.1f”,dec);
Där 3 anger antal positioner och 1 antal decimaler. För att kunna använda dessa funktioner
måste följande bibliotek inkluderad i programmet:
#include <conio.h>
Övning 4.7:
Skriv ett program som läser in ditt namn, samt en position, rensar skärmen och sedan skriver
ut ditt namn på angiven position.
Övning 4.8:
Modifiera föregående övning så att programmet även frågar efter vilken färg namnet skall
skrivas med.
Övning 4.9:
Skriv ett program som automatiskt skriver ut vilket heltal som motsvarar en viss färg. Heltalet
skall ha den färgen. Utskriften skall ha följande utseende:
0
1
2
3
4
…
Övning 4.10:
Skriv ett program som läser in ditt namn, en färg och som sedan skriver ut ditt namn med den
färgen i skärmens hörn och i mitten av skärmen.
Övning 4.11:
Skriv ett program som läser in ditt namn, en färg och som sedan skriver ut ditt namn på en
slumpmässig position på skärmen. Rensa skärmen innan namnet skrivs ut.
Övning 4.12:
Modifiera föregående uppgift så att ditt namnskrivs ut på 25 slumpmässiga positioner på
skärmen och med en slumpmässig färg.
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 28 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
Kopiering
Vi nämnde tidigare att det inte går att tilldela en strängvariabel ett värde, förutom vid
deklarationen. Vill vi åstadkomma följande tilldelning:
namn = ”Anders”; //Felaktigt!
Måste vi använda funktionen strcpy:
strcpy(namn,”Anders”);
För att kunna använda strcpy och nedanstående strängfunktioner måste vi inkludera filen
string.h:
#include <string.h>
Jämförelse
Det går heller inte att jämföra två strängvariabler så som man jämför tal. Vill vi utföra
följande jämförelse mellan strängarna a och b:
if (a==b) //Felaktigt!
Måste vi använda funktionen strcmp:
strcmp(a,b);
Värdet av funktionen är <0 om a<b, 0 om a=b och >0 om a>b. En programsnutt som läser in
två strängar och jämför vilken som är minst (d v s kommer först i bokstavsordning) ser ut på
följande sätt:
…
char a[10], b[10];
cout<<"Mata in två namn: ";
cin>> a >>b;
if (strcmp(a,b)<0)
cout << a <<" Först";
else
cout << b <<" Först";
…
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 29 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
Sammansättning av strängar
Med funktionen strcat(a,b) hamnar innehållet i strängen b efter innehållet i strängen a, enligt
nedanstående exempel:
cout << ”Ange ett förnamn”;
cin >> namn1;
cout << ”Ange ett efternamn”;
cin >> namn2;
strcat(namn1,namn2);
cout << namn1;
Läses Kalle in till variabeln namn1 och Anka till variabeln namn2 fås utskriften:
KalleAnka
Obs! Ingen koll sker här att namn2 får plats i namn1. Sammansättning av strängar kallas även
kontatenering.
Stränglängd
Funktionen strlen(a) ger längden av textsträngen sparad i strängvariabeln a, enligt
nedanstående exempel:
…
char namn[20] = ”Kalle”;
cout << ”Antal tecken i namnet är ” << strlen(namn);
…
Utskriften här blir alltså:
Antal tecken i namnet är 5
Övning 4.17:
Skriv ett program som läser in två namn och som skriver ut antal tecken i namnen och
namnen i bokstavsordning. Är namnen lika skall även detta skrivas ut. Även antal tecken i
namnet skall räknas. Använd följande utskrifter:
Ange första namnet: Kalle
Antal tecken: 5
Ange andra namnet: Anders
Antal tecken: 6
I bokstavsordning: Anders Kalle
Eller:
Ange första namnet: Kalle
Antal tecken: 5
Ange andra namnet: Kalle
Antal tecken: 5
Namnen är lika
Övning 4.18:
Modifiera övning 4.17 så antalet tecken inte behöver läsas in.
Övning 4.19:
Modifiera övning 4.17 vidare så att det går att läsa in hela meningar och få dem utskrivna
baklänges.
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 30 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
*Övning 4.20:
Skriv ett program som läser in tre namn och sedan skriver ut dem i boksavsordning, enligt
exemplet:
Ange första namnet: Helmer
Ange andra namnet: Amanda
Ange tredje namnet: Beata
I bokstavsordning: Amanda Beata Helmer
*Övning 4.21:
Skriv ett program där du låter din kompis gissa vilket ord som döljer sig bakom de omkastade
bokstäverna. Programmet skall fungera som exemplet Anders_A/cplusplus/ordkombi.exe.
Övning 4.22:
Skriv ett program som läser in antal personer, antal biljetter och antal bilar och sedan skriver
ut enligt följande exempel:
Ange antal personer, antal biljetter och antal bilar: 278 25 2
Antal personer: 278
Antal biljetter: 25
Antal bilar: 2
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 31 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
Övning 4.23:
Skriv ett program som läser in en sträcka (km), tid (timmar) och sedan skriver ut sträckan,
tiden och hastigheten med två decimaler, enligt följande exempel:
Ange en sträcka (km) och en tid (timmar): 69 0.82
Antal kilometer: 69.00
Tid i timmar: 0.82
Medelhastighet (km/h): 84.10
Övning 4.24:
Skriv ett program som i en tabell skriver ut hundra slumptal mella 1 och 50 i en snygg tabell
med tio rader och tio kolumner. Programmet skall fungera som exemplet
Anders_A/cplusplus/slumptabell.exe.
Övning 4.25:
Skriv ett program som i en tabell skriver ut alla tecken med ASCII-kod mellan 1 och 256
(dock ej tecknen 7-13). Programmet skall fungera som exemplet
Anders_A/cplusplus/asciitabell.exe.
Övning 4.26:
Skriv ett program som i en tabell skriver ut 10-20:ans gångertabell. Programmet skall fungera
som exemplet Anders_A/cplusplus/gangertabell.exe.
Övning 4.27:
Skriv ett program som skriver ut en värdetabell för kvadratroten ur talen 10, 20, 30, …, 100.
Värdet för x skrivs ut med en decimal och kvadratroten med två decimaler. Programmet skall
fungera som exemplet Anders_A/cplusplus/rotentabell.exe.
Övning 4.28:
Modifiera föregående övning så att startvärde, slutvärde och steglängd läses in. Kvadratroten
skrivs nu ut med fyra decimaler. Programmet skall fungera som exemplet
Anders_A/cplusplus/rotentabell_b.exe.
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 32 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
Standardtypen string
Hittills har vi betraktat strängar som fält (d v s arrayer) av tecken. Detta har C++ ärvt från
programmeringsspråket C. I nyare versioner av C++ (bl a i Visual C++) finns dock klassen
string, som förenklar hantering av strängar. Strängvariabler av klassen string behöver inga
funktioner vid tilldelningar och jämförelser, utan behandlas på liknande sätt som t ex heltal.
För att kunna använda klassen string skall inkluderingsfilen string finnas med. Observera att
de tre av inkluderingsfilerna i exemplet nedan skall skrivas utan .h. Dessutom måste raden
using namespace std; infogas:
#include <iostream> //utan .h
#include <iomanip> //utan .h
#include <conio.h>
#include <string> //utan .h
using namespace std;
main()
{
string a,b;
cout << "Ange två namn åtskilda med mellanslag: ";
cin >> a >> b;
cout << "Du matade in namnet " << a << " och " << b;
getch();
}
Om variabeln a är en sträng av typen string och variabeln b av typen string eller teckenfältet
char[i], gäller följande för tilldelningar, jämförelser och operationer (observera att följande
inte gäller om även a är ett teckenfält):
cin >> a; Läser in till a till första blanktecken.
getline(cin, a); Läser in en hel rad till a (även in blanktecken). Ger true om läsningen
gick bra.
cout << a; Skriver ut a.
a=b; Tilldelning
(a==b), (a!=b), (a<b) a<=b, … Jämförelser
a.compare(b) Jämför strängen a med strängen b. Om a<b returneras -1, om a=b
returneras 0 och om a>b returneras 1.
a.size(), a.length() Ger strängen a:s längd. Observera att avslutstecknet ”\0” inte räknas
in i längden. Om a = ”Anders” ger a.length() = 6.
a.substr(2, 3) Ger tre tecken av strängen a med början i position 2. Om a=anders
erhålls ”der”.
Sökning
a[4] Indexering av strängen. Första positionen är 0.
a[1] ger tecken i position 1 (2:a tecknet). Om a = anders, blir
resultatet ”n”.
a.find(b) Söker i a efter texten t, där ”b” är en sträng av klassen string, ett
tecken av typen char eller en tecken array (char b[] ). Returnerar
funnen position. Saknas tecknet skrivs ett tal större än strängens
längd ut. I följande exempel skrivs positionen för tecknet a[0] ut i
strängen b. Saknas tecknet skriv ett ”stort” tal ut:
string a,b="aeio";
cout << "Ange ett namn: ";
cin >> a;
cout << b.find(a[0]); //kollar om första tecknet finns i b-strängen
a.find(b, 3) Som ovan men sökning börjar i position 3. Returnerar funnen position.
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 33 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
a.find(c,7) Söker efter 7 st tecken ”c”, där ”c” är av typen char. Returnerar funnen
position.
string a="per",b;
b=a[0]+a[1]+a[2]; //Felaktigt!
cout << b << endl;
string a="per",b;
b=b+a[0]+a[1]+a[2]; //Rätt!
cout << b << endl; //per skrivs ut
a.append(b,2) Lägger till de två första tecknen från b. Om a = anders och b= kalle blir
resultatet ”anderska”
a.append(4,c) Lägger till 4 tecken av typen char. Om a = anders och c = ‟*‟ blir
resultatet anders****.
Ändra strängar
a.replace(2, 3, b) Ersätter 3 tecken i a med början i position 2 med strängen b. Om
a=anders och b=kalle blir resultatet ”ankalles”.
a.replace(2, 3, b,1,4) Ersätter 3 tecken i a med början i position 2 (3-e tecknet) med 4
tecken i b fr o m position 1 (2-a tecknet) i b. Om a=anders och b=kalle
blir resultatet”analles”.
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 34 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
4) Spara ändringen och stäng filen. Nu räcker det med en inmatning med Enter.
Innan ändringen görs är det lämpligt att spara en kopia av inkluderingsfilen string ( t ex
string_kopia).
Övning 4.29:
Skriv ett program som läser in en text och sedan omvandlar bokstäverna å, ä och ö till a
respektive o. Använd inkluderingsfilen svtecken.h och funktionen teckenbyt(). Programmet
skall ha följande utskrifter:
Mata in en text: Det gäller att göra rätt
Omvandlad text: Det galler att gora ratt
Övning 4.30:
Skriv ett program som läser in en text och sedan räknar antal tecken (inklusive mellanslag),
samt skriver ut första och sista tecknet. Programmet skall ha följande utskrifter:
Mata in en text: Detta är texten
Antal tecken i strängen: 15
Strängens första tecken är: D
Strängens sista tecken är: n
Övning 4.31:
Skriv ett program som läser in en text och sedan skriver ut den baklänges. Programmet skall
ha följande utskrifter:
Mata in en text: Kalle Persson
Baklänges: nossreP ellaK
Övning 4.32:
Skriv ett program som läser in en text och sedan skriver ut texten på rövarspråket, d v s en
konsonant ersätts med sig själv, ett ’o’ och sig själv. Exempelvis blir t tot, g gog och p pop
o s v. Ledning: Använd funktionen replace. Programmet skall ha följande utskrifter:
Mata in en text: jag heter pelle
På rövarspråk: jojagog hetoteror popelollole
Programmet skall fungera som exemplet Anders_A/cplusplus/uppg4_32.exe.
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 35 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
Övning 4.33:
Ange ett datum på amerikanskt format mm/dd/yy och låt programmet omvandla och skriva ut
detta till svenskt format yyyy-mm-dd. Om år är större än 20 ska yyyy vara 19yy * annars
20yy. Programmet skall ha följande utskrifter:
Ange ett datum (mm/dd/yy): 09/07/56
Datum på svenskt format: 1956-09-07
Övning 4.34:
Skriv ett program som läser in en mening, tar bort alla onödiga mellanslag före, i och efter
meningen, samt som skriver ut meningen igen utan onödiga mellanslag. Antalet ord i
meningen skall också skrivas ut. Programmet skall ha följande utskrifter:
Skriv in en textsträng: Jag förstår ingenting
Du matade in texten: Jag förstår ingenting
Textan består av 3 ord
Programmet skall fungera som exemplet Anders_A/cplusplus/uppg4_34.exe.
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 36 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
5. Fält (array)
Ett fält (kallas även array) påminner om en textsträng. Fältet består liksom textsträngen av ett
antal numrerade fack som man inte bara kan spara tecken i, utan även t ex decimal- och heltal
och strängar.
Övning 5.2:
Skriv ett program som fyller ett fält med 100 slumptal mellan 1 och 50. Talen i fältet skall
sedan skrivas ut snyggt i en tabell med tio rader och tio kolumner.
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 37 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
Övning 5.3:
Skriv ett program som fyller ett fält med 1000 slumptal mellan 1 och 50 och som sedan läser
in ett tal och kollar om talet finns med i fältet. Använd följande utskrifter:
Ange ett tal mellan 1 och 50: 34
Talet finns/finns ej med i fältet.
Övning 5.4:
Modifiera föregående program så att programmet räknar hur många det finns av det inlästa
talet i fältet, med följande utskrift:
Ange ett tal mellan 1 och 50: 34
Det finns 2 st tal 34 i fältet.
Övning 5.5:
Ett primtal är ett positivt heltal som endast är jämt delbart med 1 och med sig själv. Man kan
visa att ett tal är ett primtal om det inte är jämt delbart med något mindre primtal. Skriv ett
program som beräknar de första 50 primtalen och lägger dem i en tabell. När man ska avgöra
om ett visst tal är ett primtal eller inte, kan man alltså undersöka om talet är delbart med något
av de tal man hittills sparat i tabellen. Programmet ska skriva ut primtalen, enligt följande:
Utskrift av de första 50 primtalen:
2 3 5 7 11 13 17 19 23 29
31 37 41 43 47 53 59 61 67 71
73 79 83 89 97 101 103 107 109 113
127 131 137 139 149 151 157 163 167 173
179 181 191 193 197 199 211 223 227 229
Programmet skall fungera som exemplet Anders_A/cplusplus/primtal.exe.
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 38 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
Avslutad inmatning
Ett sätt att slippa ange hur många inmatningar som skall göras till ett fält, är att avsluta
inmatningen på ett lämpligt sätt. Vid inmatning av tal kan inmatningen avslutas med ett
tecken på följande sätt:
int nr = -1;
do
{
nr++;
cout << "Ange ett tal (avsluta med ett tecken): ";
}
while (cin >> tal[nr]);
Skall fler inmatningar göras med cin >> efter ovanstående do-while-loop måste
inmatningsbufferten rensas från det inmatade tecknet. Detta görs med följande två satser i
angiven ordning:
cin.clear();
cin.ignore(1000,'\n');
Vid inmatning av strängar avslutas inmatningen lämpligen med en tom inmatning:
int nr = -1;
do
{
nr++;
cout << "Ange ett namn (avsluta med tom Enter): ";
getline(cin,namn[nr]);
if (namn[nr].size()==0)
break;
}
while (true);
Här behöver ingen rensning av inmatningsbufferten göras. Observera att i båda fallen fylls
fälten till positionen nr-1.
Flerdimensionella fält
Ett flerdimensionellt fält kan betraktas som en tabell med rader och kolumner. Följande sats
deklarerar det flerdimensionella fältet tab, som lagrar heltal i fyra rader och fem kolumner:
int tab[4][5];
Figuren till höger illustrerar hur talet 75 lagras i andra raden och tredje
kolumnen, d v s i positionen (1, 2). Observera att indexet för rad och 75
kolumn börjar på 0:
tab[1][2]=75;
Det flerdimensionella fältet går även att initiera vid deklarationen:
int tab[4][5]={{11,23,15,4,12},{4,53,15,56,2},{41,93,95,8,22},{14,77,76,5,7}};
Tabell får då innehållet till höger. Följande kodrader skriver ut
11 23 15 4 12
innehållet i fältet på varsina rader med två nästlade for-loopar:
4 53 15 56 2
for (int i=0; i<4; i++)
for (int j=0; j<5; j++) 41 93 95 8 22
cout << temp[i][j] << endl;
14 77 76 5 7
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 39 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
Övning 5.6:
Skriv ett program där du först matar in hur många decimaltal du vill mata in och sedan matar
in decimaltalen och lägger dem i ett fält för decimaltal. Decimaltalen i fältet skall sedan
skrivas ut. Utskrifterna skall vara följande:
Ange antal decimaltal du vill mata in: 4
Ange decimaltalen: 1.5 23.7 64.9 5.3
Du matade in decimaltalen:
1: 1.5
2: 23.7
3: 64.9
4: 5.3
Övning 5.7:
Skriv ett program där du först matar in hur många namn du vill mata in och sedan matar in
namnen och lägger dem i ett fält för namnen. Namnen i fältet skall sedan skrivas ut.
Utskrifterna skall vara följande:
Ange antal namn du vill mata in: 3
Ange namnen:
Kalle
Lars
Pelle
Du matade in namnen:
1: Kalle
2: Lars
3: Pelle
Övning 5.8:
Skriv ett program där du matar in namn, maximalt tio stycken. Inmatningen avslutas med en
’tom’ inmatning. Namnen skrivs sedan ut på egna rader. Programmet skall fungera som
exemplet Anders_A/cplusplus/namnArr.exe.
Övning 5.9:
Skriv ett program som läser in efternamn, förnamn och ort för ett antal personer och som
sedan skriver ut personuppgifterna på en rad för respektive person, med följande utskrift:
Hur många personer vill du mata in: 2
Ange efternamn: Ek
Ange förnamn: Erik
Ange ort: Eksjö
Ange efternamn: Gran
Ange förnamn: Jan
Ange ort: Långban
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 40 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
Sortering
Vi har tidigare sorterat tal i storleksordning och namn i bokstavsordning med if-satser. Om ni
minns så var det ganska krångligt att göra det om det redan var tre tal eller namn. När vi nu
skall sortera tio och kanske tusen tal måste vi därför använda oss av fält och en enkel algoritm
(bubbelsort). Följande algoritm sorterar innehållet i ett fält i växande ordning:
for (int i=1;i<=4;i++)
for (int j=i+1;j<=5;j++)
if (tal[i]>tal[j])
{
temp=tal[i];
tal[i]=tal[j];
tal[j]=temp;
}
Om exempel fältet tal från början innehåller de fem osorterade heltalen: 25 12 32 6 11,
innehåller det sorterade fältet talen i stigande ordning: 6 11 12 25 32. Algoritmen fungerar
även för strängar.
Övning 5.10:
Skriv ett program som sparar 10 slumptal i ett fält och sedan skriver ut slumptalen sorterade.
Övning 5.11:
Skriv ett program som läser in ett antal namn och sedan skriver ut namnen i bokstavsordning.
Inmatningen avslutas med en tom inmatning. Programmet skall fungera som exemplet
Anders_A/cplusplus/sortera.exe.
*Övning 5.12:
Skriv ett program där du läser in ett antal namn och som sedan slumpmässigt drar tre namn ur
listan. Namnen på vinnarna skall sedan skrivas ut i vinstordning. Varje namn får bara finns
med en gång vid varje dragning. Ledning: Spara de dragna namnen i ett eget fält. Programmet
skall fungera som exemplet Anders_A/cplusplus/trevinnare.exe.
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 41 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
6. Funktioner
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 42 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
else
sub(); //Funktionen sub anropas här.
} //main slutar här.
Funktionerna add och sub brukar även kallas underprogram till huvudprogrammet main, som
egentligen är en vanlig funktion. Observera att funktionerna deklareras utan kod i början på
programmet (kallas även prototyp) och definieras med kod längre ner. Variablerna a och b är
lokala variabler i respektive funktion och endast användbara där, liksom variabeln val är lokal
i main-funktionen.
Övning 6.1:
Modifiera huvudprogrammet i exemplet ovan så att valen sker i en meny med följande
utseende:
main() //Huvudprogrammet börjar här
{
int val=1;
do
{
clrscr(); //Rensar skärm före nästa utskrift (kräver conio+.h)
cout << "Gör ett val i menyn nedan: " << endl;
cout << "1: Addition av två tal?: " << endl;
cout << "2: Subtraktion av två tal?: "<< endl;
cout << "3: Avsluta: "<< endl;
cin >> val;
switch (val)
{
case 1: add();break;
case 2: sub();break;
}
getch(); //Gör paus för att visa resultat av beräkning.
}
while (val!=3);
} //Huvudprogrammet slutar här.
Observera att programmet avbryts med val=3.
Övning 6.2:
Modifiera programmet ovan så att det även kan multiplicera respektive dividera två tal. Skriv
färdigt en funktion i taget och provkör sedan programmet. Är programmet lite längre blir det
ohanterligt många felmeddelanden om hel programmet skrivs färdigt innan det provkörs. Lös
därför uppgiften på följande sätt:
Lägg till en funktion mult som multiplicerar två tal.
Modifiera menyn så att det även går att välja multiplikation av två tal.
Provkör programmet och kolla att funktionen mult fungerar.
Lägg till en funktion div som multiplicerar två tal. Tänk på att datatypen vid division skall
vara för decimaltal (double).
Modifiera menyn så att det även går att välja division av två tal.
Provkör programmet. Fungerar det är det klart.
Övning 6.3:
Skriv ett program där du i huvudprogrammet via en meny kan välja mellan att beräkna arean
av en triangel, rektangel, cirkel och av ett klot. Areorna skall beräknas i fyra olika funktioner
(kallade triangel, rektangel, cirkel och klot) som anropas från huvudprogrammet via en liten
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 43 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
meny, där det även finns ett val för att avsluta programmet. Det skall gå att göra flera
beräkningar i samma körning (lägg menyn i en loop). Skärmen skall rensas mellan
körningarna. Tänk på att provkör varje funktion innan du börjar med nästa.
Parametrarna funktionen anropas med (x och y) behöver inte vara samma tecken som
parametrarna i funktionshuvudet (a och b). De måste dock vara av samma typ.
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 44 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
Övning 6.5:
Du skall skriva ett program som består av några funktioner du anropar från en meny i
huvudprogrammet main. Programmet har följande funktionsdeklarationer:
double max(int a, int b); // returnerar det största av talen a och b
double min(int a, int b); // returnerar det minsta av talen a och b
int slumptal(int tal); // returnerar ett slumtal mellan 1 och tal.
void maxtal(); // läser in två tal och skriver ut det största (anropar max)
void mintal(); // läser in två tal och skriver ut det minsta (anropar min)
void skriv_slumptal() // läser in ett positivt heltal N, skriver ut ett slumptal (anropar slumptal)
Menyn i huvudprogrammet skall innehålla följande val:
Gör ett val:
1: Beräkna det största av två tal.
2: Beräkna det minsta av två tal.
3: Generera ett slumptal.
4: Avsluta.
Under varje val skall sedan lämpliga inläsningar och utskrifter göras. Menyn skall ligga i en
while-loop.
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 45 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
}
…
Observera att parametern z i funktionsanropet måste vara en variabel. Fältparametrar är alltid
referensparametrar och skall anges utan &-tecken. Följande exempel visar en funktion som
fyller ett fält med antal slumptal:
void fyll(int a[], int antal); //Funktionen fyll deklareras
//==============================================
void fyll(int a[], int antal) //Funktionen fyll definieras
{
for (int i=0;i<antal;i++)
a[i]=rand()%100+1;
}
//===============================================
main()
{
int tal[100];
srand(time(0));
fyll(tal,5); //Funktionen fyll anropas och fyller fältet tal med 5 slumpal
for (int i=0;i<5;i++)
cout << tal[i] << endl;
}
Övning 6.6:
Gör ett program av funktionen maximal(…) i exemplet ovan, som returnerar den största av de
två inparametrarna som en referensparameter. In- och utmatning sker som i exemplet i
huvudprogrammet.
Övning 6.7:
Skriv ett program som i en funktion cirkel beräknar en cirkels omkrets och area. Omkretsen
och arean skall returneras via referensparametrar, enligt funktionshuvudet nedan:
cirkel(double radie, double& omkrets, double& area)
Inläsning, anrop av funktionen och utskrift görs i huvudprogrammet.
Övning 6.8:
Skriv en funktion i ett nytt program som avrundar till heltal med följande utseende:
int round(double x)
Provkör funktionen med anrop från huvudprogrammet med följande utskrift:
Ange ett decimaltal: 12.56
Avrundat till heltal blir det: 13
Observera att utskriften inte skall ske med formaterad utskrift (setprescision(0)…).
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 46 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 47 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
Static-parameter
Lokala variabler i en funktion initieras på nytt varje gång funktionen anropas, och när
programmet lämnar funktionen tappar variabeln sitt värde. Deklareras emellertid variabeln
som static behåller den sitt värde mellan anropen. Följande exempel illustrerar principen:
void skriv()
{
static int a=0;
a=a+1;
cout << "Nummer: " << a << endl;
}
//==============================================
main()
{
skriv();
skriv();
skriv();
}
Eftersom variabeln a är static-deklarerad initieras den med 0 endast vid första anropet.
Därefter behåller den sitt värde mellan anropen.
Överlagrade funktioner
I C++ kan olika funktioner ha samma namn och dess parametrar skiljer sig åt till antal och
datatyp. Funktioner med samma namn är överlagrade. Följande funktioner är alltså tillåtna i
samma program:
int max(int a, int b); //Två parametrar
int max(int a, int b, int c); //Tre parametrar
double max(double a, int b); //Olika datatyper
Default-parametrar
Tilldelas funktionens parametrar ett värde i funktionsdeklarationen, ett defaultvärde, kan
parametern utelämnas vid funktionsanropet. Följande exempel illustrerar detta:
void skriv(int a=8, int b=45); //Defaultparametrar med värdena 8 och 45
//==============================================
void skriv(int a, int b)
{
cout << a << " och " << b << endl;
}
//===============================================
main()
{
skriv(5,9); //Utskriften blir 5 och 9
skriv(5); //Utskriften blir 5 och 45. Observera att första parametern får nytt värde.
skriv(); //Utskriften blir 8 och 45
}
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 48 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
Rekursion
Med begreppet rekursion i datasammanhang menas en procedur eller funktion som anropar
sig själv. Rekursion användas för att åstadkomma upprepningar där det är svårt att använda
loopar, t ex används det ofta vid beräkning och uppritning av s k fraktaler. I följande exempel
beräknas summan 1+2+3+4+5 på tre olika sätt:
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 49 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
*Övning 6.10:
Skriv en funktion fib som beräknar det n:te Fibonaccitalet i talföljden 1, 1, 2, 3, 5, 8…
Funktionen skall anropas rekursivt och sakna loopar. Funktionen anropas med det n:te
Fibonaccitalet som parameter:
cout << Fib(n)
*Övning 6.11:
Skriv en funktion Fak som beräknar produkten 1234…n. Produkten kallas fakultet.
Funktionen skall anropas rekursivt och sakna loopar. Funktionen anropas med det sista talet i
produkten som parametrar:
cout << Fak(n);
*Övning 6.12:
Skriv en procedur Roten som beräknar en funktions y
nollställe (skärning med x-axeln) med y
*Övning 6.13:
Intervallhalvering har dålig konvergens vid rotberäkning, d v s det krävs många beräkningar
(intervallhalveringar) för att få fram ett bra värde på roten Skriv ett program som skiver ut x-
värdet vid vid varje intervallhalvering.
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 50 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
*Övning 6.14:
Newton-Raphsons metod för rotberäkning är betydligt y
y
effektivare än intervallhalvering. Om roten x söks i
ekvationen:
0 f ( x)
x1 x
Beräknas roten med följande iterationsformel:
x2
f ( x1 )
x 2 x1 ,
f ( x1 )
Iterationen pågår tills tillräcklig noggrannhet erhålls, t
ex när följande villkor är uppfyllt:
x1 x 2 0,000001
Newton-Raphsons metod bygger på att tangenten f´(x1):s skärning med x-axeln (x2) beräknas
upprepade gånger. Skriv ett program med en procedur raphson x1 som skriver ut x-värdet vid
vid varje nytt anrop.
Enkel grafik
Med följande funktion kan man rita enkla punktlinjer på skärmen:
void line(int x1, int y1, int x2, int y2)
{
double t=0;
int x,y;
while (t<=1)
{
x=round(x1+t*(x2-x1));
y=round(y1+t*(y2-y1));
gotoxy(x,y);
cprintf("%c",(char)219);
t=t+0.01; // Ökar parametern t långsamt för att undvika att linjerna
// blir glesa när de är sneda.
}
}
Funktionerna gotoxy och cprintf kräver inkluderingsfilen <conio.h> och funktionen round
rundar av decimaltal till heltal (se övning 6.8).
*Övning 6.15:
Skriv ett program som läser in två koordinater (x1, y1) och (x2, y2) och som ritar en linje
mellan dem. Inläsning av koordinaterna sker i huvudprogrammet. Använd funktionerna line i
exemplet ovan och round i övning 9.8 för att lösa uppgiften.
*Övning 6.16:
Modifiera programmet i föregående övning så att det även frågar efter linjens färg (ett heltal
mellan 1 och 16). När linjen ritats ut skall programmet fråga om fler linjer skall ritas ut. Om
man svarar ja raderas skärmen innan allt upprepas. All inläsning och utmatning skall ske
längst ner på skärmen (rad 24). Demoprogrammet h:/cplusplus/demo_9.10 visar hur det skall
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 51 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
fungera. Radtexten raderas genom att den skrivs ut en gång till på skärmen med bakgrundens
färg (BLACK), enligt följande exempel:
…
setcolor(WHITE);
gotoxy(1,24);
cprintf("Ange två koordinater : ");
cin >> x1 >> y1 >> x2 >> y2;
setcolor(BLACK);
gotoxy(1,24);
cprintf("Ange två koordinater : ");
setcolor(WHITE);
gotoxy(1,24);
…
*Övning 6.17:
Skriv ett program som slumpar ut 10 linjer på skärmen. Även linjernas färg skall slumpas.
*Övning 6.18:
Du skall nu göra ett längre grafiskt program uppbyggt på ett antal funktioner. Liksom tidigare
görs valen i en menyfunktion. Huvudprogrammet main innehåller endast anropet av
funktionen meny (se nedan). Programmet skall bestå av följande funktioner:
int round(double x) // Enligt uppgift 9.8
void line(int x1, int y1, int x2, int y2) // Enligt exemplet ovan.
void rita_linje() // Läser in två koordinater och anropar sedan funktionen line(..).
void rektangel(int x1, int y1, int x2, int y2) // Ritar en rektangel med övre vänstra hörnet i punkten
(x1, y1) och nedre högra hörnet i punkten (x2, y2).
void rita_rektangel() // Läser in två koordinater och anropar sedan funktionen rektangel(..)
void triangel(int x1, int y1, int x2, int y2, int x3, int y3) // Ritar en triangel med hörnen i punkterna
//(x1, y1), (x2, y2) och (x3, y3) med hjälp av funktionen line(..).
void rita_triangel() // Läser in tre koordinater och anropar sedan funktionen triangel(..)
*void cirkel(int r, int x, int y) // Ritar en cirkel med centrum i punkten (x, y) och radien r.
*void rita_cirkel() // Läser in koordinat för cirkelns centrum och dess radie och anropar sedan
funktionen cirkel(..) för att rita cirkeln.
*void rita_polygon() // Läser in polygonens antal hörn och sedan dess koordinater, som förslagsvis
sparas i två fält, ett för x-koordinaterna (x[i]) och ett för y-koordinaterna (y[i]). Polygonen ritas
sedan med funktionen line(..).
void meny() // Härifrån görs via en meny anropen av funktionerna rita_linje(), rita_rektangel(),
rita_triangel(), rita_cirkel() och rita_polygon().
Alla variabler skall vara lokala i respektive funktion. När ett val gjorts i menyn skall texten
raderas innan utskrift och inläsning sker i respektive funktion, som i sin tur raderas när
figuren ritas. Enter-tangenten skall tryckas ned innan figuren raderas och återgång sker till
menyn.
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 52 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
*Övning 6.20:
Modifiera övning 6.17 så att en ny linje ritas ut varje sekund.
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 53 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
7. Filhantering
Hittills när vi kört våra program har all inmatning skett via tangentbordet. Det vi matat in har
samtidigt försvunnit i samband med att exekveringen avslutats. Under sådana omständigeter
är det ju ganska meningslöst att exempelvis lägga upp ett adressregister. Det går emellertid att
båda läsa från och skapa externa filer. Exempelvis kan vi ganska enkelt låta ett program läsa
och skriva ut innehållet i en vanlig textfil, som är skapad i programmen Anteckningar, eller
TextPad. Lika enkelt kan programmet lagra information i en textfil för läsning vid ett senare
tillfälle. Vi skall nu lära oss hur detta går till i C++.
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 54 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
Övning 7.2:
Skapa ett nytt kort textdokumet, men spara det nu i en annan mapp. Kör programmet ovan
igen för den nya textfilen. Glöm inte att ange sökvägen.
Övning 7.4:
Skriv ett program som läser in ett filnamn och sedan beräknar och skriver ut hur många
tecken filen totalt innehåller, med följande utskrifter:
Ange ett filnamn: kalle.txt
Filen innehåller 12 tecken
Provkör filen på en kortare fil som är lätt att kontrollräkna. Provkör sedan på en längre fil,
förslagsvis j:/Anders_A/cplusplus/helger.txt.
Övning 7.5:
Skriv ett program som läser in ett filnamn, ett tecken och som sedan beräknar och skriver ut
hur många sådana tecken filen innehåller. Provkör på en kort fil så att du enkelt kan
kontrollräkna antalet. Använd följande utskrifter:
Ange ett filnamn: kalle.txt
Ange tecknet du vill beräkna antalet av: a
Tecknet a förekommer 6 gånger i filen kalle.txt
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 55 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
Övning 7.6:
Modifiera föregående övning så att du kan mata in fler tecken utan att avbryta exekveringen
(lägg in ytterligare loop med en fråga om fler tecken skall matas in):
Ange ett filnamn: kalle.txt
Ange tecknet du vill beräkna antalet av: a
Tecknet a förekommer 6 gånger i filen kalle.txt
Vill du beräkna för fler tecken (j/n)? j
Övning 7.7:
I övning 7.4 räknades alla tecken; stora och små bokstäver, kommatecken, mellanslag o s v.
a) Modifiera övning 7.4 så att bokstäverna a-z räknas (stora och små). Det är enklare att
räkna dessa tecken eftersom de ligger eftervarandra i ASCII-koden. Tänk på att konvertera
stora bokstäver till små vid beräkningen.
b) Modifiera ytterligare så att även bokstäverna å, ä, ö, Å, Ä och Ö räknas.
c) Räkna antalet meningar genom att räkna antalet punkter, frågetecken och utropstecken.
d) Räkna antalet ord genom att räkna antalet mellanslag. Det färdiga programmet skall ha
följande utskrift, där även medelordlängden beräknas:
Ange ett filnamn: kalle.txt
Filen innehåller 357 bokstäver, 18 meningar och 91 ord. Medelordlängden är 3.92 bokstäver.
*Övning 7.8:
Skriv ett program som läser in ett filnamn och som sedan skriver ut hur många bokstäver av
varje sort (antal och procent med en decimal) filen innehåller. För enkelhetsskull räknar
programmet endast de små bokstäverna a-z därför att dessa ligger efter varandra i ASCII-
koden. Provkör först på en kortare fil och kontrollräkna. Vilka bokstäver är mest
förekommande? Ledning: Följande for-sats räknar upp tecknen i ordning (a, b, c, …, z):
for (char c='a'; c<='z'; c++)
Använd ett heltalsfält antal för att lagra tecknen i (som i övning 59 när vi räknade slumptal).
Följande sats omvandlar tecken till heltal vid lagring i fältet antal:
antal[(int)c]
Programmet skall fungera som exemplet Anders_A/cplusplus/antal_letter.exe.
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 56 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
Övning 7.9:
Kopiera det första av ovanstående exempel och provkör det. Öppna sedan den skapade
textfilen och kolla att den inmatade texten finns där.
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 57 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
Övning 7.11:
Modifiera övning 7.10 så att texten läggs till i slutet på en existerande fil.
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 58 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
Strukturen struct
C++ innehåller liksom andra programspråk färdiga datatyper för bl a heltal och tecken. Ibland
krävs emellertid mer sammansatta datatyper. Antag att man skall lagra uppgifter om en
person, t ex fönamn, efternamn och ålder. Då är det ju praktiskt att kunna lagra alla dessa
uppgifter i en variabel. I C++ åstadkomms detta genom att deklarera en egendefinierad
sammansatt datatyp, en s k struct. Den kallas ibland även för posttyp. Följande rader
deklarerar den objektliknande egendefinierade datatypen person innehållande de tre
fältnamnen fnamn, enamn och age:
struct person
{
char fnamn[10], enamn[20];
int age;
};
Definitionen av en struct görs globalt överst i programmet. Vi kan nu deklarera två variabeler,
t ex person1och p, med våran sammansatta datatyp person:
person person1, p;
Variablerna person1 och p innehåller både förnamn, efternamn och ålder. Dessa tilldelas med
punktnotation på följande sätt:
strcpy(person1.fnamn,”Kalle”);
strcpy(person1.enamn,”Larsson”);
person.age = 18;
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 59 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 60 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
Binära filer
Även sammansatt variabler av datatypen struct kan lagras i externa filer, s k binära filer. De
lagras dock inte på samma sätt som tecken och strängar. Dels är inte den binära filen direkt
läsbar på samma sätt som en textfil, dels är syntaxen något annorlunda. Följande funktion
visar hur lagring görs av innehållet i fältet folk[i] av den sammansatta typen person (se ovan)
på binärfilen andersfil.bin:
void spara()
{
ofstream f1("andersfil.bin",ios::binary); //Anger att en binär fil öppnas för lagring
for (int i=1; i<=antal;i++)
{
f1.write((char *)&folk[i],sizeof(folk[i])); //Lagrar folk[i] på filen
}
f1.close(); //Filen stängs
}
Liksom tidigare kopplas här filvariabeln f1 till filen andersfil.bin. Här lagras varje person
(folk[i]) som enskilda ’paket’ på filen. I anropet görs en typkonvertering (char *) av folk[i] till
tecken, medan & anger adressen där folk[i] är lagrad på ramminnet. Paketets storlek, d v s
storleken hos strukturen person, anges med sizeof(). Flertalet datatyper kan lagras på en
binärfil. Följande sats lagrar innehållet hos heltalsvariabeln kalle på en binärfil:
f1.write((char *)&kalle,sizeof(kalle);
Observera att variabler av klassen string dock inte kan lagras på en binärfil. Därför är
fältnamnen fnamn och enamn i strukturtypen person ovan deklarerade som fält av tecken
(char). I exemplet ovan raderas eventuellt innehåll i filen när den öppnas. Med tillägget
ios::app läggs lagrad data i slutet på en existerande binärfil:
ofstream f1("andersfil.bin",ios::binary|ios::app);
Följande funktion läser från binärfilen andersfil.bin till fältet folk[]:
void hamta()
{
int i=0;
person p;
ifstream f1("andersfil.bin",ios::binary); //Anger att en binär fil öppnas för läsning
while (f1.read((char *)&p,sizeof(p))) //Läser till filslutet. Data läggs i variabeln p
{
i++;
folk[i]=p; //Innehållet i strukturen p lagras i fältet folk
}
f1.close(); //Filen stängs
}
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 61 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
*Övning 7.13:
Skriv ett program för träning av glosor. I programmet skall man kunna mata in glosor (t ex
svenska och engelska), göra förhör (slumpmässigt) mellan båda språken, samt kunna lagra de
inmatade glosorna på en binärfil. Man skall även kunna välj om glosorna skall lagras i en ny
fil eller om de skall kunna läggas sist i en redan existerande fil. Du kan spara arbete genom att
kopiera föregående uppgift och modifiera den på lämpligt sätt. Änvänd förslagsvis följande
globala struktur och fält för att lagra glosorna:
struct glos_strukt
{
char sv[20], en[20];
};
glos_strukt glosor[100];
Programmet kan fungera ungefär som exemplet Anders_A/cplusplus/glosor.exe.
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 62 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 63 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 64 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
Övning 7.14:
Du skall nu skapa ett funktionsbibliotek, d v s en egen inkluderingsfil, för några användbara
funktioner du skrivit under kursen. Inkluderingsfilen skall sparas under filnamnet
mitt_bibliotek.h. Lägg in följande funktioner och tillhörande inkluderingsfiler i biblioteket:
a) int slumptal(int tal) //Från uppgift 9.6. Lägg srand(time(0)) i funktionen
b) int rest(int a, int b) //Från uppgift 9.6
c) int round(double x) //Från uppgift 9.8
d) void write(double x, int a, int b) //Skriver ut decimaltalet x på a positioner med b decimaler
Skriv nu ett program och provkör funktionerna. Gör ingen meny, utan provkör på enklaste sätt
en funktion i taget i huvudprogrammet. Inkludera endast ”mitt_bibliotek.h” i programmet.
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 65 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
8. Objektorientering
Skälet till att C++ är ett av de mest använda programspråken är att det är objektorienterat.
Detta bygger vidare på begreppet struct (ursprungligen från språket C som inte är
objektorienterat), som i objektorienteringen kallas klass. Främsta skillnaden mellan begreppen
struktur och klass är att en klass även kan innehålla funktioner (metoder), samt att man kan
härleda nya klasser utifrån en annan (bas-) klass.
Medlemsfunktioner
Vi vill emellertid utöka vår klassdefinition med två medlemsfunktioner (metoder) för
inläsning respektive utskrift. Vi vill dessutom inte att datamedlemmarna skall vara synliga
utifrån; en användare har inget intresse av att veta hur dessa ser ut, utan vill ju bara kunna
använda klassens funktioner. Klassvariablerna deklareras därför som private. För att komma
åt klassvariablerna måste vi därför skapa ytterligare fem medlemsfunktioner, som deklareras
som public:
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 66 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 67 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
Många menar att klassdefinitionen skall hållas ren från funktionsdefinitioner, d v s alla
medlemsfunktioner (även korta) bör definieras separat utanför klassdefinitionen. Det ger en
renare klassdefinition och ökar läsbarheten.
Konstruktor
Vanliga variabler kan som bekant initieras vid deklarationen:
int i=0;
Detta är emellertid inte tillåtet för klassvariabler, d v s klassens datamedlemmar. De kan dock
initieras med en konstruktor, som liksom en funktion anropas vid deklarationen (instansen) av
variabeln (objektet). Konstruktorn är en typlös (även utan void) medlemsfunktion med samma
namn som klassen. Klassen kan dock innehålla flera konstruktorer, men med olika antal
parametrar, d v s de är då överlagrade. Följande klassdefinition innehåller två konstruktorer:
class Person
{
public:
Person (int ag,int le,int vi) //Konstruktor med parametrar
{
age=ag;
lengd=le;
vikt=vi;
}
Person() //Konstruktor utan parametrar (default-konstruktor)
{age=lengd=vikt=0;}
void inmatning(char fn[],char en[],int ag,int le,int vi);
void skriv_namn();
int ge_alder() {return age;}
int ge_langd() {return lengd;}
int ge_vikt() {return vikt;}
private:
char fnamn[20], enamn[20];
int age, lengd, vikt;
};
int main()
{
Person p1, p2(45,181,73); //Objekten p1 och p2 deklareras.
cout<<"Ålder:"<<p1.ge_alder()<<"Längd:"<<p1.ge_langd()<<"Vikt:"<<p1.ge_vikt()
<<endl;
cout<<"Ålder:"<< p2.ge_alder()<<"Längd:"<<p2.ge_langd()<<"Vikt:"<<p2.ge_vikt()
<<endl;
return 0;
}
Den första konstruktorn innehåller parametrar för ålder, längd och vikt. Variabeln (objektet)
p2:s klassvariabler (datamedlemmar) tilldelas alltså åldern 47, längden 181 och vikten 73 vid
anropet. Variabeln p1 deklareras utan parametrar, men eftersom vi har deklarerat en
parameterlös konstruktor blir den default-konstruktor som anropas automatiskt vid
deklarationen om inga parametrar anges. Variabeln p1 initieras alltså med värdet 0 på de tre
datamedlemmarna.
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 68 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
Separat konstruktordefinition
Konstruktorns definition kan liksom för medlemsfunktioner göras separat utanför
klassdefinitionen. Följande exempel visar hur detta ser ut för den parameterlösa konstruktorn
Person():
//------------------------------------------------------------------------------------------------
class Person
{
public:
Person (int ag,int le,int vi)
{
age=ag;
lengd=le;
vikt=vi;
}
Person(); //Konstruktorns deklaration
void inmatning(char fn[],char en[],int ag,int le,int vi);
void skriv_namn();
int ge_alder() {return age;}
int ge_langd() {return lengd;}
int ge_vikt() {return vikt;}
private:
char fnamn[20], enamn[20];
int age, lengd, vikt;
};
//------------------------------------------------------------------------------------------------
Person::Person() //Konstruktorns definition utan void
{
age=lengd=vikt=0;
}
//------------------------------------------------------------------------------------------------
Observera att konstruktorns definition saknar inledande void.
Initieringslista
En tredje rekommenderad variant (fungerar även för datamedlemmar som är konstanter) är att
tilldela klassvariablerna via en initieringslista. Följande exempel illustrerar detta för
konstruktorn med parametrar:
//------------------------------------------------------------------------------------------------
class Person
{
public:
Person (int ag,int le,int vi); //Konstruktorns deklaration
Person();
void inmatning(char fn[],char en[],int ag,int le,int vi);
void skriv_namn();
int ge_alder() {return age;}
int ge_langd() {return lengd;}
int ge_vikt() {return vikt;}
private:
char fnamn[20], enamn[20];
int age, lengd, vikt;
};
//------------------------------------------------------------------------------------------------
Person::Person()
{
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 69 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
age=lengd=vikt=0;
}
//------------------------------------------------------------------------------------------------
Person::Person (int a, int l, int v) //Konstruktorns deklaration
:age(a), lengd(l), vikt(v) {} //Initieringslistan inleds med :, avslutas med tom {…}
//----------------------------------------------------------------------------------------------
Observera parameterlistans inledande kolon och de avslutande tomma klamrarna.
Destruktor
En destruktor är liksom en konstruktor en typlös medlemsfunktion. Men medan konstruktorn
allokerar minnesutrymme när ett objekt skapas (variabeldeklareras), frigör destruktorn minne
när objektet upphör att existera. I vårt program, där vi ännu arbetar med statiska objekt (d v s
minnet allokeras vid kompileringen via variabeldeklarationer), anropas destrukorn automatisk
när programmet avslutas. Snart kommer vi emellertid att arbeta med dynamiska objekt (d v s
minnet allokeras dynamiskt under exekveringen) och då är det viktigt att kunna frigöra minne
(d v s ta bort objekt) som inte längre används under exekveringen. Följande kod visar
klassdefinitionen Person med en destruktor. Observera att klassdefinitionen får innehålla
endast en destruktor:
class Person
{
public:
Person (int ag,int le,int vi);
Person();
~Person() //Här är destruktorn deklarerad.
{cout << "Objektet med åldern " << age << " tas bort." << endl;}
void inmatning(char fn[],char en[],int ag,int le,int vi);
void skriv_namn();
int ge_alder() {return age;}
int ge_langd() {return lengd;}
int ge_vikt() {return vikt;}
private:
char fnamn[20], enamn[20];
int age, lengd, vikt;
};
Tecknet (~) framför destruktorns deklaration kallas tilde. Destruktorn ovan innehåller kod
som talar om att att ett visst objekt tas bort. Vanligtvis innehåller destruktorn naturligtvis
ingen kod.
Separat destruktordefinition
I följande klassdefinition definieras destruktorn utan kod separat utanför klassdefinitionen:
//------------------------------------------------------------------------------------------------
class Person
{
public:
Person (int ag,int le,int vi); //Konstruktorns deklaration
Person(); //Konstruktorns deklaration
~Person(); //Destruktorns deklaration
void inmatning(char fn[],char en[],int ag,int le,int vi);
void skriv_namn();
int ge_alder() {return age;}
int ge_langd() {return lengd;}
int ge_vikt() {return vikt;}
private:
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 70 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 71 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
lagring på och läsning från binärfil i övning 7.12. Inga globala variabler skall användas. Lös
uppgiften på följande sätt:
I main-funktionen deklareras variabeln antal, som håller reda på antalet personer, samt
fältet folk för lagring av maximalt 10 personer:
Person folk[10];
Följande funktioner skall kunna aropas pron menyn i main-funktionen:
void fyll(Person f[], int& antal); läser in och lagrar personens förnamn, efternamn,
födelseår, längd och vikt i fältet.
void skriv(Person f[], int antal); skriver ut personernas förnamn, efternamn, ålder
BMI och status (se nedan) i en snygg tabell.
void medelvarde(Person f[],int antal); skriver ut medelvärdet för samtligas vikt, ålder
och BMI.
void spara(Person f[],int antal); lagrar personerna på en binärfil.
void hamta(Person f[],int& antal); läser in personerna från en binärfil.
Klasser av klasser
Det är ofta praktiskt att deklarera klassvariabler och klassmetoder av andra egendefinierade
klasser.
Två klasser
Följande programexempel visar en struktur för hur elever kan lagras med två klasser, där
klassen Klass bygger på klassen Elev:
#include <iostream>
#include <fstream>
#include "conio+.h"
#include <string>
#include <stdlib.h>
#include <iomanip>
#include "svtecken.h"
using namespace std;
//------------------------------------------------------------------------------------------------
class Elev
{
char fnamn[20], enamn[20]; //Klassvariabler är Private
int foddar;
public:
void inmatning_elev();
void skrivut_elev(char klass[]);
};
//------------------------------------------------------------------------------------------------
class Klass
{
int elevantal;
char klassnamn[5]; //Lagrar klassnamn (TE3, NV2...)
Elev eleverna[40]; //Lagrar klassens elever
public:
Klass(); //Default-konstruktor sätter elevantal till 0 och läser in klassnamn
void inmatning_klass();
void inmatning_klassnamn();
void skrivut_klass();
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 72 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
};
//----------------------------------------------------------------------------------------------
Klass::Klass() //Default-konstruktorns definition
{
elevantal=0;
inmatning_klassnamn();
}
//----------------------------------------------------------------------------------------------
void Elev::inmatning_elev()
{
cout << "Ange förnamn: ";
cin >> fnamn;
cout << "Ange efternamn: ";
cin >> enamn;
cout << "Ange födelseår: ";
cin >> foddar;
}
//------------------------------------------------------------------------------------------------
void Elev::skrivut_elev(char klass[])
{
cout << klass << setw(20) << enamn << setw(20) << fnamn << setw(15) << foddar<<
endl;
}
//------------------------------------------------------------------------------------------------
void Klass::inmatning_klassnamn()
{
cout << "Ange klassnamn (TE1, NV2 ...): ";
cin >> klassnamn;
}
//------------------------------------------------------------------------------------------------
void Klass::inmatning_klass()
{
int n;
cout << "Hur många elevnamn vill du mata in i klass " << klassnamn << "?";
cin >> n;
for (int i=elevantal+1; i<=elevantal+n; i++)
eleverna[i].inmatning_elev(); //Metod i Elev används
elevantal=elevantal+n;
}
//------------------------------------------------------------------------------------------ ------
void Klass::skrivut_klass()
{
cout << "Klass" << setw(20) << "Efternamn" << setw(20) << "Förnamn" << setw(15) <<
"Födelseår"<< endl;
for (int i=1; i<=elevantal; i++)
eleverna[i].skrivut_elev(klassnamn); //Metod i Elev används
}
//------------------------------------------------------------------------------------------------
int main()
{
Klass te3, nv3; //Instans av objekten te3 och nv3 initieras av
teckenbyt(); //default-konstruktorn
te3.inmatning_klass();
te3.skrivut_klass();
te3.inmatning_klass(); //Ytterligare inmatning för att illustrera att elevantal ökas
te3.skrivut_klass();
return 0;
}
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 73 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
Observera att Klass-konstruktorn nollställer objektets antal klasser från början, samt tilldelar
objektet klassnamnet.
Tre klasser
Gymnasiet är ju uppbyggt kring program (TE, NV, SP), som är utgörs av klasser (TE1, TE2,
NV1…), som i sin tur består av elever. I nästa exempel har därför klassen Program införts för
att illusterera hur ett program som bygger på tre klasser kan se ut, d v s klassen Program
bygger på klassen Klass som bygger på klassen Elev:
//------------------------------------------------------------------------------------------------
class Elev
{
char fnamn[20], enamn[20]; //Klassvariabler är Private
int foddar; //Födelseår
public:
void inmatning_elev();
void skrivut_elev(char klass[]);
};
//------------------------------------------------------------------------------------------------
class Klass
{
int elevantal; //Antal elever i klassen
char klassnamn[5]; //Lagrar klassnamn (TE3, NV2, SP2a...)
Elev eleverna[40]; //Lagrar klassens alla elever
public:
Klass(); //Default-konstruktor sätter elevantal till 0
void inmatning_klass();
void inmatning_klassnamn();
void skrivut_klass();
string skrivut_klassnamn(){return klassnamn;} //Korta definitioner gör här. Obs string!
int skrivut_elevantal(){return elevantal;} //Behövs för att kunna skrivas i Program-metod
};
//----------------------------------------------------------------------------------------------
class Program
{
int klassantal; //Antal klasser på programmet
char prognamn[20]; //Lagrar programnamnet (Teknik, Natur, Samhäll…)
Klass klass[10]; //Lagrar klasserna som ingår i programmet
public:
Program(); //Programkonstruktor sätter klassantal till 0 och läser in prognamn
void inmatning_program();
void skrivut_program();
void matain_elever(); //Läser in elever till vald klass
void skrivut_elever(); //Skriver ut elever från vald klass
};
//----------------------------------------------------------------------------------------------
Klass::Klass() //Default-konstruktorns definition
{
elevantal=0;
}
//----------------------------------------------------------------------------------------------
Program::Program() //Default-konstruktorns definition
{
klassantal=0;
cout << "Ange programnamn (Teknik, Natur ...): ";
cin >> prognamn;
}
//----------------------------------------------------------------------------------------------
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 74 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
void Elev::inmatning_elev()
{
cout << "Ange förnamn: ";
cin >> fnamn;
cout << "Ange efternamn: ";
cin >> enamn;
cout << "Ange födelseår: ";
cin >> foddar;
}
//------------------------------------------------------------------------------------------------
void Elev::skrivut_elev(char klass[])
{
cout << klass << setw(20) << enamn << setw(20) << fnamn << setw(15) << foddar<<
endl;
}
//------------------------------------------------------------------------------------------------
void Klass::inmatning_klassnamn()
{
cout << "Ange klassnamn (TE1, NV2 ...): ";
cin >> klassnamn;
}
//------------------------------------------------------------------------------------------------
void Klass::inmatning_klass()
{
int n;
cout << "Hur många elevnamn vill du mata in i klass " << klassnamn << "?";
cin >> n;
for (int i=elevantal+1; i<=elevantal+n; i++)
eleverna[i].inmatning_elev();
elevantal=elevantal+n;
}
//------------------------------------------------------------------------------------------------
void Klass::skrivut_klass()
{
cout << "Klass" << setw(20) << "Efternamn" << setw(20) << "Förnamn" << setw(15) <<
"Födelseår"<< endl;
for (int i=1; i<=elevantal; i++)
eleverna[i].skrivut_elev(klassnamn); //Metod i Elev används
}
//------------------------------------------------------------------------------------------------
void Program::inmatning_program()
{
int n;
cout << "Hur många klasser vill du lägga till för " << prognamn << "-programmet?";
cin >> n;
for (int i=klassantal+1; i<=klassantal+n; i++)
{
klass[i].inmatning_klassnamn(); //Metoderna i Klass används
klass[i].inmatning_klass();
}
klassantal=klassantal+n;
}
//------------------------------------------------------------------------------------------------
void Program::matain_elever()
{
int n;
cout << "Ange för vilken klass du vill mata in elever: " << endl;
for (int i=1; i<=klassantal; i++)
cout << i << setw(10) << klass[i].skrivut_klassnamn() << endl;
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 75 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
cin >> n;
klass[n].inmatning_klass(); //Metoderna i Klass används
}
//------------------------------------------------------------------------------------------------
void Program::skrivut_elever()
{
int n;
cout << "Ange för vilken klass du vill mata in elever: " << endl;
for (int i=1; i<=klassantal; i++)
cout << i << setw(10) << klass[i].skrivut_klassnamn() << endl;
cin >> n;
klass[n].skrivut_klass();
}
//------------------------------------------------------------------------------------------------
void Program::skrivut_program()
{
cout << setw(15) <<"Program"<<setw(10) << "Klass" <<setw(12) << "Elevantal" <<
endl;
for (int i=1; i<=klassantal; i++)
cout << setw(15) << prognamn << setw(10) <<
klass[i].skrivut_klassnamn() << setw(12) << klass[i].skrivut_elevantal() << endl;
}
//------------------------------------------------------------------------------------------------
int main()
{
Program te; //Instans av objektet te
teckenbyt();
te.inmatning_program();
te.skrivut_program();
te.matain_elever();
return 0;
}
Notera att hur metoderna i underliggande klasser används. Tänk även på att klassvariabler
som är Private i t ex klassen Klass inte är läsbara i klassen Program, trots att klassvariabeln
klass[10] är deklarerad som Klass i klassen Program. För att komma åt klassvariabeln
elevantal i en Program-metod måste därför metoden Klass-metoden skrivut_elevantal()
användas.
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 76 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
Övning 8.3:
Du skall nu skriva ett grafiskt program som hanterar punkter, linjer och rektanglar.
Programmet skall fungera som exemplet Anders_A/cplusplus/klass_8_3.exe. Programmet
skall använda följande tre klasser:
#include <windows.h> //Behövs för funktionerna min och max nedan
//------------------------------------------------------------------------------------------------
class Punkt
{
public:
int x,y,farg; //Färg är ett värde mellan 1-16
Punkt(){farg=7;} //Defaultkonstruktor ger standardfärgen 7
void inmatning_punkt(); //Inmatning via tangentbord till x och y
void inlasning_punkt(int u, int v); //Inläsning via parametrar till x och y
void rita_punkt(); //Ritar ut punkten (se nedan)
};
//------------------------------------------------------------------------------------------------
class Linje
{
public:
Punkt p1,p2;
int farg;
Linje(){farg=7;}
void rita_linje();
double stracka(); //Beräknar sträckan mellan p1 och p2
};
//------------------------------------------------------------------------------------------------
class Rektangel
{
public:
Punkt p1,p2; //Diagonala punkter i rektangeln
int farg;
Rektangel(){farg=7;}
void rita_rektangel();
double area(); //Beräknar rektangelns area
};
//------------------------------------------------------------------------------------------------
Till din hjälp får du även följande funktioner:
//------------------------------------------------------------------------------------------------
void Linje::rita_linje() //Ritar en linje
{
double t=0;
int x,y;
setcolor(farg);
while (t<=1)
{
x=round(p1.x+t*(p2.x-p1.x));
y=round(p1.y+t*(p2.y-p1.y));
gotoxy(x,y);
cprintf("%c",(char)219);
t=t+0.01; //Undviker ”hål” i linjen
}
}
//------------------------------------------------------------------------------------------------
void Punkt::rita_punkt() //Ritar en liten fyrkant
{
setcolor(farg);
gotoxy(x,y);
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 77 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 78 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 79 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
//------------------------------------------------------------------------------------------------
class Fordon
{
protected: //Protected gör att datamedlemmarna blir läsbara i härledda klassen.
int ant_hjul, vikt;
public:
Fordon(int a, int v);
void skrivut();
};
//------------------------------------------------------------------------------------------------
class Cykel : public Fordon //Klassen Cykel ärver klassen Fordons egenskaper
{
int ant_vaxel; //Cykelns antal växlar
char typ[20]; //Cykeltyp (herr, dam, barn...)
public:
Cykel(int ahj, int vi, int av, char ty[]); //Konstruktordeklaration
void skrivut(); //Metoddeklaration för utskrift av datamedlemmarna
};
//------------------------------------------------------------------------------------------------
Fordon::Fordon(int a, int v)
{
ant_hjul=a;
vikt=v;
}
//------------------------------------------------------------------------------------------------
void Fordon::skrivut()
{
cout << "Antal hjul:" << ant_hjul << endl;
cout << "Vikt:" << vikt << endl;
}
//------------------------------------------------------------------------------------------------
Cykel::Cykel(int ahj, int vi, int av, char ty[]) : Fordon(ahj,vi) //Konstruktordefinition för klassen Cykel
{ //Observera att klassen Fordons konstruktor tar hand om parametrarna ahj (antal_hjul) och vi(-kt)
ant_vaxel=av;
strcpy(typ,ty);
}
//------------------------------------------------------------------------------------------------
void Cykel::skrivut()
{
cout << "En cykel" << endl;
cout << "Antal växlar:" << ant_vaxel << endl;
cout << "Typ:" << typ << endl;
Fordon::skrivut(); //Metod ur Fordon anropas. Klassnamnet anges därför att
//metoden har samma namn som i Cykel
}
//------------------------------------------------------------------------------------------------
int main()
{
Cykel c(2,17,21,"Herr"); //Deklaration (instans) av objektet c
teckenbyt();
c.skrivut();
getch();
return 0;
}
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 80 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 81 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
};
//------------------------------------------------------------------------------------------------
class Motorfordon: public Fordon
{
protected:
char marke[20],reg[10];
public: //Fordon:s konstruktor läser in parametrar från Motorfordons konstruktor
Motorfordon(int ahj, int vi, char re[], char ma[]): Fordon(ahj,vi)
{strcpy(reg,re);strcpy(marke,ma);}
void skrivut();
};
//------------------------------------------------------------------------------------------------
class Personbil: public Motorfordon
{
protected:
int pass; //Antal passagerar
char modell[10]; //Astra, S80...
public:
Personbil(int ahj, int vi, char re[], char ma[], char mo[],int pa):
Motorfordon(ahj,vi,re,ma), pass(pa){strcpy(modell,mo);}
void skrivut();
};
//------------------------------------------------------------------------------------------------
class Lastbil : public Motorfordon
{
protected:
int last; //Last i kg
public:
Lastbil(int ahj, int vi, char re[], char ma[],int la): Motorfordon(ahj,vi,re,ma),last(la){}
void skrivut();
};
//------------------------------------------------------------------------------------------------
void Fordon::skrivut()
{
cout << "Antal hjul:" << ant_hjul << endl;
cout << "Vikt:" << vikt << endl;
}
//------------------------------------------------------------------------------------------------
void Cykel::skrivut()
{
cout << "Antal växlar:" << ant_vaxel << endl;
cout << "Cykeltyp:" << typ << endl;
Fordon::skrivut(); //Metod ur klassen Fordon anropas.
}
//------------------------------------------------------------------------------------------------
void Motorfordon::skrivut()
{
cout << "Märke:" << marke << endl;
cout << "Registernummer:" << reg << endl;
Fordon::skrivut();
}
//------------------------------------------------------------------------------------------------
void Personbil::skrivut()
{
cout << "En personbil" << endl;
cout << "Antal passagerare:" << pass << endl;
cout << "Modell:" << modell << endl;
Motorfordon::skrivut(); //Metod ur klassen Motorfordon anropas.
}
//------------------------------------------------------------------------------------------------
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 82 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
void Lastbil::skrivut()
{
cout << "En lastbil" << endl;
cout << "Lastkapacitet:" << last << endl;
Motorfordon::skrivut();
}
//------------------------------------------------------------------------------------------------
int main()
{
Cykel c(2,17,21,"Herr");
c.skrivut();
getch();
return 0;
}
Figuren till höger visar arvsstrukturen. Observera att alla
metoder ärvs till underliggande klasser. Exempelvis kan Fordon
Multipelt arv
Hittills har våra härledda klasser ärvt egenskaper från en basklass. En klass kan emellertid
ärva från flera basklasser, s k multipelt arv. I följande exempel har föregående klass
kompletterats med klassen Buss, med klasserna Personbil och Lastbil som basklasser:
//------------------------------------------------------------------------------------------------
class Fordon
{
protected:
int ant_hjul, vikt;
public:
Fordon(int a, int v):ant_hjul(a),vikt(v){}; //Konstruktor tilldelas med initieringslista
void skrivut();
};
//------------------------------------------------------------------------------------------------
class Motorfordon: public Fordon
{
protected:
char marke[20],reg[10];
public:
Motorfordon(int ahj, int vi, char re[], char ma[]):
Fordon(ahj,vi){strcpy(reg,re);strcpy(marke,ma);}
void skrivut();
};
//------------------------------------------------------------------------------------------------
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 83 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
{
protected:
int pass; //Antal passagerar
char modell[10]; //Astra, S80...
public:
Personbil(int ahj, int vi, char re[], char ma[], char mo[],int pa):
Motorfordon(ahj,vi,re,ma),pass(pa){strcpy(modell,mo);}
void skrivut();
};
//------------------------------------------------------------------------------------------------
class Lastbil : virtual public Motorfordon //Klassen Motorfordon ärvs virtuellt
{
protected:
int last; //Last i kg
public:
Lastbil(int ahj, int vi, char re[], char ma[],int la): Motorfordon(ahj,vi,re,ma),last(la){}
void skrivut();
};
//------------------------------------------------------------------------------------------------
class Buss : public Personbil, public Lastbil //Klassen Buss ärver både från Personbil och från Lastbil
{
protected:
bool luft; //Luftkonditionering
public:
//Buss():Lastbil(),Personbil(),Motorfordon(){} Konstruktor utan parametrar
Buss(int ahj,int vi,char re[],char ma[],char mo[],int pa,int la,bool lu):
Personbil(ahj,vi,re,ma,mo,pa),
Lastbil(ahj,vi,re,ma,la),
Motorfordon(ahj, vi, re, ma),luft(lu){}
void skrivut();
//Observera att basklassen Motorfordon måste finnas med i definitionen av Buss-konstruktorn
};
//------------------------------------------------------------------------------------------------
void Fordon::skrivut()
{
cout << "Antal hjul:" << ant_hjul << endl;
cout << "Vikt:" << vikt << endl;
}
//------------------------------------------------------------------------------------------------
void Motorfordon::skrivut()
{
cout << "Märke:" << marke << endl;
cout << "Registernummer:" << reg << endl;
Fordon::skrivut();
}
//------------------------------------------------------------------------------------------------
void Personbil::skrivut()
{
cout << "En personbil" << endl;
cout << "Antal passagerare:" << pass << endl;
cout << "Modell:" << modell << endl;
Motorfordon::skrivut();
}
//------------------------------------------------------------------------------------------------
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 84 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
void Lastbil::skrivut()
{
cout << "En lastbil" << endl;
cout << "Lastkapacitet:" << last << endl;
Motorfordon::skrivut();
}
//------------------------------------------------------------------------------------------------
void Buss::skrivut()
{
cout << "En buss" << endl;
cout << "Antal passagerare:" << pass << endl;
cout << "Modell:" << modell << endl;
Motorfordon::skrivut();
cout << "Lastkapacitet:" << last << endl;
if (luft)
cout << "Luftkocditionering: Ja" << endl;
else
cout << "Luftkocditionering: Nej" << endl;
}
//------------------------------------------------------------------------------------------------
int main()
{
Buss b(6,5200,"ABC123","SCANIA","År 2002",52,5800,true);
teckenbyt();
b.skrivut();
getch();
return 0;
}
Det multipla arvet är litet speciellt här. Basklasserna Fordon
Personbil och Lastbil har klasserna Motorfordon och
Fordon som gemensammma basklasser (se figur). Det
innebär att klassen Buss kan ärva klasserna Motorfordon Cykel
n
Motorfordon:s och Fordon:s egenskaper på två sätt;
antingen via Personbil eller via Lastbil. Detta innebär Lastbil Personbil
samtidigt att Buss har dubbla uppsättningar av
datamedlemmarna i både Motorfordon och Fordon,
Buss
vilket är orimligt och skapar problem vid
kompileringen. Problemet löses genom att används en s k virtuell basklass, d v s att klasserna
Personbil och Lastbil ärver Motorfordon virtuellt. Detta åstadkoms genom att skriva virtual
vid klassdefinitionerna av Personbil och Lastbil. Observera även att Motorfordon måste anges
vid definitionen av konstruktorn Buss. I klassdefinitionen för Buss kommenteras hur en
konstruktordeklaration görs utan parametrar. Basklasserna måste då också ha parameterlösa
konstruktorer.
Övning 8.4:
Du skall skriva ett program som hanterar en sjöjungfru. Däggdjur Fisk
Programmet innehåller några klasser och ett multipelt arv (se
figur). Följande klasser skall ingå i programmet:
Människa
Klass: Daggdjur; medlemmar: ant_ben (int), kon (char);
metoder: void lasin(), void skrivut(); arv: inget.
Sjöjungfru
Klass: Manniska; medlemmar: namn (char), alder (int);
metoder: void lasin(), void skrivut(); arv: Daggdjur.
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 85 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
Klass: Fisk; medlemmar: ant_fen (int), hemhav (char); metoder: void lasin(), void skrivut();
arv: inget.
Polymorfism
Polymorfism bygger på pekare och behandlas därför i nästa kapitel (s. 93).
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 86 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 87 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
//------------------------------------------------------------------------------------------------
Cykel::Cykel(int ahj, int vi, int av, char ty[]) : Fordon(ahj,vi)
{
ant_vaxel=av;
strcpy(typ,ty);
}
//------------------------------------------------------------------------------------------------
void Cykel::skrivut()
{
cout << "En cykel" << endl;
cout << "Antal växlar:" << ant_vaxel << endl;
cout << "Typ:" << typ << endl;
Fordon::skrivut();
}
//------------------------------------------------------------------------------------------------
Här är programmet som använder inkluderingsfilen fordon_cykel.h:
#include "conio+.h" //Kan ej läggas i inkluderingsfilen (fel i conio+.h?)
#include "fordon_cykel.h"
int main()
{
Cykel c(2,17,21,"Herr"); //Deklaration (instans) av objektet c
teckenbyt();
c.skrivut();
getch();
return 0;
}
Naturligtvis fungerar det även att lägga metoddefinitionerna i inkluderingsfilen och strunta i
definitionsfilen.
Övning 8.5:
Modifiera övning 8.3 genom att lägga klassdefinitionerna Punkt och Linje och tillhörande
metoddefinitioner i inkluderingsfilen punkt_klass.h.
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 88 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
Pekare
En pekare är en variabel som pekar ut adressen i primärminnet där något, t ex ett heltal, är
lagrat. Följande kod skriver ut adressen där heltalsvariabeln k är lagrad:
int k=5;
cout << &k << endl; //Operatorn & utläses ”adressen till”
Utskriften blir en hexadecimal adress, t ex 0x0012FF7C. Med operatorn ”&” anges adressen
där variabeln är lagrad. Vi deklarerar nu en pekarvariabel p som pekar på variabeln k, samt
som skriver ut innehållet i den adress den pekar på, d v s 5 skrivs ut:
int k=5, *p; //Asterisken anger att det är en pekarvariabel för heltal.
p=&k; //p sätts att peka på adressen där k är lagrad.
cout << *p << endl; //Med asterisken fås värdet hos den adress som p pekar på, d v s 5.
Asterisken ”*” anger att variabeln p är en pekare som kan peka på p
heltal. På motsvarande sätt kan en pekare som är deklarerad som
double eller char endast peka på decimaltal respektive tecken. k 5
Deklarationen ovan illustreras med figuren intill. Följande
deklarationer är också möjliga:
p
int k=5, *p;
p=&k; //Pekaren p pekar på k:s adress.
*p=7; k 7
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 89 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
I följande kod skapas två nya pekare som pekar på olika adresser. Innhållet i adressen som p
pekar på tilldelas p1:s adress:
p1
int *p, *p1;
p=new int; p
p1=new int; 7
*p=7;
*p1=*p; //p1:s adress lagrar värdet värdet 7 7
cout << "pekaren: " << *p1 << endl; //Talet 7 skrivs ut.
Liksom det går att skapa minnesutrymme går det även att frigöra minnesutrymme. Följande
satser raderar adressen som p pekar på:
delete p;
Den grunläggande pekarsyntaxen vi hittills lärt oss är ännu inte så användbar i
programmerandet. Många upplever pekar som svårt och det är viktigt att man kan grunderna.
Innan vi går vidare och verkligen inser fördelarna med pekare, skall vi göra några övningar
som ökar förståelsen.
Övning 9.1:
Skriv ett program som läser in ett heltal och ett decimaltal till två pekarvariabler (p1 och p2)
för heltal respektive decimaltal. Talen skall sedan skrivas ut igen. Programmet skall ha
följande utskrift:
Ange ett heltal och ett decimaltal: 5 8.3
Du matade in talen 5 och 8.3
Övning 9.2:
Skriv ett program som läser in ett heltal till pekarvariabeln p1, tilldelar innehållet i adressen
den pekar på till heltalspekaren p2, som sedan skrivs ut. Programmet skall ha följande
utskrift:
Ange ett heltal: 5
Du matade in talet 5
Övning 9.3:
Skriv ett program som läser in ett heltal till pekarvariabeln p1, tilldelar heltalspekaren p2
samma adress som p1 pekar på, tilldelar p2 ett annat heltal, samt slutligen skriver ut talet som
p1 pekar på. Vilket tal skrivs ut – det som matades in först eller sist? Programmet skall ha
följande utskrift:
Ange ett heltal: 5 //Läses in till *p1
Ange ytterligare ett heltal: 8 //Läses in till *p2
Pekaren p1 pekar på talet 8 //Skriver ut talet som p1 pekar på
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 90 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 91 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 92 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
Länkad lista
En länkad lista är användbar när man i förväg inte alls vet hur många t ex tal eller namn som
skall lagras. Visserligen kan detta lösas med en pekare och ett dynamiskt allokerat fält, men
har fältet en gång allokerats går det inte att ändra. Den länkade listan byggs däremot ut
efterhand som ny data lagras. Listan bygger på små ’boxar’, även kallade element, som
innehåller lagrad data och en pekare som pekar på bakomliggande element. På så sätt blir den
länkade listan som en kedja av element som hålls samman av elementens pekare. Antag att vi
vill lagra ett godtyckligt antal heltal i en länkad lista. Vi börjar då med att definiera klassen
Box (se kod nedan), som lagrar heltalet och en pekare till nästa element. Vi deklarerar sedan
pekaren first, som alltid pekar på listans första element, samt pekaren temp, som används för
att skapa nya element. Följande programexempel skapar en länkad lista med tre element:
#include <iostream.h>
//-------------------------------------------------------------------------------------- ----------
class Box
{
public:
int tal;
Box *next; //Pekar ut nästa element.
};
//------------------------------------------------------------------------------------------------
int main()
{ first
Box *first, *temp;
temp=new Box; //temp pekar på ett nytt Box-element. NULL
temp->tal=5; //Datamedlemmen tal får värdet 5. 5 next
temp->next=NULL; //next pekar inte på något.
first=temp; //first pekar på samma element som temp. temp
temp=new Box; //Detta upprepas tre gånger.
temp->tal=7; //Piloperator, inte “.”
temp->next=first; first
first=temp;
temp=new Box; NULL
temp->tal=9; 7 next 5 next
temp->next=first;
first=temp;
temp
cout << first->tal << endl;
cout << first->next->tal << endl;
cout << first->next->next->tal << endl; //Elementen nås via upprepade next-anrop.
return 0;
}
first
Utskriften blir då:
NULL
9 9 next 7 next 5 next
7
5
temp
Figurerna ovan visar hur den länkade listan skapas. Observera att piloperatorn används för att
anropa objektets (elementets) datamedlemmar via pekaren. Exemplet ovan illustrerar bra hur
en länkad lista skapas, men metoden är krånklig; minnesallokeringen är omständlig och
utskriften svåröverskådlig, i synnerhet om listan innehåller fler element. Vi modifierar därför
exemplet ovan genom att i klassen Box lägga till en konstruktor med en parametrar för heltalet
tal och en för pekaren next. På så sätt kan elementet tilldelas värden när minnet allokeras.
Utskriften modifieras också men en while-loop. Programmet blir då:
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 93 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
#include <iostream.h>
//------------------------------------------------------------------------------------------------
class Box
{
public:
int tal;
Box *next;
Box (Box *p, int t);
};
//------------------------------------------------------------------------------------------------
Box::Box(Box *p, int t)
{
tal=t;
next=p;
}
//------------------------------------------------------------------------------------------------
int main()
{
Box *first=NULL; //first pekar inte på något (tom lista)
first=new Box(first,5); //Första elementet skapas, där next pekar på NULL (från first)
first=new Box(first,7); //first i konstruktorn pekar på första elementet o s v.
first=new Box(first,9);
while (first!=NULL) //Utskriften pågår tills listan är tom
{
cout << first->tal << endl;
first=first->next; //first sätts till att peka på det element som next pekar på.
}
return 0;
}
//------------------------------------------------------------------------------------------------
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 94 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
}
}
//------------------------------------------------------------------------------------------------
int main()
{
Box *first=NULL;
lagg_forst(first,5); //Vid anropet pekar first på NULL. Efter anropet
lagg_forst(first,7); //pekar first på första elementet o s v.
lagg_forst(first,9);
skrivut(first); //Här pekar first på listans första element.
return 0;
}
//------------------------------------------------------------------------------------------------
Rekursiv utskrift
I samband med listor används ofta rekursiva funktioner. Funktionen skriv_ut blir något
enklare som rekursiv:
void skrivut(Box *p)
{
if (p!=NULL) //Kollar om p nått listans slut
{
cout << p->tal << endl;
skrivut(p->next);
}
}
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 95 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
NULL
9 next 7 next 5 next
temp temp->next->next
I figuren illustreras fallet då elementet med talet 7 skall bort ur listan. Pekaren temp pekar
’förbi’ elementet som skall avlägsnas. Med ovanstående deklarationer och anropet…
ta_bort(first,7);
…avlägsnas elementet med talet 7 ur listan. Vid anropet av funktionen ta_bort kommer p i
funktionen att peka på samma element som first, d v s listans första element.
Övning 9.5:
Du skall skriva ett program som hanterar förnamn i en länkad lista. Programmet skall läsa in,
skriva ut, söka efter och ta bort namn ur listan. Programmet har menyn har utseendet:
cout << "Gör ett val i menyn nedan: " << endl;
cout << "1: Lägg in namn i listan " << endl;
cout << "2: Skriv ut namn " << endl;
cout << "3: Sök ett namn " << endl;
cout << "4: Ta bort ett namn " << endl;
cout << "5: Avsluta "<< endl;
Programmet skall fungera som exemplet Anders_A/cplusplus/lenkadlista_9_5.exe.
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 96 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
Polymorfism
Tidigare i kursen har vi sett att ett program kan innehålla funktioner med samma namn, men
med olika antal parametrar och/eller parametertyper. Funktioner med samma namn är
överlagrade. Följande program visar ett exempel på detta:
//==============================================
void funk(int x)
{
cout << "Ett heltal: " << x << endl;
}
//===============================================
void funk(double x)
{
cout << "Ett decimaltal: " << x << endl;
}
//===============================================
main()
{
int n=5;
double d=6.9;
funk(n); //Övre funktionen anropas eftersom n är ett heltal
funk(d); //Undre funktionen anropas eftersom d är ett decimaltal
}
Vilken av funktionerna som anropas beror på parametertypen. Detta är en enklare form av
polymorfism, d v s att programmet kan anropa olika funktioner beroende på parameter- och
variabeltyper. Här bestäms dock hur programmet skall exekveras redan vid kompileringen,
eftersom parametertyperna framgår av programkoden. Detta kallas statisk bindning. Riktig
polymorfism innebär att det under exekveringen bestäms vilka funktioner som skall anropas.
Detta kallas dynamisk bindning. För att åstadkomma detta måste vi arbeta med klasser och
pekare. Principen bygger på två saker:
En pekare till en basklass kan även peka på klasser som härletts ur basklassen. En
pekare till en härledd klass kan dock inte peka på motsvarande basklass.
Polymorfismen illustreras med följande fordonsexempel med arv vi tidigare använt (s. 77):
class Fordon
{
protected:
int ant_hjul, vikt;
public:
Fordon(int a, int v):ant_hjul(a),vikt(v){};
virtual void skrivut(); //skriv_ut är en virtuell funktion, även i övriga klasser
void lasin();
};
//------------------------------------------------------------------------------------------------
class Cykel : public Fordon
{
int ant_vaxel;
char typ[20];
public:
Cykel(int ahj, int vi, int av, char ty[]): Fordon(ahj,vi),ant_vaxel(av){strcpy(typ,ty);}
void skrivut();
};
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 97 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
//------------------------------------------------------------------------------------------------
class Motorfordon: public Fordon
{
protected:
char marke[20],reg[10];
public:
Motorfordon(int ahj, int vi, char re[], char ma[]):
Fordon(ahj,vi){strcpy(reg,re);strcpy(marke,ma);}
void skrivut();
void lasin();
};
//------------------------------------------------------------------------------------------------
class Personbil: public Motorfordon
{
protected:
int pass;
char modell[10];
public:
Personbil(int ahj, int vi, char re[], char ma[], char mo[],int
pa):Motorfordon(ahj,vi,re,ma),pass(pa){strcpy(modell,mo);}
void skrivut();
void lasin();
};
//------------------------------------------------------------------------------------------------
void Fordon::skrivut()
{
cout << "Antal hjul:" << ant_hjul << endl;
cout << "Vikt:" << vikt << endl;
}
//------------------------------------------------------------------------------------------------
void Cykel::skrivut()
{
cout << "Antal växlar:" << ant_vaxel << endl;
cout << "Cykeltyp:" << typ << endl;
Fordon::skrivut();
}
//------------------------------------------------------------------------------------------------
void Motorfordon::skrivut()
{
cout << "Märke:" << marke << endl;
cout << "Registernummer:" << reg << endl;
Fordon::skrivut();
}
//------------------------------------------------------------------------------------------------
void Personbil::skrivut()
{
cout << "En personbil" << endl;
cout << "Antal passagerare:" << pass << endl;
cout << "Modell:" << modell << endl;
Motorfordon::skrivut();
cout << Fordon::vikt << endl;
}
//------------------------------------------------------------------------------------------------
main()
{
Personbil b(4,1200,"BNO177","Opel","Kadett",5);
Fordon *ff;
ff=&b; //En pekare av klassen Fordon pekar på ett objekt av klassen Personbil.
ff->skrivut(); //Funktionen skrivut() i klassen Personbil anropas.
}
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 98 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson
Virtuella funktioner skapar dynamisk bindning. Genom att deklarera funktionen skrivut i
basklassen Fordon som virtual kommer även funktionerna skrivut i övriga klasser att bli
virtuella. En klass som innehåller en virtuell funktion eller ärver en en klass med en virtuell
funktion kallas för polymorf klass. Detta innebär att funktionen i den klassen pekaren pekar på
anropas. I exemplet ovan pekar en pekare av klassen Fordon på ett objekt av klassen
Personbil. Således anropas funktionen skrivut() i klassen Fordon. Även om exemplet ovan
demonstrerar dynamisk bindning, ser det ut som statisk bindning; variablerna är ju givna vid
kompileringen. I följande exempel pekas olika fordonstyper (cyklar och personbilar) ut av
fältet ftab, innehållande pekare av klassen Fordon:
main()
{
Fordon *ftab[4];
ftab[0]=new Cykel(2,18,21,"Herr");
ftab[1]=new Cykel(2,9,1,"Barn");
ftab[2]=new Personbil(4,980,"BNO177","Opel","Kadett",5);
ftab[3]=new Personbil(4,1200,"POG234","Volvo","S50",5);
for (int i=0; i<=3; i++)
ftab[i]->skrivut();
}
Här är det mer uppenbart att det handlar om dynamisk bindning, i synnerhet om programmet
förses med en funktion som tillåter användaren att lägga in fordon under exekveringen (se
övning nedan). Fördelen med polymorfa klasser är alltså att man inte behöver bry sig om
vilken klass ett visst objekt har. Utan polymorfism i ovanstående exempel hade vi t ex vid
utskriften varit tvungna att bry oss om vilken klass det lagrade fordonet tillhör för att få rätt
skrivut-funktion, vilket avsevärt krånglat till programmerandet.
*Övning 9.6:
Modifiera exemplet ovan så att användaren kan läsa in nya fordon via funktionen void
lasin_fordon(). Funktionen skall bl a fråga efter vilken fordonstyp (cykel eller personbil) som
skall läsas in. Detta är nödvändigt för att veta vilken klasstyp minnet skall allokeras för med
new. Maximalt 10 fordon räcker. Programmet skall ha följande meny:
cout << "Gör ett val i menyn nedan: " << endl;
cout << "1: Läs in fordon " << endl;
cout << "2: Skriv ut fordonsinfo "<< endl;
cout << "3: Avsluta: "<< endl;
*Övning 9.7:
Modifiera föregående övning så att fordonen istället lagras i en obegränsad länkad lista.
Kursen slut!
C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 99 10-09-17