You are on page 1of 99

LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson

PROGRAMMERING I SPRÅKET C++


Innehåll
1. VI BÖRJAR PROGRAMMERA ..................................................................................................................... 3
GYMNASIEKURSEN PROGRAMMERING C (100 P).................................................................................................. 3
INLEDNING ........................................................................................................................................................... 3
SKRIVA PROGRAM I VISUAL C++ ......................................................................................................................... 3
FÖRSTA PROGRAMMET I C++ ............................................................................................................................... 3
BLOODSHED DEV-C++ ........................................................................................................................................ 5
INMATNING .......................................................................................................................................................... 6
HELTAL................................................................................................................................................................ 7
DECIMALTAL OCH HELTALSDIVISION ................................................................................................................... 7
CASTING .............................................................................................................................................................. 7
VARIABLER OCH KONSTANTER ............................................................................................................................ 8
ANTAL DECIMALER .............................................................................................................................................. 9
MATEMATISKA FUNKTIONER ............................................................................................................................... 9
SLUMPTAL ......................................................................................................................................................... 10
2. URVAL ............................................................................................................................................................ 12
IF-SATSEN .......................................................................................................................................................... 12
CHAR ................................................................................................................................................................. 12
ELSE IF ............................................................................................................................................................... 13
SWITCH OCH CASE ............................................................................................................................................. 13
JÄMFÖRELSEOPERATORER OCH LOGISKA OPERATORER ..................................................................................... 13
UTSKRIFT AV SVENSKA TECKEN......................................................................................................................... 14
3. REPETITIONER OCH LOOPAR ................................................................................................................ 17
WHILE-SATSEN .................................................................................................................................................. 17
DO-WHILE-SATSEN ............................................................................................................................................ 18
BREAK OCH CONTINUE ....................................................................................................................................... 18
RENSA SKÄRMEN ............................................................................................................................................... 20
FOR-SATSEN....................................................................................................................................................... 21
OBUFFRAD INMATNING ...................................................................................................................................... 22
BOOLESK DATATYP ............................................................................................................................................ 23
FÖRDRÖJNING .................................................................................................................................................... 23
TANGENTFUNKTIONEN KBHIT() ......................................................................................................................... 24
4. TEXTSTRÄNGAR ......................................................................................................................................... 25
TEXTSTRÄNGAR AV TYPEN CHAR ....................................................................................................................... 25
ESCAPE-SEKVENSER........................................................................................................................................... 26
ASCII-KOD ........................................................................................................................................................ 26
FÄRGER, POSITIONER OCH UTSKRIFT .................................................................................................................. 27
KOPIERING ......................................................................................................................................................... 29
JÄMFÖRELSE ...................................................................................................................................................... 29
SAMMANSÄTTNING AV STRÄNGAR ..................................................................................................................... 30
STRÄNGLÄNGD .................................................................................................................................................. 30
FORMATERAD UTMATNING MED SETW, LEFT, RIGHT OCH SETFILL ..................................................................... 31
STANDARDTYPEN STRING .................................................................................................................................. 33
Sökning .......................................................................................................................................................... 33
Addering av strängar (konkatenering) .......................................................................................................... 34
Ändra strängar .............................................................................................................................................. 34
FEL I VISUAL C++ .............................................................................................................................................. 35
5. FÄLT (ARRAY) .............................................................................................................................................. 37
FÄLT FÖR HELTAL .............................................................................................................................................. 37
FÄLT FÖR DECIMALTAL, TECKEN OCH TEXTSTRÄNGAR ...................................................................................... 38

C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 1 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson

AVSLUTAD INMATNING ...................................................................................................................................... 39


FLERDIMENSIONELLA FÄLT ................................................................................................................................ 39
SORTERING ........................................................................................................................................................ 41
6. FUNKTIONER................................................................................................................................................ 42
FUNKTIONER SOM INTE RETURNERAR ETT VÄRDE .............................................................................................. 42
FUNKTIONER SOM RETURNERAR ETT VÄRDE ...................................................................................................... 44
FUNKTIONER MED REFERENSANROP .................................................................................................................. 45
AVRUNDNING TILL HELTAL................................................................................................................................ 46
STATIC-PARAMETER .......................................................................................................................................... 48
ÖVERLAGRADE FUNKTIONER ............................................................................................................................. 48
DEFAULT-PARAMETRAR .................................................................................................................................... 48
REKURSION ........................................................................................................................................................ 49
ENKEL GRAFIK ................................................................................................................................................... 51
EGEN FUNKTION FÖR FÖRDRÖJNING ................................................................................................................... 53
7. FILHANTERING ........................................................................................................................................... 54
LÄSNING AV TEXT FRÅN FIL ............................................................................................................................... 54
LÄSNING AV TECKEN UR FIL............................................................................................................................... 55
KONVERTERING MELLAN STORA OCH SMÅ BOKSTÄVER ..................................................................................... 56
LAGRA TEXT PÅ FIL ............................................................................................................................................ 57
LAGRING AV TECKEN PÅ FIL............................................................................................................................... 58
LÄGGA TILL TEXT I EXISTERANDE FIL ................................................................................................................ 58
STRUKTUREN STRUCT ........................................................................................................................................ 59
BINÄRA FILER .................................................................................................................................................... 61
EGNA INKLUDERINGSFILER (HEADERFILER) ....................................................................................................... 63
Uppdelning i inkluderingsfil och definitionsfil .............................................................................................. 64
8. OBJEKTORIENTERING .............................................................................................................................. 66
KLASS OCH OBJEKT ............................................................................................................................................ 66
Medlemsfunktioner ........................................................................................................................................ 66
KONSTRUKTOR .................................................................................................................................................. 68
Separat konstruktordefinition ........................................................................................................................ 69
Initieringslista ............................................................................................................................................... 69
DESTRUKTOR ..................................................................................................................................................... 70
Separat destruktordefinition .......................................................................................................................... 70
KLASSER AV KLASSER........................................................................................................................................ 72
Två klasser .................................................................................................................................................... 72
Tre klasser ..................................................................................................................................................... 74
ARV, BASKLASS OCH HÄRLEDD KLASS ............................................................................................................... 79
Flera härledda klasser .................................................................................................................................. 81
Multipelt arv .................................................................................................................................................. 83
POLYMORFISM ................................................................................................................................................... 86
KLASSER I INKLUDERINSFIL OCH DEFINITIONSFIL .............................................................................................. 87
9. PEKARE OCH DYNAMISK MINNESALLOKERING ............................................................................. 89
PEKARE .............................................................................................................................................................. 89
PEKARE OCH FÄLT ............................................................................................................................................. 91
PEKARE TILL TEXTSTRÄNGAR ............................................................................................................................ 92
LÄNKAD LISTA ................................................................................................................................................... 93
Funktioner för att länka och skriva ut lista ................................................................................................... 94
Rekursiv utskrift ............................................................................................................................................ 95
Kolla tal i länkad lista ................................................................................................................................... 95
Ta bort element ur länkad lista ..................................................................................................................... 96
POLYMORFISM ................................................................................................................................................... 97

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

Gymnasiekursen Programmering C (100 p)


Denna kurs ges inom ramen för den nationella gymnasiekursen Programmering C (100 p). För
att gå kursen krävs förkunskaper motsvarande de båda nationella gymnasiekurserna
Programmering A och Programmering B, båda på 50 p. Förutom de begrepp (variabler,
loopar, datatyper, strängar, vektorer, funktioner, filer etc.) som berörts i A- och B-kursen,
kommer C-kursen även att ta upp pekare och objektorientering. Programmeringen kommer att
ske i språken C++ och senare i Java.

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.

Skriva program i Visual C++


VB har ett grafiskt gränssnitt med programkoden kopplad till grafiska komponenter
(formulär, knappar, textrutor etc). Även Visual C++ genererar grafiska komponenter. Vi
kommer dock inledningsvis att lära oss C++ via s k console-programmering, d v s
kommunikationen med programmet sker via tangentbordet utan några grafiska finesser.
Programmet skrivs in i en texteditor, där programmet kompileras och körs. I Visual C++
skapas ett C++-program på följande sätt:

1) Öppna programmet Visual C++

2) Välj File/New

3) Välj fliken Files

4) Klicka på C++ Source File. Du har nu texteditorn framför dig där programkoden skrivs
in.

Första programmet i C++


Programmering handlar om att få datorn att utföra vissa saker, t ex addera tal, rita figurer eller
något mer i form av ett ordbehandlingsprogram. För att lyckas med detta måste man lära sig
språkets syntax, d v s programspråkets uppbyggnad, samt att strukturera. Skriver man längre
program är det väldigt viktigt att man lär sig skriva programmen på ett lättläst och logiskt sätt
så att det är lätt att förstå vad programmet gör, samt lätt att hitta eventuella fel. Vi börjar med
C++ från grunden.

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.

2) Kompilera programmet via menyvalet Build/Compile test.cpp (Ctrl F7). Du får då en


fråga om ett workspace skall skapas. Svara ja! I samband med detta skapas tre nya filer
(.dsp, .ncb, .html) och mappen Debug med fyra filer (.obj, .pch, .idb, .pdb).

3) Kör nu programmet med Build/Execute test.cpp (Ctrl F5). Du får då en fråga om


exekveringsfilen Debug/test.exe skall skapas. Svara ja! I mappen Debug skapas då
dessutom två filer (.ilk, .pdp) samtidigt som programutskriften visas i körfönstret.

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.

2) Stäng existerande workspace med File/Close Workspace.

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++:

 #include <iostream.h> saknar .h i Dev-C++

 using namnspace std deklareras i Dev-C++ (även i Visual C++ ibland)

 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.

Decimaltal och heltalsdivision


Vill vi räkna med decimaltal (flyttal) deklareras variablerna som datatyperna float (7 siffror, 4
byte, 3.4∙10±38) eller double (16 siffror, 8 byte, 1.7∙10±308). Vid division (/) måste termerna
vara av typen double. Är termerna deklarerade som heltal utförs annars heltalsdivision. Vill vi
ha reda på resten vid division mellan två heltal används operatorn ’%’ (mod VB). Följande
program utför division mellan två decimaltal:
#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.
cout << "Kvoten av talen är " << a/b; //Kvoten av a och b skrivs ut på skärmen.
}

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

Variabler och konstanter


Variabler deklareras i regel i början av programmet efter main. Variabeltilldelningar kan se ut
på lite olika sätt. I följande exempel tilldelas värdet på variablerna bettan och c direkt i
deklarationen och på allan i programmet. Observera att konstanten antal, vars värde inte kan
ändras i programmet, även deklareras med datatyp:
#include <iostream.h>
main()
{
const int antal=12;
int allan, bettan=4;
double c=3.78;
allan=23;
cout << "allan="<< allan << " bettan="<< bettan << endl;
cout << " c="<<c << endl;
cout << "Antalet är "<< antal <<" stycken";
}
Övning 1.5:
Skriv ett program som omvandlar från Celsiusgrader (C) till Fahrenheit (F) med formeln
F=1,8C+32. Programmet skall ha följande utskrifter:
Ange en temperatur i Celsiusgrader: 20
Temperaturen motsvarar 68 Fahrenheit.
Övning 1.6:
Skriv ett program som omvandlar från svenska kronor till US dollar, om en dollar kostar 9,22
kr. Programmet skall ha följande utskrift:
Ange ett belopp i kronor: 74.50 kr
Detta motsvarar 8.08026 dollar
Övning 1.7:
Skriv ett program som beräknar resten vid division mellan två heltal. Programmet skall ha
följande utskrift:
Ange två heltal: 15 6
Resten vid division är 3
Övning 1.8:
Kopiera föregående program till en ny fil och modifiera det så att det istället skriver ut hur
många hela gånger nämnaren går i täljaren. Programmet skall ha följande utskrift:
Ange två heltal: 15 6
6 går 2 hela gånger i 15
*Övning 1.9:
Skriv ett program som läser in ett belopp (heltal) i kronor och skriver ut
hur det kan delas upp i olika valörer (se urklipp).

*Ö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.

Switch och case


Programexemplet ovan med else if kan förenklas med en switch-konstruktion:
#include <iostream.h>
main()
{
int a;
cout << "Ange ett heltal!";
cin >> a;
switch (a)
{
case 1: cout << "Måndag";break;
case 2: cout << "Tisdag";break;
case 3: cout << "Onsdag";break;
default: cout << "En annan dag";
}
}
Utelämnas break-satsen i slutet på en rad utförs samtliga följande case-satser, d v s om t ex
a=3 blir utskrifter Onsdag Torsdag En annan dag. Default-satsen utförs om ingen annan sats
utförts.

Jämförelseoperatorer och logiska operatorer


Följande jämförelseoperatorer används vid urval med if-satser:
< Mindre än
> Större än
<= Mindre än eller lika med
>= Större än eller lika med
== Lika med
!= Inte lika med
&& Och (and)
|| Eller (or)
! Icke (not)

C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 13 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson

Utskrift av svenska tecken


Som du sett ersätter Visual C++ alla svenska tecken (å, ä, ö). I den utökade inkluderingsfilen
svtecken.h finns dock funktionen teckenbyt(), som gör att de svenska tecknen skrivs ut. Filen
finns i kursmappen cplusplus och skall placeras i mappen c:/Program/Microsoft Visual
Studio/VC98/Include. Inkluderingsfilen anges på följande sätt i progremmet:
#include "svtecken.h";
Omställning till svenska tecken görs sedan i programmet med funktionsanropet:
teckenbyt();
Följande program skriver ut några svenska bokstäver:
#include <iostream> //Utan ‟.h‟ på iostream
#include "svtecken.h"
main()
{
teckenbyt();
cout << "ÅÄÖåäö";
}
Observera att ändelsen ’h’ nu saknas på inkluderingsfilen iostream.

Ö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:

a. 10 < tal < 20

b. 10 <= tal <= 20

c. tal > 20 eller tal < 10

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

3. Repetitioner och loopar


I programmering vill man ofta åstadkomma repetitioner. Vill man t ex skriva ut
Programmering är roligt på skärmen tio gånger vore det ju praktiskt om man kunde be datorn
att göra detta tio gånger istället för att göra det med tio cout-satser i programmet. Och detta är
naturligtvis möjligt. Vi kommer att använda while- och for-satserna för att åstadkomma
repetitioner, eller loopar som man också säger.

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

Det går även att tilldela variabler i samband med deklarationen:


int sum=0, i=0;
Följande satsförenklingar kan dessutom göras i C++:
i=i+1; i++; (därav namnet C++)
sum=sum+i; sum+=i;
k=k-1; k—;
k=k*i; k*=i;
Med dessa modifieringar får ovanstående program följande något kompaktare utseende:
#include <iostream.h>
main()
{
int sum=0,i=1;
while (i<=5)
{
sum+=i;
i++;
}
cout << "Summan är " << sum;
}
Innehåller while-loopen endast en sats behövs inte klammerparenteserna ’{’ och ’}’.

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');
}

Break och continue


Med satsen…
break;
…avslutas loopen (se exempel nedan), och med satsen…
continue;
…fortsätter repetitionen med nästa iteration.

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

Får summan något speciellt värde om N är ett stort tal?

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öljande rader visas inläsning med getch():


#include <iostream.h>
#include <conio.h>
main()
{
bool goon=true;
while (goon)
{
cout << "Vill du fortsätta (j/n)? " << endl;
if (getch()=='n')
goon=false;
}
}
Samma sak löses enklare med break utan booelsk variabel:
#include <iostream.h>
#include <conio.h>
main()
{
while (true)
{
cout << "Vill du fortsätta (j/n)? " << endl;
if (getch()=='n')
break;
}
}

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

Textsträngar av typen char


En textsträng (teckenfält) är en följd av tecken, exempelvis är Anders Andersson en textsträng
som består av 16 tecken; 15 bokstäver och ett blanktecken. Hittills har vi enbart arbetat med
ett tecken i taget (d v s datatypen char). Det går emellertid även att arbeta med textsträngar i
C++. Vill vi läsa in en textsträng innehållande högst 8 tecken till variabeln namn gör vi
följande variabeldeklaration:
char namn[8] ;
Variabeln kan även tilldelas ett värde vid deklarationen:
Char namn[8] = ”anders”;
Det kan fungera att läsa in fler än 8 tecken till en strängvariabel som är deklarerad för 8
tecken, med detta är inte att rekommendera. Nu kan vi läsa in en sträng till våran
namnvariabel:
cout << ”Ange ett namn: ”;
cin >> namn;
Däremot går det inte att tilldela en strängvariabel ett värde. Följande tilldelning fungerar alltså
inte:
namn = ”Anders”; //Felaktigt!
Hur detta löses återkommer vi till senare. Vill vi skriva ut tredje tecknet i textsträngen gör vi
följande utmatning:
cout << namn[2];
Tecknet d skrivs då ut om variabeln namn 0 1 2 3 4 5 6 7
innehåller strängen anders. I strängen har första a n d e r s
tecknet ordningsnumret 0, andra tecknet
ordningsnumret 2 o s v, enligt figuren intill. I
position 6, d v s i positionen efter det sist inlästa
tecknet, hamnar radsluttecknet ’\0’ (se Escape-sekvenser nedan). Nackdelen med denna typ av
inläsning är att inläsningen endast sker till första blanktecknet. Matas t ex textsträngen Kalle
Anka in via tangentbordet sparas endast Kalle i strängvariabeln, eftersom det sedan alltså
kommer ett blanktecken. Vill man även kunna läsa in mellanslag får man använda följande
inläsningsfunktionen getline:
cout << ”Ange ett för- och ett efternamn med blanktecken emellan: ”;
cin.getline(namn,6);
I detta fallet läses högst 5 tecken in till strängvariabeln namn. I den 6:e positionen i
strängvariabeln hamnar ett radsluttecken. Istället för att ange strängens längd med ett tal kan
anges med funktionen sizeof(namn):
cin.getline(namn,sizeof(namn));

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:

cout << (int)((unsigned char)teck);

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

Färger, positioner och utskrift


Hittills har utskriften skett vänsterjusterad och med vit färg. Det går emellertid att själv välja
både läge och färg på texten. I Visual C++ finns ingen inkluderingsfil som standard för detta.
Den utökade inkluderingsfilen conio+.h har dock funktionerna för detta. Filen finns i
kursmappen cplusplus och skall placeras i mappen C:/Program/Microsoft Visual
Studio/VC98/Include. Filen anges på följande sätt i progremmet:
#include "conio+.h";
Utskriftspositionen flyttas med anropet:
gotoxy(x,y);
Där x och y är skärmkoordinater. Det horisontella x har värden mellan 1 och 80 och det
vertikala y mellan 1 och 24. Anropet gotoxy(1,1) flyttar markören högst upp till det vänstra
hörnet. Färgen ändras med anropet:
setcolor(n);
Där n är ett heltal mellan 0 och 15. Varje siffra motsvarar en färg, t ex 1 är blått och 4 rött.
Vid förflyttning av utskriften med gotoxy måste nu göras med funktionen cprintf(). Den
tidigare använda cout << fungerar inte här. Vill vi t ex skriva ut Hej med röd färg i poitionen
x=45 och y=12 görs detta med följande anrop:

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

*Övning 4.13: (slumpfärg)


Skriv ett program som fyller skärmen med slumpmässigt färgade nollor på slumpmässiga
positioner. Programmet skall fungera som exemplet Anders_A/cplusplus/slumpfarg.exe.

*Övning 4.14: (myran)


Skriv ett program som simulerar en myras slumpmässiga vandring på skärmen med ett steg i
taget (uppåt, nedåt, höger eller vänster). Observera att myrans position är rödfärgad.
Programmet skall fungera som exemplet Anders_A/cplusplus/myran.exe.

*Övning 4.15: (namnpil)


Skriv ett program som läser in ett ord, som rensar skärmen och där sedan namnet kan flyttas
med piltangenterna. Programmet avslutas med Esc-tangenten. Programmet skall fungera som
exemplet Anders_A/cplusplus/namnpil.exe.

*Övning 4.16: (pilspel)


Skriv ett program där slumpmässigt nedfallande bollar skall infångas med en textsträng styrd
med piltangenterna. Programmet skall fungera som exemplet Anders_A/cplusplus/pilspel.exe.

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.

Formaterad utmatning med setw, left, right och setfill


Vid utskrift av tal, priser och tabeller vill man ibland kunna formatera texten på ett snyggt
sätt. Exempelvis vill man ofta ha entals-, tiotals- och hundratals siffror under varandra:
Antal personer: 125
Antal biljetter: 45
Antal bilar: 3
Detta kan åstadkommer man i C++ genom att ange antal positioner för den följande utskriften
med manipulatorn setw(). I följande utskriftsexempel är antal en heltalsvariabel som skrivs ut
högerjusterad på fyra positioner.:
cout << ”Antal personer:” << setw(4) << antal;
Formaterad utmatning av decimaltal sker på liknande sätt som för heltal. Här måste vi
emellertid även ange antalet decimaler för utskriften (se sidan 5 ovan). I följande exempel
skrivs decimaltalet tal ut högerjusterat på 7 positioner med 2 decimaler:
cout << "Talet är " << setiosflags(ios::fixed) << setprecision(2) << setw(7) <<tal;
Normalt är utskriften högerjusterad. Vänsterjusterad utskrift fås med manipulatorn left, som
gäller till manipulatorn right anges. Nedanstående exempel illustrerar syntaxen:
cout << setw(20) << left << "Euro" << setw(10) << right << euro << endl;
Manipulatorn setfill(‘tecken’) fyller ut utrymmet som anges av manipulatorn setw med tecknet
’tecken’. Nedanstående exempel illustrerar syntaxen:
int i=4;
cout << setw(i) << setfill('*') << "" << i << endl;
Ger utskriften:
****4
Manipulatorerna finns i inkluderingsfilen <iomanip.h>.

Ö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.

a.rfind(b) Som a.find(b), men söker bakifrån.


a.find_first_of(b) Returnerar den position som den första förekomsten av tecknet
återfinns i..
a.find_first_of(b,3) Som ovan, men sökningen börjar I position 3.
a.find_last_of(b) Som a.find_first_of(b), men sökningen börjar bakifrån.
a.find_first_not_of(b) Söker efter första förekomsten av tecken som inte finns i b
a.find_last_not_of(b) Sökning bakifrån.

Addering av strängar (konkatenering)


a+=b; a=a+b; Ekvivalenta. Adderar b till a, d v s b hamnar sist i a.
a+b Om a = Anders och b = kalle blir resultatet anderskalle. Följande
addition av strängar är inte tillåten:

string a="per",b;
b=a[0]+a[1]+a[2]; //Felaktigt!
cout << b << endl;

Skälet är att en string ej kan skapas av tecken. Däremot kan tecken


adderas till en string-typ:

string a="per",b;
b=b+a[0]+a[1]+a[2]; //Rätt!
cout << b << endl; //per skrivs ut

a.append(b) Lägger till ”b” i slutet av ”a”.


a.append(b,2,3) Lägger till ”b” i slutet av ”a”. Om a = anders och b= kalle blir resultatet
”anderslle”

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”.

a.insert(2, b) Skjuter in strängen b fr o m positionen 2 i a. Om a=anders och b=kalle


blir resultatet ankalleders.
a.insert(2, b,0,3) Skjuter in 4 tecken från position 3 i b till a fr o m position 2. Om a=
anders och b= kalle blir resultatet ”ankalders”
a.insert(3,b,4) Skjuter in de fyra första tecknen från b till position 3 i a. Observera att
b måste vara av typen char.
a.insert(2, 5,‟*‟) Skjuter in de fem ‟*‟ till position 2 i a. Om a= anders blir resultatet
an*****ders
a.resize(n) Ändrar a:s längd till n(siffra). Fyller ut med nollor om n är större än den
gamla längden, annars kapas slutet.
a.resize(6,‟*‟) Som resize(6), men fyller ut med ‟*‟ istället för nollor.
a.erase(2,4) Tar bort 4 tecken ur a med början i position 2.
a.clear() Tar bort alla tecken ur a.

C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 34 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson

Fel i Visual C++


Om du provat inläsningsfunktionen getline() ovan kanske du märk att den kräver två
inmatningar med Enter-tangenten för att fungera. Detta beror på ett fel i inkluderingsfilen
string (den utan .h). Felet rättas till med följande ändring i inkluderingsfilen string:

1) Öppna filen string i mappen c:/Program/Microsoft Visual Studio/VC98/Include i


programmet Visual C++.

2) Gå till raden med följande sats: _I.rdbuf()->snextc();

3) Ändra till följande sats: _I.rdbuf()->stossc();

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.

Fält för heltal


Antag exempelvis att man behöver 8 (eller 100) olika heltalsvariabler, då är det ju lite
opraktiskt att behöva deklarera 8 (eller 100) olika heltalsvariabler. Istället deklarerar man ett
fält med 8 element av typen int:
int slumptal[8];
Tilldelningen av fältets element kan göras direkt vid deklarationen. Observera att fältet får
lika många element som det initieras med:

int a[]={22, 3, 19, 49, 31, 30, 12, 2};

När vi fyllt fältet med slumptal mellan 1


och 50 ligger talen lagrade som i bilden 0 1 2 3 4 5 6 7
av fältet intill, d v s på liknande sätt som Slumptal: 22 3 19 49 31 30 12 2
i en textsträng. Observera att fältets
första nummer (index) även här är 0.
Med följande satser kan vi läsa in och
spara ett tal i fältet slumptal:s position 4:
cout << ”Ange ett heltal: ”;
cin >> slumptal[4];
Vill vi istället fylla position 4 med ett slumptal mellan 1 och 50 gör vi följande tilldelning:
slumptal[4] = rand()%50+1;
Med följande for-sats kan vi skriva ut innehållet i fältet slumptal:s alla positioner på varsin
rad:
for (int i=0; i<=7;i++)
cout << slumptal[i] << endl;
Jämförelser och tilldelningar mellan fält är inte tillåtet (endast för textfält med strcmp e t c).
Om a och b är fältvariabler, är följande satser inte tillåtna:
a=b; //Ej tillåtet!
if (a==b) //Ej tillåtet!
Däremot är motsvarande satser tillåtna för fältets element:
a[4]=b[12];
if (a[7]==b[2])
Övning 5.1:
Skriv ett program som via en for-sats läser in tio heltal till ett fält och som sedan skriver ut
talen i fältet på samma rad.

Ö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.

Fält för decimaltal, tecken och textsträngar


Hittills har vi fyllt fälten med heltal. Fälten kan emellertid även innehåll decimaltal, tecken
och strängar. En fältvariabel teck som kan innehålla 15 tecken (med index 0-14) deklareras på
följande sätt:
char teck[15];
Som du ser är en fältvariabel för tecken detsamma som en textsträng. Det är dock inte
detsamma som klassen string. En fältvariabel tal som kan innehålla 15 decimaltal (med index
0-14) deklareras på följande sätt:
double tal[15];
En fältvariabel namn som kan innehålla 100 namn deklareras på följande sätt:
string namn[100];
Vill vi t ex läsa in ett namn till fältets position nummer 3 gör vi på följande sätt:
cout << "Ange ett namn: ";
cin >> namn[3];
cout << ”Du matade in namnet ”<< namn[3];
I övrigt hanteras fältvariabler innehållande textsträngar på samma sätt som tidigare.

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

Efternamn Förnamn Ort


Ek Erik Eksjö
Ögren Örjan Ölme

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

Funktioner som inte returnerar ett värde


Som du kanske redan upptäckt blir programmen vi hittills skrivit krångliga och svårlästa när
de blir lite längre. Långa program går emellertid att göra mer överskådliga om de delas upp i
mindre delar, s k funktioner. Skärmrensaren clrscr(), gotoxy(x,y), sqrt(x) och sin(x) är
exempel på färdiga funktion vi använt tidigare. Vi illustrerar begreppet funktion med ett par
exempel. Antag att vi skall skriva ett program som läser in två tal och som sedan frågar efter
om talen skall adderas eller subtraheras. Resultatet skall sedan skrivas ut. Skriver vi
programmet med det vi hittills lärt oss om C++ får det följande utseende:
#include <iostream.h>
main()
{
int a,b;
char val;
cout << "Ange två heltal: ";
cin >> a >> b;
cout << "Skall talen adderas eller subtraheras (a/s)?: ";
cin >> val;
if (val=='a')
cout << "Summan är " << a+b;
else
cout << "Differensen är " << a-b;
}
Vi löser samma uppgift en gång till, men nu använder vi oss av två funktioner. I den ena
funktionen beräknar vi additionen och i den andra subtraktionen. Kallas funktionerna för add
och sub får programmet följande utseende:
#include <iostream.h>
void add(); //Funktionen add deklareras här (prototyp)
void sub(); //Funktionen sub deklareras här (prototyp)
//==============================================
void add() //Funktionen add definieras här utan semikolon
{ //Funktionshuvud
int a,b; //a och b är lokala variabler endast giltiga i add()
cout << "Ange två heltal: "; //Beräkningar görs i funktionskroppen.
cin >> a >> b;
cout << "Summan är " << a+b << endl;
}
//============================================== Strecken skiljer funktionerna åt…
void sub() //Funktionen sub definieras här utan semikolon
{
int a,b; //a och b är lokala variabler endast giltiga i sub()
cout << "Ange två heltal: ";
cin >> a >> b;
cout << "Skillnaden är " << a-b << endl;
}
//===============================================…det ökar läsbarheten
main() //Huvudprogrammet main börjar här.
{
char val;
cout << "Skall talen adderas eller subtraheras (a/s)?: ";
cin >> val;
if (val=='a')

C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 42 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson

add(); //Funktionen add anropas här.

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.

Funktioner som returnerar ett värde


Hittills har inläsning och utskrift skett inuti de funktioner vi skrivit. Funktionen har inte
returnerat något värde. Det reserverade ordet void som står framför funktionsnamnet i
deklarationen anger att funktionen inte returnerar värden. En funktion kan emellertid även
returnera ett värde. Exempel på färdiga funktioner vi använt som returnerar värden är de
matematiska funktionerna sqrt(x) och pow(x,y). Vill vi exempelvis beräkna roten ur 64 skriver
vi sqrt(64) och funktionen sqrt returnerar värdet 8. I det inledande exemplet adderas och
subtraheras tal i funktionerna add() och sub(). Programmet blir kortare om vi gör inläsning
och utskrift i huvudprogrammet main, medan funktionerna add() och sub() endast utför
beräkningarna. Programmet får då följande utseende:
#include <iostream.h>
double add(double a, double b); //Funktionsdeklarationer
double sub(double c, double d);
//==============================================
double add(double a, double b) //Funktionen add definieras, (funktionshuvud)
{
return a+b;
}
//==============================================
double sub(double c, double d) //Funktionen sub
{
return c-d;
}
//===============================================
int main() //Huvudprogrammet börjar här. Returnerar int för att slippa varning.
{
char val;
double x,y;
cout << "Ange två tal: ";
cin >> x >> y;
cout << "Skall talen adderas eller subtraheras (a/s)?: ";
cin >> val;
if (val=='a')
cout << "Summan är " << add(x,y);
else
cout << "Skillnaden är " << sub(x,y);
return 0; //Returnerar 0, innebär egentligen ingenting.
} //main slutar här
Några saker att tänka på:
 När funktionen returnerar ett värde byts ordet void ut mot det returnerade värdets datatyp;
i exemplet ovan double.
 Värdet funktionen returnerar föregås av ordet return.
 I exemplet anropas funktionerna add och sub med parametrarna (argumenten) x och y av
typen double. I funktionshuvudet måste därför deklareras hur många parametrar
funktionen har och vilken typ de måste ha:
double add(double a, double b)

 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

 I exemplet får a x:s värde och b y:s värde. Ordningen är viktig.


 Den delen i funktionen där beräkningen görs kallas funktionskropp.
 Variablerna a och b är endast giltiga i funktionen add. De kallas lokala variabler.
Variablerna x och y är kan endast användas i huvudprogrammet main.
Övning 6.4:
Modifiera övning 6.3 ovan så att inläsning och utskrift sker i huvudprogrammet och
funktionerna endast utför beräkningen med funktionsparametrarna och returnerar ett värde.
Modifiera en funktion i taget och provkör.

Ö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.

Funktioner med referensanrop


Vi har hittills använt två typer av funktioner: En typ som inte returnerar ett värde (void) och
en typ som returnerar ett värde. Båda funktionstyperna kan anropas med värden (parametrar)
som används i funktionen, s k värdeanrop. Detta har vi gjort i många övningsexempel ovan.
Men hur skall man göra om man vill att funktionen skall returnera mer än ett värde? Jo, det
går även att anropa en funktion på ett tredje sätt med ett s k referensanrop. Det innebär att
void-funktion ’returnerar’ ett eller flera värden i form av referensparametrar i
funktionshuvudet. Referensparametern föregås av ett ’&’-tecken. Funktionen maximal(…) i
exemplet nedan visas hur referensparametern z används:
void maximal(int a, int b, int& c)
{
if (a>b)
c=a;
else
c=b;
}
main()
{
int x,y,z;
cout << "Ange två tal: ";
cin >> x >> y;
maximal(x,y,z);
cout << "Största talet är " << z;

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.

Avrundning till heltal


Ibland vill man i beräkningar avrunda decimaltal till heltal. I C++ finns dock ingen färdig
funktion för avrundning till heltal på matematiskt rätt sätt. Det är dock enkelt att skriva en
egen funktion som avrundar med hjälp av casting, enligt följande algoritm:
(int) (x+0.5)
Om exempelvis x=8,49 avrundas talet till neråt till 8. Är x=8.5 avrundas dock uppåt till 9.

Ö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

Övning 6.9 - inlämningsuppgift:


Du skall nu skriva ett längre menyorienterat program som hanterar 100 slumptal mellan 0 och
200 på lite olika sätt. Läs igenom hela uppgiften innan du börjar skriva programmet.
Programmet skall bestå av följande funktioner:
int round(double x); Avrundar decimaltalet x till ett heltal (se övning 6.8).
int slumptal(int tal); Returnerar ett slumtal mellan 0 och tal (se övning 6.5).
void fyll_slumptal(int slump[], int antal, int tal); Fyller antal slumptal mellan 0 och tal i fältet slump.
Funktionen anropar funktionen slumptal för att generera slumptal.
void skriv_ut_slumptal(int slump[], int antal); Skriver ut slumptalen i fältet slump i en formaterad
tabell på 10 rader och 10 kolumner (anropa med antal=100).
void rakna_ett_slumptal(int slump[], int antal); Läser in ett tal mellan 0 och 200 som räknar och
skriver ut hur många sådana slumptal fältet slump innehåller.
void rakna_alla_slumptal(int slump[], int antal); Räknar alla slumptal (antal nollor, ettor, tvåor, treor
…) i faltet slump och skriver ut resultatet i en formaterad tabell på formen 0: 2 1: 4 2: 7 3: 6 4: 3.
Slumptalen räknas genom att deklarera ett lokalt fält n, som först nollställs och sedan fylls via satsen:
n[slumptal]=n[slumptal]+1;
double medelvarde(int slump[], int antal); Beräknar medelvärdet av alla slumptalen i fältet slump.
Medelvärdet skrivs ut i menyn med två decimaler i anslutning till funktionsanropet.
*void medelvarde_tusen(int slump[], int antal); Beräknar medelvärdet 1000 gånger av slumptalen i
fältet slump. Medelvärdet skall avrundas (med round ovan) till ett heltal och sparas i ett lokalt
deklarerat fält i funktionen. Medelvärdena räknas på samma sätt som slumptalen ovan. Sedan skall
medelvärdena och antal skrivas ut under varandra till höger på sidan. En kul variant är att göra ett
liggande stapeldiagram för antalet, där staplarna görs med stjärnor (*). Använd manipulatorerna
setfill() och setw(). Vilken sannolikhetsfördelning representerar medelvärdena? Funktionen anropar
funktionen fyll_slumptal inför varje medelvärdesberäkning och funktionen medelvarde för beräkning av
varje medelvärde. Denna funktionen är frivillig i inlämningsuppgiften.
*void valj_antal_max(int& antal, int& max); Funktionen tillåter användaren att välja antalet slumptal
och största slumptalet som skall genereras. Denna funktionen är frivillig i inlämningsuppgiften.
Tänk på att rensa skärmen efter funktionsanropen och vid återgången till menyn. Använd
funktionen getch() för att åstadkomma pausar efter utskrifterna i funktionerna. Funktionen
main innehåller en meny varifrån ovanstående funktioner (utom de två första) anropas, samt
med ett val för att avbryta programmet. I main deklareras även fältet där slumptalen lagras. I
denna uppgiften räcker det med 100 slumptal, men vill du provköra med fler måste du
deklarera ett större fält. Anropa funktionerna med antal=100 och tal=200 (största slumptalet)
när du provkör programmet. Du har två lektioner på dig att lösa uppgiften. Du visar då en
körning av programmet (så långt du har kommit) för läraren och lämnar sedan en
programutskrift till läraren för kommentarer. Börja nu med att skriva programmet. Skriv en
funktion i taget i den ordning de har ovan. Fyll efterhand som funktionerna blir färdiga på
med nya funktioner och val i menyn och provkör. Kommentera gärna programkoden.

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:

 Först på traditionellt sätt med en for-loop.

 Sedan med en rekursiv funktion.

 Sist med en rekursiv funktion med referensparameter.


#include <iostream.h>
int summa(int n);
int rek_summa(int n);
void rek_summa_ref(int n, int& sum);
//==============================================
int summa(int n)
{ //1+2+3+n med for-loop
int delsum=0;
for (int i=1;i<=n;i++)
delsum=delsum+i;
return delsum;
}
//===============================================
int rek_summa(int n)
{ //1+2+3+n med rekursion
if (n==1)
return 1;
else
return rek_summa(n-1)+n; //Rekursivt anrop av rek_summa
}
//===============================================
void rek_summa_ref(int n, int& sum)
{ //1+2+3+n med rekursion och referensparameter
if (n>0)
{
sum=sum+n;
rek_summa_ref(n-1,sum); //Rekursivt anrop av rek_summa_ref
}
}
//===============================================
main()
{
int k, sum=0;
cout << "Ange ett tal: ";
cin >> k;
cout << "For-summa: " << summa(k) << endl;
cout << "Rekursionsumma: " << rek_summa(k) << endl;
rek_summa_ref(k,sum);
cout << "Rekursionsumma med referensparameter: " << sum << endl;
}
Rekursion är relativt minneskrävande, eftersom vid varje rekursivt anrop lagras en ny upplaga
av funktionen i datorns minne. Detta gör rekursiva program långsammmare än en iterativ och
i värsta fall tar minnet slut.

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 1234…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

intervallhalvering. Det fungerar på följande sätt.


Proceduren Roten anropas med två värden, ett x-värde
till vänster (x1) om nollstället och ett x-värde (x2) till
höger om nollstället (se figuren): x1 x2 x

Roten (double x1, double x2, double& xmitt); xmitt


Proceduren räknar sedan ut x-värdet (xmitt) mitt
emellan x1 och x2, och kollar därefter om funktionen
skär x-axeln mellan x1 och xmitt eller mellan xmitt
och x2. Funktionen skär x-axeln emellan x1 och xmitt
om produkten av funktionsvärdena för x1 och xmitt är negativ. Då anropas proceduren
rekursivt:
Roten (x1, xmitt, rot);

Skär funktionen i det andra intervallet blir anropet:


Roten (xmitt, x2, rot);
Detta pågår tills intervallet är godtyckligt litet, t ex när differensen x2 - x1 = 0,00001 om man
vill ha fem siffrors noggrannhet i roten. Utskriften görs sedan i proceduren Roten. Förslagsvis
beräknas funktionsvärdet i en separat funktion. I detta och följande två exempel används
funktionen y = 2 - x2, som alltså har har rötterna  2  1,41421... Prova gärna med andra
funktioner. Vilka rötter har t ex funktionen y = sin(x) ?

*Ö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

Egen funktion för fördröjning


En enkel funktion för fördröjning kan man göra själv genom att använda time-funktionen.
Funktionen delay i exemplet nedan fördröjer exekveringen i tiden tid sekunder. Minsta
fördröjningen är 0.5 s:
void delay(double tid)
{
double t0=time(0);
while (time(0)-t0<=tid);
}
*Övning 6.19:
Skriv ett program med hjälp av delay-funktionen i exemplet ovan som flyttar en text över
skärmen.

*Ö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++.

Läsning av text från fil


Vid läsning från och lagring på externa filer måste man skapa s k strömobjekt. I
programexemplet nedan är f1 (filvariabel) ett sådant strömobjekt tillhörande klassen ifstream
vid läsning från en fil. Detta kräver inkluderingsfilen fstream. Ett program som läser och
skriver ut innehållet i en textfil har följande struktur:
#include <iostream>
#include <fstream> //Ny inkluderingsfil för filhantering. Anges utan .h
using namespace std; //Glöm inte namespace!
main()
{
char filnamn[10]; //Filnamnet får ej vara av typen string
cout << "Ange textfilens namn: ";
cin >> filnamn; //Ange sökvägen om inte texfilen ligger i samma mapp som
//programmet.
ifstream f1(filnamn); //Kopplar samman filnamnet med ifstream-objektet f1.
cout << "Detta står i filen: " << endl;
cout << f1.rdbuf(); //Skriver ut hela innehållet i filen.
}
Ett alternativ är att deklarera variabeln f1 som ett strömobjekt av klassen ifstream och öppna
filen med funktionen open:
ifstream f1;
f1.open(filnamn); //Istället för ifstream f1(filnamn);
Filen stängs när kopplingen mellan fil och strömobjekt (f1 i vårt exempel) upphör. Detta görs
automatiskt när programmet når slutet. Vill man emellertid ’återanvända’ strömvariabeln för
en anna fil måste filen stängas med funktionen close:
f1.close();
Använd gärna följande satser för att kolla om filen som öppnas finns:
if (!f1)
{
cout << "Kunde ej öppna filen";
return 0; //Programmet avslutas om detta ligger i main()
}
Övning 7.1
Skriv en kort mening i exempelvis texthanteraren Anteckningar och spara dokumentet i din
C++-mapp. Kopiera sedan programmetexemplet ovan, kompilera det och kör det för textfilen
du sparade.

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.

Läsning av tecken ur fil


Förra exemplet läste och skrev vi ut hela filen på en gång med satsen:
f1.rdbuf();
Vill vi läsa tecken för tecken ur filen används istället satsen:
f1.get(c);
Då får teckenvariabeln c filpekarens aktuella värde. Filpekaren flyttas ett tecken för varje
anrop av satsen. En alternativ tilldelning av c är:
f1 >> c;
Följande booleska sats är ’false’ tills filpekaren når filslutet:
f1.eof()
Nu har vi några verktyg som ger oss möjlighet att bl a skriva ut tecken för tecken. Följande
programrader visar hur det går till:

f1.get(c);
while (!f1.eof())
{
cout << c;
f1.get(c);
}

Utskriften kan även göras med:
cout.put(c);
Övning 7.3:
Modifiera det första exempel så att det skriver ut filinnehållet med ett tecken på var sin rad.

Ö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

Konvertering mellan stora och små bokstäver


Vid exempelvis räkning av antalet bokstäver spelar det ingen roll om det är gemener (små)
eller versaler (stora). Följande två funktioner tolower respektive toupper konverterar till
gemener respektive versaler:
teck=(char)tolower(‟A‟); //Variabeln teck får värdet ‟a‟
teck=(char)toupper(„a‟); //Variabeln teck får värdet ‟A‟
Konverteringen fungerar dock ej för å, ä och ö.

Ö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

Lagra text på fil


Hittills har vi läst från existerande textfiler. Vi skall nu lära oss att från c++-programmet
skapa nya textfiler och lagra textdata på dessa. Programmet nedan läser in ett filnamn och
sedan en text som sparas på filen:
#include <iostream>
#include <fstream> //Ny inkluderingsfil för filhantering.
#include "svtecken.h"
using namespace std;
int main()
{
char filnamn[20], text[100];
teckenbyt();
cout << "Ange textfilens namn: ";
cin.getline(filnamn, 20);
ofstream f1(filnamn); //Skapar en ny tom fil att lagra i.
cout << "skriv in text:" << endl;
cin.getline(text,100); //Läser in text till enter.
f1 << text; //Text lagras efter all inläsning
f1.close();
return 0;
}
Detta påminner mycket om det inledande exemplet om läsning från fil. Den väsentliga
skillnaden här är att klassen ofstream används vid skrivning till (d v s lagring på) fil. Anropet
ofstream skapar en ny fil med namnet filnamn. Finns filen med det namnet tidigare raderas
innehållet innan den nya texten lagras på filen. Antag nu att vi i samma program vill kolla om
lagring fungerar genom att skriva ut innehållet i den nyss skapade textfilen. Följande tre rader
kan då läggas till efter f1.close() i exemplet ovan:
ifstream f2(filnamn); //Öppnar filen med strömobjektet f2 (fungerar ej med f1)
cout << "Detta står i filen: " << endl;
cout << f2.rdbuf();
f2.close();
Filen som är associerad med strömobjektet f1 måste stängas (close) innan den kan öppnas för
läsning. Den öppnas då med strömobjektet f2, som måste ha ett annat namn än f1 (annars
deklareras den otillåtet två gånger).

Ö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

Lagring av tecken på fil


I förra exemplen lagrades en hel textsträng på filen. Nu vill vi lagra tecken för tecken.
Följande sats lagrar innehållet i teckenvariabeln c på filen:
f1.put(c);
Följande rader lagrar en inmatad text (inklusive mellanslag och radbrytningar) tecken för
tecken på filen tills ett ’+’-tecken anges:

cin.get(c);
while (c!='+')
{
f1.put(c); //Lagrar tecknet c på filen.
cin.get(c); //Läser som getche, men även radbrytningar.
}

Övning 7.10:
Modifiera övning 7.9 så att det även går att lagra radbrytning.

Lägga till text i existerande fil


Hittills har filerna vi skapat alltid varit tomma eller tömts när vi öppnat dem. Det går
emellertid att lägga till text i slutet på en existerande fil. Tillägget ios::app lägger till inmatad
text i slutet på en existerande fil:
ofstream f1(filnamn, ios::app);
Existerar inte filen tidigare skapas en tom fil.

Ö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;

Eller via inmatning:


cout << "Ange förnamn: ";
cin >> person1.fnamn;
cout << "Ange efternamn: ";
cin >> person1.enamn;
cout << "Ange ålder: ";
cin >> person1.age;
Innehållet i variabeln person1 tilldelas en annan variabel av strukturtypen person, t ex p, utan
att alla tre fältnamnen behöver anges:
p = person1;

C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 59 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson

Ett program för inläsning och utskrift kan se ut på följande sätt:


#include <iostream>
using namespace std;
int main()
{
struct person //Sammansatta datatypen person
{
char fnamn[10], enamn[20];
int age;
};

person pers1, pers2; //Två variabler av typen person deklarerade


cout << "Ange första personens förnamn: ";
cin >> pers1.fnamn;
cout << "Ange första personens efternamn: ";
cin >> pers1.enamn;
cout << "Ange första personens ålder: ";
cin >> pers1.age;
pers2=pers1; //Variablen pers2 tilldelas värdet av pers1
cout << "Förnamn: " << pers2.fnamn << endl;
cout << "Efternamn: " << pers2.enamn << endl;
cout << "Efternamn: " << pers2.age << endl;
return 0;
}
Skall många personer lagras är det lämpligt att göra det i ett fält, t ex i fältvariabeln folk, med
datatypen person:
person folk[10]; //Fältet folk lagrar 10 personer
Inläsningen av personernas namn och ålder görs lämpligen i en for-loop och kan då antingen
göras via strukturvariabelnvariabeln p:
for (int i=0; i<10;i++)
{
cout << "Förnamn: ";
cin >>p.fnamn;
cout << "Efternamn: ";
cin >>p.enamn;
cout << "Ålder: ";
cin >>p.age;
folk[i]=p;
}

Eller direkt till fältvariabeln folk:


for (int i=0; i<10;i++)
{
cout << "Förnamn: ";
cin >>folk[i].fnamn;
cout << "Efternamn: ";
cin >>folk[i].enamn;
cout << "Ålder: ";
cin >>folk[i].age;
}

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.12 - inlämningsuppgift:


Du skall nu skriva ett längre program för hantering av en adresslista innehållande förnamn,
efternamn och ålder. Programmet skall fungera som exemplet
Anders_A/cplusplus/struktur.exe. Läs först igenom hela uppgiften och lös den sedan enligt
punkterna nedan:
a) Deklarera globalt en struktur person för hantering av personuppgifterna förnamn,
efternamn och ålder.
b) Deklarera globalt ett fält folk[20] av typen person som lagrar de inmatade personerna.
Deklarera även en global variabel antal för antalet lagrade personer i fältet folk.
c) Skriv funktionen void fyll(); som läser in personer till fältet folk. Finns redan personer
i folk läggs de inlästa efter dessa.
d) Skriv funktionen void skriv(); som skriver ut personuppgifterna i fältet folk i en
tabell, samt med ordningsnummer.
e) Skriv funktionen void ta_bort(); som raderar personen med det angivna
ordningsnumret. Observera att tabellen skrivs ut före och efter raderingen (anropa
skriv).
f) Skriv funktionen void sortera(); som sorterar efternamnen i bokstavsordning i fältet
folk. Observera att tabellen skrivs ut efter sorteringen.
g) Skriv funktionen void spara(); som lagrar innehållet i fältet folk på en binärfil.
h) Skriv funktionen void hamta(); som läser in personerna från binärfilen till fältet folk.
Funktionerna ovan skall anropas från en meny i main-funktionen. Du har två lektioner på dig
att lösa uppgiften. Du visar då en körning av programmet (så långt du har kommit) för läraren
och lämnar sedan en programutskrift till läraren för kommentarer. Börja nu med att skriva
programmet. Skriv en funktion i taget i den ordning de har i punktlistan ovan. Fyll efterhand
som funktionerna blir färdiga på med nya funktioner och val i menyn och provkör.
Kommentera gärna programkoden.

*Ö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

Egna inkluderingsfiler (headerfiler)


Ett C++-program inleds vanligtvis med s k inkluderingsfiler för ut- och inmatning,
stränghantering, matematikfunktioner etc:
#include <iostream.h> // In- och utmatning
#include <iomanip.h> // Formaterad utskrift
#include <string.h> // Stränghantering
#include <math.h> // Matematiska funktioner
Inkluderingsfiler är inget annat än filer innehållande standardfunktioner för olika
tillämpningar. Bokstaven ’h’ i slutet på varje inkluderingsfil står för header. Inkluderingsfiler
kallas därför även för headerfiler. Vi skall nu skapa en egen inkluderingsfil, bibliotek.h, för
alla användbara funktioner vi själva skrivit under kursens gång. Vi kan dessutom lägga in de
vanligaste inkluderingsfilerna så att vi slipper ange dem i programmen vi skriver. För att
exemplifiera användningen av egna inkluderingsfiler skapar vi först en inkluderingsfil
innehållande två funktioner - en som skriver ut ett streckad linje och en som adderar två
heltal. Vi lägger även in några vanliga inkluderingsfiler, samt en konstantdeklaration av talet
pi. Vår inkluderingsfil får då följande utseende:
#ifndef bibliotek_h //Kollar att inkluderingsfilen inte inkluderas mer än en gång.
#define bibliotek_h //Definierar variabeln bibliotek_h (här lämpligt namn)
#include <iostream>
#include "svtecken.h"
#include <fstream>
#include <iomanip>
#include <math.h>
#include <stdlib.h>
#include <time.h>
#include <string>
using namespace std;

const double pi=3.141592654; //Talet pi deklareras som en konstant.


void skriv_streck(); //Funktionsdeklarationer (prototyper)
int add(int, int); //Variablerna behöver inte anges i funktionsdeklarationen.

void skriv_streck() //Funktionsdefinition


{
cout << "-------------------------------------------------" << endl;
}

int add(int a, int b) //Funktionsdefinition


{
return a+b;
}
#endif
Vi sparar inkluderingsfilen under filnamnet bibliotek.h och placerar den i samma mapp som
programmet som skall använda den. De två första raderna #ifndef (if not define) och #define,
samt den sista raden #endif, kollar att filen bibliotek.h inte inkluderas mer än en gång i
programmet, t ex via en annan inkluderingsfil. Dessa rader är inte nödvändiga, men är bra att
ha med eftersom det inte är tillåtet att inkludera filen mer än en gång. Programmet som skall
använda sig av inkluderingsfilen har följande utseende:

C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 63 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson

#include "bibliotek.h" //Observera citationstecknen.


#include "conio+.h" //Kan ej läggas i inkluderingsfilen (fel i conio+.h?)
main()
{
int x,y;
teckenbyt();
skriv_streck();
cout << "Ange två tal: ";
cin >> x >> y;
cout <<"Summan är " << add(x,y) << endl;
skriv_streck();
cout << ”pi=” << pi << endl;
}
Observera att egna inkluderingsfiler omsluts av citationstecken. Även strukturer kan
deklareras i inkluderingsfilen. Ligger inte inkluderingsfilen i samma mapp som programmet
anges sökvägen:
#include "c:/anders_a/bibliotek.h"

Uppdelning i inkluderingsfil och definitionsfil


Stora inkluderingsfiler brukar delas upp i två filer – en inkluderingsfil (.h) för
funktionsdeklarationerna (prototyperna) och en definitionsfil (.cpp) för
funktionsdefinitionerna med koden för funktionerna. Filerna läggs i programmappen. I
föregående exempel skulle inkluderingsfilen bibliotek.h få följande utseende:
#ifndef bibliotek_h
#define bibliotek_h
#include <iostream>
#include "svtecken.h"
#include <fstream>
#include <iomanip>
#include <math.h>
#include <stdlib.h>
#include <time.h>
#include <string>
using namespace std;

const double pi=3.141592654;


void skriv_streck(); //Funktionsdeklaration (prototyp)
int add(int,int); //Funktionsdeklaration (prototyp)
#endif
Definitionsfilen bibliotek.cpp (samma namn men .cpp) får följande utseende:
#include "bibliotek.h"
void skriv_streck() //Funktionsdefinition
{
cout << "------------------------------------------------------------------" << endl;
}

int add(int x, int y) //Funktionsdefinition


{
return x+y;
}
Skall filerna bibliotek.h och bibliotek.cpp användas av ett annat program måste filen
bibliotek.cpp inkluderas i dess projekt via menyvalet Project/Add To Project/Files… Filen
bibliotek.h behöver dock inte inkluderas i projektet.

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.

Klass och objekt


Nedan skapar vi klassen Person innehållande datamedlemmar för förnamn, efternamn, ålder,
längd och vikt:
#include "svtecken.h" //Övriga inkluderingsfilerna utelämnas här av utrymmesskäl
using namespace std;
//-------------------------------------------------------------------------------------------------------------------------------------
class Person //Definition av klassen Person börjar. Versal på Person
{
public: //Anger att datamedlemmarna nås utanför klassen
char fnamn[20], enamn[20]; //Deklaration av datamedlemmar
int age, lengd, vikt; //Deklaration av datamedlemmar
}; //Definition av klassen slutar
//----------------------------------------------------------------------------------------------------------------------------- --------
int main()
{
Person p; //Variabeln p är ett objekt av klassen Person (instans av klassen)
cout << "Ange förnamn: ";
cin >> p.fnamn; //Klassens datamedlemmar anges med punktoperatorn
cout << "Ange efternamn: ";
cin >> p.enamn;
cout << "Ange ålder, längd och vikt: ";
cin >> p.age>> p.lengd >> p.vikt;
cout << p.fnamn << p.enamn << p.age << p.lengd << p.vikt <<endl;
return 0;
}
//----------------------------------------------------------------------------------------------------------------------------- --------
Klassnamnet brukar anges med stor boksatv för att lättare kunna särskiljas från variabler.
Främsta skillnaden hittills mellan struktur och klass är annars att ordet public måste anges för
att datamedlemmarna (variablerna) skall vara åtkomliga (synliga) utanför klassen. Anges inte
public blir de automatiskt private och osynliga utanför klassen. Observera även att
variabeldeklarationen av p av klasstypen Person gör att p blir ett objekt tillhörande klassen
Person. Variabeldeklarationen innebär att p är en instans av klassen.

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

using namespace std; //Övriga inkluderingsfilerna utelämnas här


//------------------------------------------------------------------------------------------------ -------------------------------------
class Person //Definition av klassen Person (med versal)
{
public: //Anger att medlemsfunktionerna syns utanför klassen
void inmatning(char fn[],char en[],int ag,int le,int vi); //Deklaration av medlemsfunktioner
void skriv_namn(); //Deklaration av funktion för utskrift av för- och efternamn
int ge_alder() {return age;} //Korta funktioner definieras i klassdefinitionen
int ge_langd() {return lengd;} //Funktionen returnerar objektets längd
int ge_vikt() {return vikt;} //Funktionen returnerar objektets vikt
private: //Anger att datamedlemmarna ej syns utanför klassen
char fnamn[20], enamn[20]; //Deklaration av datamedlemmar (klassvariabler)
int age, lengd, vikt;
}; //Definition av klassen slutar
//------------------------------------------------------------------------------------------------------------ -------------------------
void Person::inmatning(char fn[],char en[],int ag,int le,int vi)
{ //Definition av medlemsfunktion för inläsning till klassvariablerna (datamedlemmarna)
age=ag;
lengd=le;
vikt=vi; //Klassvariablerna är åtkomliga i klassfunktionerna
strcpy(fnamn,fn);
strcpy(enamn,en);
}
//----------------------------------------------------------------------------------------------------------------------------- --------
void Person::skriv_namn() //Definition av medlemsfunktion för utskrift av för- och efternamn
{
cout << setw(20) << fnamn << setw(20) << enamn << endl;
}
//----------------------------------------------------------------------------------------------------------------------------- --------
int main()
{
Person p; //Instans av klassen Person, d v s p är ett objekt av klassen
char f[20], e[20];
int a,l,v;
cout << "Ange förnamn: ";
cin >> f;
cout << "Ange efternamn: ";
cin >> e;
cout << "Ange ålder, längd och vikt: ";
cin >> a >> l >> v;
p.inmatning(f,e,a,l,v); //Anrop av objektet p:s funktion inmatning
p.skriv_namn(); //Skriver ut inmatade för- och efternamn
cout << "Ålder:"<<p.ge_alder()<<"Längd:"<<p.ge_langd()<<"Vikt:"<<p.ge_vikt() <<endl;
return 0;
}
//-------------------------------------------------------------------------------------------------------------------------------------
Klassen Person innehåller nu fem medlemsfunktioner och fem datamedlemmar
(klassvariabler), d v s totalt tio attribut som beskriver klassens egenskaper. Observera att
klassens namn anges med dubbla kolon (::) när klassfunktionerna (medlemsfunktionerna)
definieras separat, samt att klassvariablerna är åtkomliga i klassfunktionerna (de tillhör ju
klassen). Observera även att korta klassfunktioner (ge_alder t ex) kan definieras direkt i
klassdefinitionen. Alternativet är att skriva en separat funktionsdefinition (som för inmatning
och skriv_namn ovan):
int Person::ge_alder() //Definition av medlemsfunktion som returnerar klassvariabln age
{
return age;
}

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

char fnamn[20], enamn[20];


int age, lengd, vikt;
};
//------------------------------------------------------------------------------------------------
Person::~Person() //Destruktorns definition
{
cout << "Objektet med åldern " << age << " tas bort." << endl;
}
//------------------------------------------------------------------------------------------------
Övning 8.1:
Du skall skriva ett program som läser in en persons förnamn, efternamn, födelseår, längd
(meter) och vikt. Programmet skall sedan skriva ut personens för- och efternamn, ålder , BMI-
värde (se nedan) med en decimal och om personen är överviktig. Programmet skall fungera
som exemplet Anders_A/cplusplus/klass_8_1.exe. Programmet skall ha följande
klassdefinition:
class Person
{
public:
void inmatning(char fn[],char en[],int f,double le,int vi);
void skriv_namn();
double bmi();
int alder(int artal);
private:
char fnamn[20], enamn[20];
int vikt, bar;
double lengd;
};
Klassen har följande medlemsfunktioner:
 inmatning(…); läser in personens förnamn, efternamn, födelseår, längd och vikt.
 skriv_namn(); skriver ut för- och efternamn på en rad utan radbrytning.
 bmi(); beräknar personens BMI (body mass index), d v s vikten (kg) dividerad med
längden (meter) i kvadrat.
 alder(ar); beräknar personens ålder utifrån inmatat innevarande årtal.
Klassen har följande datamedlemmar (klassvariabler):
 fnamn (förnamn), enamn (efternamn), vikt (vikt), bar (födelseår) och lengd (längd).
Programmet innehåller dessutom en funktion string overvikt(double bmi); som skriver ut om
personen är underviktig (bmi<20), överviktig (bmi>20) eller normalviktig.
Övning 8.2:
Ändra klassdefinitionen i föregående uppgift så att den får följande utseende:
class Person
{
public:
double bmi();
int alder(int artal);
char fnamn[20], enamn[20];
int vikt, bar;
double lengd;
};
Observera att klassens samtliga attribut är synbara (public) utifrån. Programmet skall nu
kunna lagra flera personer i ett fält. Modifiera och använd funktionerna för inläsning, utskrift,

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.

Programmet skall fungera som exemplet Anders_A/cplusplus/klass_8_2.exe.

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

cprintf("%c",(char)219); //ASCII-kod för fyrkantigt tecken


}
//------------------------------------------------------------------------------------------------
void Rektangel::rita_rektangel() //Ritar sidorna i rektangeln (gör variant med klassen Linje)
{ //mi och ma är två egna funktioner som returnerar minsta
setcolor(farg); //respektive största värdet.
for (int x=min(p1.x,p2.x);x<=max(p1.x,p2.x);x++)
{
gotoxy(x,p1.y);
cprintf("%c",(char)219);
}
for (x=min(p1.x,p2.x);x<=ma(p1.x,p2.x);x++)
{
gotoxy(x,p2.y);
cprintf("%c",(char)219);
}
for (int y=min(p1.y,p2.y);y<=max(p1.y,p2.y);y++)
{
gotoxy(p1.x,y);
cprintf("%c",(char)219);
}
for (y=min(p1.y,p2.y);y<=max(p1.y,p2.y);y++)
{
gotoxy(p2.x,y);
cprintf("%c",(char)219);
}
}
//------------------------------------------------------------------------------------------------
void ritarektangel() //Anropas av menyn för beräkning av area och ritning av rektangel
{
Rektangel R;
R.p1.inmatning_punkt(); //Observera hur inmatningen av en punkt görs
R.p2.inmatning_punkt();
cout << "Rektangelns area=" << R.area()<<endl;
cout << "Ange en färg (1-16):";
cin>>R.farg;
clrscr();
R.rita_rektangel();
setcolor(7);
}
//------------------------------------------------------------------------------------------------
cout << "Gör ett val i menyn nedan: " << endl;
cout << "1: Rita en punkt " << endl;
cout << "2: Slumpa punkter " << endl;
cout << "3: Linjelängd och ritar en linje " << endl;
cout << "4: Slumpa linjer " << endl;
cout << "5: Rektangelarea och ritar en rektangel " << endl;
cout << "6: Slumpa rektanglar " << endl;
cout << "7: Avsluta: "<< endl;
Lös uppgiften stegvis i menyns ordning ovan, d v s skriv successivt klassmetoderna som
saknas, provkör och rätta eventuella fel innan du bygger vidare på programmet. Det färdiga
programmet skall provköras och kommenteras på en utskrift av läraren.

C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 78 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson

Arv, basklass och härledd klass


Förutom att klasser kan bygga på varandra, kan de även ärva egenskaper (datamedlemmar och
klassmetoder) från andra klasser. Denna möjlighet kan spara arbete och många programrader,
samtidigt som programmet blir mer strukturerat. Klassen som egenskaperna ärvs ifrån kallas
basklass och klassen som ärver kallas härledd klass. Begreppet arv skall nu illustreras med
några klasser för olika fordonstyper (cykel, bil, buss, lastbil och van). Vi börjar med att
definiera den allmänna klassen Fordon, som håller koll på fordonets antal hjul och vikt.
//------------------------------------------------------------------------------------------------
class Fordon
{
int ant_hjul, vikt; //Datamedlemmar för antal hjul och vikt
public:
Fordon(int a, int v); //Konstruktordekl. tilldelar antal hjul och vikt vid instans av objekt
void skrivut_fordon(); //Metoddeklaration för utskrift av datamedlemmarna
};
//------------------------------------------------------------------------------------------------
Fordon::Fordon(int a, int v) //Konstruktordefinition
{
ant_hjul=a;
vikt=v;
}
//------------------------------------------------------------------------------------------------
void Fordon::skrivut_fordon() //Metoddefinition
{
cout << "Antal hjul:" << ant_hjul << endl;
cout << "Vikt:" << vikt << endl;
}
//------------------------------------------------------------------------------------------------
int main()
{
Fordon f(2,17); //Instans av ett fordon med 2 hjul och vikten 89
teckenbyt();
f.skrivut_fordon();
getch();
return 0;
}
Programmet ger utskriften:
Antal hjul:2
Vikt:17
Vi bygger nu ut programmet med den härledda klassen Cykel, som ärver basklassen Fordon:s
egenskaper:

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

Programmet ger utskriften:


En cykel Fordon
Antal växlar: 21
Typ: Herr
Antal hjul:2 Cykel
Vikt:17
Figuren visar arvsstrukturen. Observera några saker. I konstruktordefinitionen för klassen
Cykel anges klassen Fordon med kolon:
Cykel::Cykel(int ahj, int vi, int av, char ty[]) : Fordon(ahj,vi)
På så sätt läses parametrarna ahj och vi in till klassen Fordon:s konstruktor. Parametrarna
skall ha samma namn, medan ordningen inte spelar någon roll. Ordet protected: (skyddad)
anger att klassen Fordon:s datamedlemmar ant_hjul och vikt blir läsbara i den härledda
klassen Cykel. I övrigt är de inte läsbara (som private). Vi utnyttjar dock inte läsbarheten i
vårt program. Vi skulle kunna gjort det genom att ersätta
Fordon::skrivut();
i klassen Cykel:s metod skrivut() med
cout << "Antal hjul:" << ant_hjul << endl;
cout << "Vikt:" << vikt << endl;
Vår variant är dock bättre, d v s att anropa metoden skrivut() från klassen Fordon. Notera att
vi måste ange klassnamnet med dubbla kolon därför att metoderna är överlagrade, d v s det
finns en metod med samma namn i klassen Cykel som anropas i första hand. Klassen Cykel
definieras med public Fordon:
class Cykel : public Fordon
Det innebär ett synligt arv (vanligast), där alla datamedlemmar som är skyddade eller synliga
(public) i klassen Fordon även bli det i klassen Cykel. Om arvet anges med protected blir det
ett skyddat arv. Det innebär att alla medlemmar som är skyddade eller synliga i klassen
Fordon blir skyddade i klassen Cykel. Anges arvet med private blir alla datamedlemmar som
är synliga eller skyddade i klassen Fordon privata i klassen Cykel.

Flera härledda klasser


Vi kompletterar föregående exempel med klasserna Motorfordon, Personbil och Lastbil.
Samtidigt spar vi utrymme genom att använda parameterlista i konstruktorerna:
//------------------------------------------------------------------------------------------------
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 Cykel : public Fordon
{
int ant_vaxel;
char typ[20];
public: //Fordon:s konstruktor läser in parametrar från Cykels konstruktor
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 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

metoden skrivut() i klassen Fordon anropas av objektet bil


tillhörande klassen Personbil: Motorfordon Cykel
n
bil.Fordon::skrivut; //Fungerar
Däremot kan inte en ärvd protected-deklarerad datamedlem Lastbil Personbil
läsas av objektet:
cout << bil.Fordon::vikt << endl; //Fungerar ej
Datamedlemmarna är dock läsbara i en definition för en klassmetod, exempelvis kan följande
sats ligga i klassen Personbil:s metoddefinition skrivut:
cout << Fordon::vikt << endl; //Fungerar

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

class Personbil: virtual public Motorfordon //Klassen Motorfordon ärvs virtuellt

{
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.

Klass: Sjojungfru; medlemmar: farg (char); konstruktor: Sjojungfru(), tilldelar medlemmen


alder i klassen Manniska ett slumpmässigt värde mellan 1 och 100; metoder: void lasin(),
void skrivut(), void gissa_alder(), låter användare gissa sjöjungfruns ålder med ledorden För
högt och För lågt; arv: Manniska, Fisk.

Programmet har följande meny:


cout << "Gör ett val i menyn nedan: " << endl;
cout << "1: Inläsning " << endl; //Observera att åldern inte läses in
cout << "2: Utskrift "<< endl; //Skriver ut värdet på alla medlemmar
cout << "3: Gissa sjöjungfruns ålder "<< endl;
cout << "8: Avsluta: "<< endl;

Programmet skall fungera som exemplet Anders_A/cplusplus/klass_8_4.exe.

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

Klasser i inkluderinsfil och definitionsfil


I kapitel 7 (s. 59) skapade vi egna inkluderingsfiler (.h). På liknande sätt kan
klassdefinitionerna placeras i en inkluderingsfil. Fördelen med detta är att flera program kan
utnyttja klasserna. Vi visade även tidigare att stora inkluderingsfiler delas upp i en
inkluderingsfil (.h) för funktionsdeklarationerna och en definitionsfil (.cpp) för
funktionsdefinitionerna. När det gäller klasser placeras klassdefinitionen (borde heta
klassdeklaration!) i inkluderingsfilen och medlemsfunktionernas definitioner i
definitionsfilen. I följande exempel har det tidigare exemplet med klasserna Fordon och Cykel
(s. 76) delats upp i en inkluderingsfil och en definitionsfil. Följande fil är inkluderingsfilen
fordon_cykel.h:
#include <iostream>
#include <fstream>
#ifndef bibliotek_h
#define bibliotek_h
#include <string>
#include <time.h>
#include <stdlib.h>
#include <math.h>
#include <iomanip>
#include "svtecken.h"
using namespace std;
//----------------------------------------------------------------------------------------------- -
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[]);
void skrivut();
};
//------------------------------------------------------------------------------------------------
#endif
Följande fil är definitionsfilen fordon_cykel.cpp:
#include "fordon_cykel.h"
//------------------------------------------------------------------------------------------------
Fordon::Fordon(int a, int v)
{
ant_hjul=a;
vikt=v;
}
//------------------------------------------------------------------------------------------------
void Fordon::skrivut()
{
cout << "Antal hjul:" << ant_hjul << endl;
cout << "Vikt:" << vikt << endl;
}

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

9. Pekare och dynamisk minnesallokering


I programmen vi hittills har skrivit har vi deklarerar de variabler programmet använder i
programkoden, s k statisk minnesallokering. D v s minnet som reserveras för variabler vid
kompileringen kan inte ändras under programexekveringen. Exempelvis måste vi ju i
programmet ange hur stor en vektor skall vara. Detta har vi hittills inte kunnat påverka under
körningen av programmet. Med dynamisk minnesallokering kan vi emellertid reservera minne
under programexekveringen. Exempelvis kan vektorlängden bestämmas när programmet körs.
Begreppet pekare används för att åstadkomma dynamisk minnesallokering.

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

Här ändras även värdet på k till 7 (pekaren pekar ju på k:s adress).


Följande fungerar dock inte:
p
int *p;
*p=7; NULL
Pekaren p saknar här minnesutrymme (adress) att peka på. En pekare
som saknar adress att peka på kallas tom pekare och brukar tilldelas värdet NULL:
p=NULL; //Fungerar även med 0.
Ett nytt minnesutrymma kan dock allokeras dynamiskt under exekveringen med det
reserverade ordet new på följande sätt:
int *p;
p=new int; //Datatypen minnet allokeras för anges efter new.
*p=7;

C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 89 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson

Vi deklarerar en ny pekarvariabel p1 och låter den peka på samma adress som p:


int *p, *p1;
p1
p=new int;
*p=7; p
p1=p; //p1 pekar på samma adress som p.
cout << "pekaren: " << *p1 << endl; //7 skrivs ut.
7

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

Pekare och fält


I C++ är pekare och fält (vektorer) praktiskt taget samma sak. Fältets position i pekar på
positionen i+1, som pekar på positionen i+2 o s v utan att man som användare behöver tänka
på detta. För att illustrera hur pekare och fält hänger samman deklarerar vi först fältet a[5]
med de fem heltalen 10, 11, 12, 13 och 14, samt heltalspekaren p:
int a[]={10,11,12,13,14}, *p;
Följande sats pekar ut första elementet (med index 0) i fältet:
p=&a[0];
p
Eller enklare:
p=a;
Fältets första element kan alltså skrivas ut med a 10 11 12 13 14
följande två likvärdiga satser: 0 1 2 3 4
cout << *a << endl; //Fältet a är en pekare
cout << *p << endl;
Figuren till höger visar hur det ser ut. Fältets fjärde element med index 3 (d v s 13) kan nu
skrivas ut på följande tre sätt:
cout << a[3] << endl;
cout << p[3]<< endl; //Pekaren p kan betraktas som ett fält.
cout << *(p+3) << endl; //Innebär att adressen tre positioner längre bort pekas ut.
cout << *(a+3) << endl;
Satserna visar att fältvariabeln a i praktiken är en pekare som pekar på fältets första element,
liksom att pekaren p kan betraktas som en fältvariabel. Genom att allokera minne för en
pekare som pekar på ett fält kan vi bestämma fältets storlek under exekveringen, s k dynamisk
minnesallokering. Detta är nytt för oss! Tidigare har vi ju varit tvugna att bestämma
fältstorleken statiskt i programkoden. Följande sats allokerar minne för ett fält med n heltal,
där p pekar på första elementet:
p=new int[n];
Följande rader lagrar heltal i ett fält. Först läses hur många heltal in som skall läsas in och
sedan heltalen:
int *p, antal;
cout << "Ange antal tal som skall läsas in: ";
cin >> antal;
p=new int[antal]; //Fältets storlek bestämms under exekveringen (dynamisk allokering).
for (int i=1;i<=antal;i++)
{
cout << "Ange tal " << i << " :";
cin >> p[i];
}
Minnesutrymmet som allokerats för fältet och som p pekar på frigörs med följande sats:
delete [] p;

C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 91 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson

Pekare till textsträngar


Pekare och textsträngar fungerar som pekare och fält. Följande exempel illustrerar detta:
char namn[]="kalle",*n;
n=namn;
cout << n << endl; //Utskrift: kalle
cout << *n << endl; //Utskrift: k
cout << *(n+4) << endl; //Utskrift: e
Funktioner som returnerar textsträngar av typen char måste anges som pekare. Följande
exempel illustrerar detta:
char *namn() //Funktionen pekar ut textsträngens första tecken.
{
return "kalle";
}
main()
{
cout << namn() << endl; //kalle skrivs ut.
cout << *namn() << endl; //k skrivs ut, d v s tecknet som namn pekar på.
}
Om funktionen namn() ovan angetts utan *-tecken hade felmeddelandet vid kompileringen
angett att för många tecken skrivs ut till typen char, d v s ett typfel. Funktioner med
textparametrar kan även anropas med pekare. Funktionen namn i följande program anropas
med en pekarvariabel:
void namn(char *n)
{
cout << n << endl; //pelle skrivs ut
}
main()
{
char *k="pelle";
namn(k);
}
Programmet kan även lösas på ’traditionellt’ sätt med ett textfält:
void namn(char n[])
{
cout << n << endl;
}
main()
{
char k[6]="pelle";
namn(k);
}
Övning 9.4:
Skriv ett program som läser in förnamn och som sedan skriver ut dem på samma rad. Antalet
förnamn läses in först. Namnen skall lagras i ett fält av strängar (klassen string) som är lika
stort som antalet förnamn, d v s fältet skall skall skapas dynamiskt via en pekarvariabel.
Programmet skall fungera som exemplet Anders_A/cplusplus/ovning_9_4.exe.

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;
}
//------------------------------------------------------------------------------------------------

Funktioner för att länka och skriva ut lista


Programkoden kan komprimeras ytterligare om konstruktorn deklareras med parameterlista
direkt i klassdefinitionen. I följande exempel skapas nya element med funktionen lagg_forst,
medan utskriften görs med funktionen skrivut. På så sätt blir programmet generellare, t ex kan
funktionerna användas av andra program som vill hantera länkade listor. Programmet blir då:
#include <iostream.h>
//------------------------------------------------------------------------------------------------
class Box
{
public:
int tal;
Box *next;
Box (Box *p, int t):next(p),tal(t){} //Initieringslista för konstruktor
};
//------------------------------------------------------------------------------------------------
void lagg_forst(Box *& p, int t) //Referensparameter eftersom p ändras i funktion.
{
p=new Box(p,t);
}
//------------------------------------------------------------------------------------------------
void skrivut(Box *p) //p skickas som parameter
{
while (p!=NULL)
{
cout << p->tal << endl;
p=p->next;

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);
}
}

Kolla tal i länkad lista


Följande funktion kollar om heltalet n finns i den länkade listan:
void serch(Box *first, int n)
{
if (first!=NULL)
{
if (first->tal==n)
cout << "Talet finns" << endl;
else
serch(first->next,n);
}
else
cout << "Talet saknas" << endl;
}

C:\Users\REALIS~1\AppData\Local\Temp\Cplus_lektioner.doc 95 10-09-17
LEKTIONSGENOMGÅNGAR I C++ av Anders Andersson

Ta bort element ur länkad lista


I en vektor är det krångligt att ta bort ett värde med ett godtyckligt index. Detta är dock
ganska enkelt i en länkad lista. Följande funktion ta_bort tar bort ett element med ett visst
värde ur en länkad lista:
void ta_bort(Box *&p, int t)
{
Box *temp=p; //Variabeln temp används därför att p måste peka på första elementet.
if (p->tal==t) //Första elementet behandlas separat. Här behövs ej temp.
p=p->next;
else
while (temp->next!=NULL) //Loopar så länge utpekat element inte är det sista.
if (temp->next->tal==t) //Kollar talet i elementet efter det utpekate elementet.
temp->next=temp->next->next; //Pekar i så fall förbi detta elementet (se fig)
else
temp=temp->next;
}
p

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:

 Härledda klasser kan typomvandlas till basklasser.

 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

You might also like