Programmering i C++ : en innføring i strukturert og objektorientert programmering
 8205307334

Citation preview

Else Lervik | Mildrid Ljosland

Programmering i C++ En innføring i strukturert og objektorientert programmering

GYLDENDAL AKADEMISK

© Forfatterne, Stiftelsen TISIP og Gyldendal Norsk Forlag AS 2003

1. utgave, 1. opplag 2003 Boka er en utvidet og bearbeidet versjon av tittelen Grunnleggende programmering i

C++ som ble utgitt på AdNotam Gyldendal i 1993.

ISBN 82-05-30733-4 Omslagsdesign: Kristin Berg Johnsen Layout: Designlaboratoriet

Sats: Forfatterne Brødtekst: Times New Roman 11/11 Papir: 90 g Galerie One

Trykk og innbinding: AIT Otta AS, 2003

Boka er utgitt i samarbeid mellom Gyldendal Akademisk og Stiftelsen TISIP Alle henvendelser om boka kan rettes til

Gyldendal Akademisk

Postboks 6730 St. Olavs plass 0130 Oslo www. gy 1 dendal .no/akademisk

akademisk@gyldendal .no www.tisip.no

Verken forfatterne, Stiftelsen TISIP eller Gyldendal Akademisk tar ansvar for at programmene i boka og på bokas intemettside

kan brukes til annet enn undervisningsformål. Det må ikke kopieres fra denne boka i strid med åndsverkloven

eller avtaler om kopiering inngått med KOPINOR,

interesseorgan for rettighetshavere til åndsverk. Kopiering i strid med lov eller avtale kan medføre erstatningsansvar og

inndragning, og kan straffes med bøter eller fengsel.

Forord Dette er ei lærebok i grunnleggende programmering, der C++ brukes som programmeringsspråk. Boka er tenkt brukt ved grunnkurs i program­ mering, fortrinnsvis på høgskolenivå, men også andre som ønsker en grunnleggende innføring i programmering, vil ha glede av boka.

Boka bygger på "Grunnleggende programmering i C++" og "Objektori­ entert programmering i C++" som kom ut i henholdsvis 1993 og 1994. Strukturen til boka følger i hovedtrekk den første av disse bøkene, men flere av emnene i den andre boka er tatt med. Ti år er lang tid i databran­ sjen, men C++ er fortsatt et meget aktuelt programmeringsspråk. Vi har derfor valgt å lage en ny utgave med de endringene som var nødvendige for å tilpasse den til dagens virkelighet. De vesentligste endringene er: -

Klassen string benyttes i stedet for nullterminerte strenger, som nå kun er tatt med for helt spesielle anvendelser.

-

Det har kommet inn et kapittel om Standard Template Library (STL), der spesielt vektorer får en grundig behandling.

-

Mer stoff om klasser og objekter er tatt med, for eksempel konstruktører og destruktører, utvidelse av bruksområdet til operatorer ("operator overloading"), polymorfi og arv.

-

Boka har fått egen nettside, www.tisip.no/boker/cpp, og stoff som tidligere fulgte med på diskett, kan du nå finne der. Også løsning på småoppgavene ligger nå på denne nettsiden.

Vi takker ...

-

Stiftelsen TISIP, som i sin tid gjorde det mulig for oss å skrive denne boka, og som nå gjør det mulig å få revidert den.

-

de mange studenter og andre som opp gjennom årene har brukt boka og kommet med verdifulle kommentarer og forslag.

-

student Ingvar Ljosland som har foretatt alle de trivielle endringene, slik at vi kunne konsentrere oss om de vesentlige tingene.

Trondheim juli 2003

Else Lervik

Mildrid Ljosland

Innhold Innledning

1

1 Datamaskiner og programmer 1-1 Datamaskiner, programmer og programmering 1-2 Fra kildekode til kjørbart program 1-3 Elementene i et C++-program 1-4 Livsløpet til programmer 1-5 Algoritmer og kontrollstrukturer Repetisjonsoppgaver Programmeringsoppgaver

5 6 12 15 24 26 30 30

2 Program med sekvensiell struktur 2-1 Et program med sekvensiell struktur 2-2 Ord og setninger 2-3 Data 2-4 Kommentarer og programmeringsstandard 2-5 Tilordning og aritmetiske uttrykk 2-6 Å bruke interne variabler 2-7 Hva skjer ved innlesing og utskrift? Repetisjonsoppgaver Programmeringsoppgaver

33 34 35 40 50 51 55 57 61 62

3 Valg som kontrollstruktur 3-1 Et program med valg som kontrollstruktur 3-2 Blokker og rekkevidden til navn 3-3 //-setningen 3-4 Logiske uttrykk 3-5 Flervalgsetninger 3-6 Å programmere beslutningstabeller Repetisjonsoppgaver Programmeringsoppgaver

65 66 69 73 79 84 88 90 91

4 Funksjoner med returverdi og inn-argumenter 4-1 Å bruke funksjoner - et eksempel 4-2 Å lage funksjoner 4-3 Flere funksjoner 4-4 Byggeklossprinsippet 4-5 Et gløtt bak kulissene Repetisjonsoppgaver Programmeringsoppgaver

95 96 100 106 119 122 126 127

vii

Innledning

viii

5 Løkke som kontrollstruktur 5-1 Et program med løkke som kontrollstruktur 5-2 Data leses inn og behandles i løkke 5-3 Å huske en dataverdi fra et løkkegjennomløp til neste 5-4 Tellerkontrollerte løkker 5-5 Nøstede kontrollstrukturer 5-6 Kontroll av inndata 5-7 Testing og feilsøking Repetisjonsoppgaver Programmeringsoppgaver

131 132 137 141 143 149 151 153 159 161

6 Tekststrenger 6-1 Strengobjekter 6-2 Strengobjekt som funksjonsargument og returverdi 6-3 Funksjoner knyttet til strengobjekt 6-4 Nullterminerte tekststrenger 6-5 Innlesing av tekst og tall om hverandre 6-6 Å omforme tekst til tall og omvendt 6-7 Pseudokode Repetisjonsoppgaver Programmeringsoppgaver

165 166 174 180 188 190 194 199 201 202

7 Funksjoner med ut-argumenter 7-1 Verdioverføring 7-2 Referanseoverføring 7-3 Funksjoner på flere nivåer 7-4 Funksjoner med utvidet bruksområde 7-5 Funksjonsargument med standardverdi Repetisjonsoppgaver Programmeringsoppgaver

205 206 212 219 228 230 232 233

8 Datatyper, operatorer og uttrykk 8-1 Uttrykk 8-2 De enkelte operatorene 8-3 Datatyper 8-4 Typeomforming Repetisjonsoppgaver Programmeringsoppgaver

237 238 243 252 264 270 271

9 Tabeller 9-1 Datastrukturen tabell 9-2 Å definere og bruke en tabell 9-3 Aktuell og maksimal lengde av tabellen

273 274 276 284

Innhold

9-4 Tabell som argument til en funksjon 9-5 Søking og sortering 9-6 Flerdimensjonale tabeller Repetisjonsoppgaver Programmeringsoppgaver

287 291 297 301 302

10 Objektorientert programmering 10-1 Eksempel på en klasse som byggekloss 10-2 Klasser som byggeklosser i et program 10-3 Å programmere med klasser 10-4 Tekststrenger som datamedlemmer 10-5 Relasjoner mellom objekter av samme klasse 10-6 Syntaksbeskrivelser og stil 10-7 Tabeller av objekter Repetisjonsoppgaver Programmeringsoppgaver

307 308 316 318 326 330 332 334 336 337

11 Å bruke datafiler 11-1 Enkel bruk av datafiler 11-2 Strømmer og filer 11-3 Filobjekter som funksjonsargumenter 11-4 Feil ved filen, eller bare filslutt? 11-5 Tekstfiler og binærfiler 11-6 Å bruke binærfiler 11-7 Direkte tilgang til innholdet i en fil 11-8 Noen spesielle filfunksjoner Repetisjonsoppgaver Programmeringsoppgaver

341 342 352 352 357 360 362 369 376 378 379

12 Å sette sammen flere filer til ettprogram 12-1 Kompilering og lenking 12-2 Navnerom 12-3 ISO/ANSI standardbibliotek 12-4 Å fordele programmet på flere filer Repetisjonsoppgaver Programmeringsoppgaver

383 384 386 390 393 403 404

13 Mer om kontrollstrukturer 13-1 Betingelsesoperatoren og rekkefølgeoperatoren 13-2 Flervalgsetningen switch 13-3 Mer om for-setningen 13-4 do-while -setningen 13-5 Løkker - sammendrag

407 408 410 416 421 422 ix

Innledning

x

13-6 Hva er en kontrollstruktur? Repetisjonsoppgaver Programmeringsoppgaver

423 424 425

14 Mer om klasser 14-1 Funksjonsargumenter og returverdier 14-2 Konstruktører 14-3 Destruktører 14-4 En-del-av-forhold mellom objekter Repetisjonsoppgaver Programmeringsoppgaver

427 428 435 447 448 458 459

15 Utvidet bruksområde for operatorer 15-1 Hva menes med å utvide bruksområdet for en operator? 15-2 Eksempel: klassen Broek 15-3 Å definere operatorer som ikke-medlemsfunksjoner 15-4 Spesielle ting å ta hensyn til Repetisjonsoppgaver Programmeringsoppgaver

463 464 467 478 482 485 486

16 Adresser og pekere 16-1 Å lage og bruke en peker 16-2 Tabeller og pekere 16-3 Aritmetikk på og sammenlikning av pekere 16-4 Pekere må behandles med forsiktighet! 16-5 Peker til et objekt 16-6 new og delete 16-7 Fra flerdimensjonal til endimensjonal tabell 16-8 Peker til en tabell og en tabell av pekere Repetisjonsoppgaver Programmeringsoppgaver

489 490 493 497 502 503 505 509 515 520 522

17 STL-vektorer og -algoritmer 17-1 Hva er STL? 17-2 Konteineren vektor 17-3 Iteratorer 17-4 Elevregisteret som et objekt 17-5 Algoritmer 17-6 Vektorer, et gløtt bak kulissene Repetisjonsoppgaver Programmeringsoppgaver

525 526 526 535 538 544 559 567 567

18 Arv og polymorfi

571

Innhold

18-1 Er-forhold og en-del-av-forhold 18-2 Et er-forhold er et arvehierarki 18-3 Å implementere et arvehierarki 18-4 Å bruke objekter av avledede klasser 18-5 Arv av funksjoner med utvidet bruksområde 18-6 Medlemsfunksjoner med spesielle arveegenskaper 18-7 Vektorer og objekter i et arvehierarki 18-8 Syntaksbeskrivelser Repetisjonsoppgaver Programmeringsoppgaver

572 574 578 584 595 597 600 602 607 608

Litteratur

613

Vedlegg V-1 ASCIl-tegnsettet V-2 Operatorer i C++ V-3 Reserverte ord V-4 Tallsystemer V-5 Strukturer V-6 Oversikt over standardbibliotekene V-7 Norsk/engelsk ordliste V-8 Programmeringsstandard

615 616 617 619 620 623 625 652 658

Stikkord

669

xi

Innledning C++ er et stort språk. Denne boka dekker alle de grunnleggende delene av språket. Noen detaljer er det imidlertid ønskelig å fortie av pedago­ giske grunner, både fordi det blir alt for mye for en nybegynner å holde orden på, og fordi enkelte av detaljene krever en viss erfaring med pro­ grammering før man er i stand til å bruke dem på en fornuftig måte.

Alle programmene i rammer (merket "Programliste") finner du på bokas nettside. Programmene er kjørt i Microsoft Visual C++ programmerings­ omgivelser samt i Linux. Med unntak av noen fa operativsystemkommandoer følger boka og alle programmene standard C++.

Hvordan boka er bygd opp Boka begynner med å gjennomgå strukturert programmering for deretter å behandle objektorientert programmering.

I ei lærebok i C++ er det naturlig å behandle kontroll strukturene tidlig. Dette gjøres i kapittel 2 (sekvens), 3 (valg) og 5 (løkke). I forbindelse med kontroll strukturene innføres også flytskjema og pseudokode. Funksjonsbegrepet innføres gradvis gjennom tre kapitler (kapitlene 4, 7 og 9). Hvert av kapitlene tar for seg en måte å overføre argumenter på. Det legges vekt på at en funksjon er en byggekloss, og at det ikke er vilkårlig hvordan et program deles opp i mindre deler ved bruk av funksjoner. Studentene oppfordres tidlig til å bruke ferdige biblioteksfunksjoner og å lage sine egne "biblioteker".

Klasser introduseres førte gang i forbindelse med tekststrenger i kapittel 6. I kapittel 10 behandles temaet grundig og videreføres i kapittel 14. Endelig behandles arv og polymorfi i kapittel 18. Leserne får på denne måten en grunnleggende innføring i alle viktige sider ved objektorientert programmering.

1

Innledning

Bruk av datafiler forutsetter en viss kjennskap til klasser og tas derfor så seint som i kapittel 11. Tekstfiler og feilbehandling i forbindelse med filer gjennomgås relativt grundig.

Nybegynnere har ofte problemer med begrepene kompilering og lenking. Etter å ha gjennomgått dette i kapittel 1 tar vi det opp igjen i kapittel 12. Der lærer studentene også å lage sine egne "header"-filer og sette sam­ men flere filer til ett program. Muligheten til å utvide bruksområdet for operatorer ("operator overloading") er en viktig egenskap ved C++. Dette temaet behandles i kapittel 15.

Selv om behovet for å beherske pekere har avtatt ved innføringen av nye språkelementer, kan vi ikke greie oss helt uten dette når vi i slutten av boka gir en introduksjon til mer avanserte temaer som STL-vektorer og algoritmer. Kapittel 16 er derfor viet temaet pekere.

Oppgaver Boka inneholder tre typer oppgaver: 1

De fleste underkapitlene etterfølges av små oppgaver. Noen krever at studenten gjør seg kjent med det som er spesielt for den kompilatoren som vedkommende bruker, andre at små programmer skal skrives, eller at noen av programmene i boka skal forandres. På bokas nett­ side fins det løsning på de fleste av disse oppgavene.

2

Hvert kapittel avsluttes med ei rekke repetisjonsoppgaver. Dette er hovedsaklig teorispørsmål som studenten kan finne svaret på ved å bla tilbake og lese deler av kapitlet på nytt.

3

Programmeringsoppgavene helt til slutt i hvert kapittel er de viktigste oppgavene i boka. Nettsida inneholder løsning til de oppgavene som er merket med *.

Skrivemåte i denne boka Vi har brukt forskjellige skrifttyper for å vise enkelte ting i denne boka:

2

Innledning

Programkode skrives med Courier New. Se f.eks. programmet på side 9. Under programkoden fins et avsnitt som heter Kjøring av programmet. Her vises skjermbildet. Det brukeren skal skrive, er trykt i kursiv. I vanlige tekstavsnitt er navn fra programmer skrevet med fete typer. I definisjoner, programbiter m.m. fins ofte tekst skrevet på denne måten. Det betyr at her kan det stå flere forskjellige ting. Det som står der, er en beskrivelse av det som skal stå der.

Noen steder er både tekst og programmer skrevet med veldig små bokstaver. Dette er muligheter som nybegynnere bør unngå å bruke på grunn av at det gir programmer som har lett for å bli feil og/eller er vanskelige å lese. Det er likevel tatt med fordi studenten kan måtte lese programmer der disse tingene er brukt. Enkelte programlinjer avsluttes med tekst skrevet på denne måten. Dette er kommentarer av pedagogisk art som ikke må forveksles med vanlige kommentarer som hører til programmet (slike som begynner med //).

3

1 Datamaskiner og programmer Dette kapitlet gir deg det nødvendige grunnlaget for å begynne å pro­ grammere. Det forteller hva en datamaskin er, og hva et program er. Vi forklarer hvordan du får programmet inn i maskinen, og hvordan du får maskinen til å utføre det. To eksempelprogrammer er vist og forklart, slik at du kan lage et lite program på egen hånd etterpå. Til slutt er det tatt med litt om hvordan programmer kan brukes til å løse ulike oppgaver. For å sette de programmene du skal lage, inn i en større sammenheng, har vi tatt med en beskrivelse av livsløpet til kommersielle programmer.

Begreper du lærer å kjenne i dette kapitlet sentralenhet, minne, primærlager og sekundærlager celleadresse, datacelle, bit, byte, binær, digital inn-enhet, ut-enhet og ytre enhet maskinvare, programvare, program og operativsystem data, informasjon, fil og katalog maskinspråk, assembler og høynivåspråk redigeringsprogram (editor) og kildekode kildefil og objektfil å kompilere, lenke, laste og kjøre syntaksfeil, logiske feil og feilsøkeprogram (debugger) preprosessorkommando ledetekst og kommentar definisjon, variabel og konstant aktiv setning, tilordningssetning og lese- og skrive-setning hovedprogram main, int, double, cin, cout, endl, const, if, return "header"-fil flytskjema, algoritme og abstraksjon kontrollstruktur, sekvens, løkke og valg kravspesifikasjon, inkrementell og iterativ utvikling

5

1-1 Datamaskiner, programmer og programmering

1-1 Datamaskiner, programmer og pro­ grammering Denne boka er ei lærebok i programmering ved hjelp av C++. Det betyr at du lærer prinsippene for hvordan programmer lages, og hvordan de formuleres ved hjelp av C++. Vi har valgt å bruke C++ fordi det er et svært utbredt språk og støtter opp om en ryddig organisering av pro­ grammene.

For å lære å programmere, må du praktisere det du har lest. Det betyr at du trenger tilgang til en datamaskin, en C++-kompilator og ei håndbok (eventuelt Hjelp-system på datamaskinen) for denne kompilatoren. I tillegg må du også vite litt om det operativsystemet maskinen har, og helst ha tilgang til ei håndbok for det. (Ordene kompilator og operativsystem er forklart seinere i dette kapitlet.) Emnene vi tar opp, er felles for alle C++-kompilatorer og operativsyste­ mer, det som er spesielt for hvert enkelt, må du lese om i håndbøkene. Mange av temaene er også felles for alle programmeringsspråk; tanke­ gangen bak det å programmere er nokså lik i de fleste programmerings­ språk. Det betyr at når du har lært å programmere i C++, skulle det ikke by på vesentlige problemer å lære et annet språk etterpå.

Datamaskinens oppbygning Alle datamaskiner har en sentralenhet, lagerplass og en eller flere enheter for å kommunisere med omverdenen (mennesker, andre datamaskiner og/eller andre tekniske innretninger). sentralenhet

Sentralenheten (CPU - Central Processing Unit) er selve "hjernen" i maskinen. Den kalles gjeme prosessoren, og styrer det meste av det som skjer i maskinen. Sentralenheten består av styreenheten og aritmetisk/logisk enhet. Styreenheten passer på hvilke instruksjoner (komman­ doer) som skal utføres, mens aritmetisk/logisk enhet utfører dem.

Maskinen har alltid bruk for å lagre data av mange slag til seinere bruk. Det kan være instruksjoner, tall, ord, bilder eller lyd. Data som skal bru­ kes snart, lagres i primærlageret, mens sekundærlageret brukes til å stue unna data som ikke skal brukes på ei stund. Data som ligger i primær­ lageret, vil forsvinne når vi slår av strømmen, mens data i sekundærlage­ ret ikke er avhengig av strøm.

6

1 Datamaskiner og programmer

primærlager minne

Primærlageret (kalles også minnet, hukommelsen eller RAM - Random Access Memory) er nært knyttet til sentralenheten. For å kunne utføre en instruksjon, må den ligge lagret i primærlageret hvor sentralenheten henter den. Det samme gjelder de data som sentralenheten skal jobbe med. Skal f.eks. to tall adderes, finner styreenheten tallene i primær­ lageret og lager en kopi av dem, som den overlater til aritmetisk/logisk enhet. Aritmetisk/logisk enhet adderer dem, og styreenheten plasserer svaret i primærlageret. Data i sekundærlageret må kopieres inn til primærlageret før de kan brukes.

datacelle celleadresse

Primærlageret kan betraktes som ei lang remse med celler der hver celle kan inneholde ett tall, en bokstav eller en instruksjon. Cellene har adres­ ser (dvs. er nummerert), slik at sentralenheten kan angi nøyaktig hvilken celle den skal ha tak i. Når vi programmerer, setter vi navn på noen av disse cellene, slik at vi slipper å huske adressene. Navnet tall 1 kan f.eks. bety adresse 23. Vi bruker disse navngitte cellene til å lagre data for programmet vårt, og benytter begrepet datacelle om dem.

binær digital

Hver celle består av mange små elektroniske komponenter som vi kan se på som brytere som enten kan være av eller på. "Av" representerer 0, "på" gir 1. På denne måten kan vi lage mange forskjellige kombina­ sjoner av nuller og enere, og hver kombinasjon betyr ett bestemt tall, bokstav eller liknende. Dette kalles binær eller digital representasjon av data.

bit byte

En av/på-komponent kalles en bit, 8 biter blir en byte. De cellene vi lagrer informasjon i, består av en eller flere byte, avhengig av maskin­ type og hva vi skal lagre. Et mål for datamaskinstørrelse er hvor mange byte primærlageret inneholder. Vanlig antall for personlige datamaski­ ner i dag (2003) er noen millioner byte (KB = kilobyte = tusen byte, MB = megabyte = million byte, GB = gigabyte = milliard byte).

inn-enhet ut-enhet

All informasjon i datamaskinen lagres og behandles på binær form. Det er bare i kommunikasjonen med mennesker at bokstaver og bilder egner seg bedre. Kontakten mellom mennesket og maskinen skjer ved hjelp av inn-enheter og ut-enheter. Eksempler på slike enheter er tastatur, mus, skjerm og skriver. De to første er inn-enheter (vi sender data inn til maskinen), de to siste er ut-enheter (maskinen sender data ut til oss).

sekundærlager

Noen enheter kan være både inn-enheter og ut-enheter. Eksempler her er harddisk, CD og diskett. De utgjør til sammen sekundærlageret

ytre enhet

Inn-enheter, ut-enheter og sekundærlageret kalles med en fellesbeteg­ nelse for ytre enheter. Å bruke de ytre enhetene er mye mer tidkrevende 7

1-1 Datamaskiner, programmer og programmering

for maskinen enn å bruke primærlageret, siden det ofte innebærer meka­ niske operasjoner, ikke bare elektroniske På figur 1-1 har vi vist noen vanlige komponenter i en datamaskin.

seknxtealager

Figur 1-1: Datamaskinens komponenter

Programmer maskinvare programvare

Komponentene vi har beskrevet hittil, utgjør den fysiske maskinen, det som kalles maskinvaren. I tillegg må vi kunne gi maskinen beskjed om hva den skal gjøre. Det gjør vi ved hjelp av programvaren.

program

Et program er en samling instruksjoner til datamaskinen, som forteller hvordan den skal løse en bestemt oppgave. Samlingen av alle program­ mer som fins i en maskin, utgjør maskinens programvare.

operativsystem Datamaskinens viktigste program er operativsystemet. Det er det programmet som administrerer datamaskinen, slik at andre programmer kan utføres. Operativsystemet holder bl.a. styr på hvor ting er lagret, og henter inn det vi ber om. Det styrer bruken av de ytre enhetene, og det tolker de kommandoene vi sender til maskinen. Eksempler på kjente ope­ rativsystemer er Windows, Linux og UNIX.

Andre eksempler på programmer: -

8

Tekstbehandler: Program som brukes for å skrive og redigere brev og andre dokumenter.

1 Datamaskiner og programmer

-

Regneark: Program som lager tabeller, utregninger og grafiske presentasjoner av tallmateriale.

Her er et eksempel på et lite program som er skrevet i C++: //--------------------------------------------------------

// // adder.cpp // // Program for å addere to heltall // #include using namespace std; int main() { int talll; int tall2; int sum; cout > tall2; sum = talll + tall2; cout > valg;

(" « trekant grunnlinje » hoyde; areal = grunnlinje * hoyde * 0.5; } // trekantberegning else { // sirkelberegning double radius; cout « "Skriv radius : "; cin >> radius; areal = pi * radius ★ radius; } // sirkelberegning

? "

";

cout « "Arealet blir " « areal; return 0; } // main

Kjøring av programmet Eksempel 1 Trekant eller sirkel (T/S)? T Skriv grunnlinje og høyde: 2 3 Arealet blir 3

Eksempel 2 Trekant eller sirkel Skriv radius: 2 Arealet blir 12.5664

(T/S)? S

69

3-2 Blokker og rekkevidden til navn

Oppgaver 1

Hvorfor har vi i programliste 3-1 skrevet cout

blokk

Enten utføres setningerl eller setninger?. Gruppene av setninger omsluttes av { }. Vi kaller ei slik gruppe med setninger for ei blokk. Også setning­ ene i main( ) er omsluttet av { } og utgjør dermed ei blokk. Vi har blok­ ker inni hverandre, og sier at blokkene er "nøstet". Ei blokk kan plasseres overalt der en setning kan plasseres. Vi kan si at ei blokk er en setning, if-konstruksjonen foran kan derfor skrives: if

(valg == trekant)

setning 1 else

setning? der setningl og setning? er blokker.

70

3 Vaig som kontrollstruktur

Merk Legg merke til hvordan vi plasserer { }, og hvordan vi bruker innrykk i programmet. Måten vi gjør dette på, er med på å gjøre et program lettere å lese, kompilatoren ignorerer uansett innrykkene.

{ plasseres på egen linje når den innleder hovedprogrammet (ytterste blokk). Ellers plasseres den bakerst på linja. Etterfølgende setninger ryk­ kes inn to posisjoner. Dette innrykket holdes inntil } påtreffes. } plasseres på egen linje. Dersom } avslutter hovedprogrammet, rykker vi ut når vi skriver }, ellers er det første setning etter } som rykkes ut. Flere blokker inni hverandre vil føre til at vi får mange innrykk før vi begynner å rykke ut igjen.

At klammeparentesen som avslutter ei blokk får stå på egen linje, gjør at vi får inn luft i programmet på en naturlig plass. Klammeparentesen som starter ei blokk, står imidlertid på samme linje som f.eks. den if-setningen som er årsaken til blokka. Det er ikke naturlig med mye luft her, if-set­ ningen og blokka hører sammen.

int main( ) { const char trekant - T; const char sirkel = 'S'; const double pi - 3.141592;

char valg:

rekkevidden til grunnlinje og hoyde

double areal; if (valg == trekant) { double grunnlinje; double hoyde;

rekkevidden til trekant, sirkel, pi, areal og valg

} // trekantberegning rekkevidden til

else {// sirkelberegning double radius;

radius

} // sirkel-beregning

} // main

Figur 3-2: Rekkevidden til navn definert i arealprogrammet

71

3-2 Blokker og rekkevidden til navn

rekkevidde

Med rekkevidden til et navn menes setninger der en kan referere til nav­ net. Rekkevidden til et navn er blokka der navnet er definert, og alle blokkene inni denne. Rekkevidden til navnene i programliste 3-1 er vist på figur 3-2. Vi definerer variablene i den blokka der de brukes, ikke utenfor, grunnlinje, hoyde og radius trengs ikke i ytre blokk, det gjør derimot areal. Konstanter kan vi imidlertid velge å definere relativt langt "ute", selv om de bare brukes i ei indre blokk.

Konstanter er ofte karakteristiske for det problemet som vi skal løse, f.eks. moms eller antallStudenter. Det må være enkelt å finne verdiene, slik at de eventuelt kan forandres. Konstanter av denne typen bør plasse­ res først i hovedprogrammet. Plassering av konstanter vil alltid være en vurderingssak. Er du i tvil, plasser dem øverst i hovedprogrammet. å redefinere navn

Det er mulig å redefinere et navn. Eksempel: {

BLOKK 1

int talll; int ta!12;

setning 1 setning2 i f et eller annet int talll; int tall3;

tilgjengelig i setning 1, 2, 5 og 6 tilgjengelig i alle setningene

{BLOKK 2 tilgjengelig i setning 3 og 4, navnet talH er redefinert tilgjengelig i setning 3 og 4

setning3 setning4 }

slutt på BLOKK 2

setning5 setning6 }

slutt på BLOKK 1

Blokk 1 består av definisjonene talll og taI12, samt setningl, setning2, blokk 2, setningS og setning6. Blokk 2 består av definisjonene talll og tal!3, samt setning3 og setning4. Det vil si at navnet talll får en ny betyd­ ning inni blokk 2.

Blokk 1 definerer to dataceller. Blokk 2 definerer også to dataceller. Datacella med navn talll i blokk 2 er ikke den samme som datacella med navn talll i blokk 1.

Idet programkontrollen går ut av blokk 2, vil datacellene definert i blokk 2 ikke lenger være tilgjengelige. Navnet talll får tilbake den betydningen det hadde før vi gikk inn i blokk 2. Generelt vil vi advare mot å redefinere navn. Anta at vi ved et uhell hadde definert areal også inni blokka som beregner arealet til en trekant:

72

3 Valg som kontrollstruktur

double areal; if (valg == trekant) { double grunnlinje; double hoyde; cout > side; areal = side * side; } // kvadratberegning

";

else { // enten rektangel eller trekant double grunnlinje; double hoyde; cout « "Grunnlinje og høyde: "; cin » grunnlinje » hoyde; if (valg == trekant) areal = grunnlinje * hoyde * 0.5; else areal = grunnlinje * hoyde; } // enten rektangel eller trekant cout « "Arealet blir " = grenseE && poeng < grenseD) ....

Denne siste måten å gjøre det på krever ingen bestemt rekkefølge av ifsetningene. Testene er imidlertid unødvendig kompliserte, og det er lett å gjøre feil. Vi anbefaler derfor at du bruker enkle tester der det er mulig (det vil si når beslutningstabellen er kontinuerlig). Dersom det er "hull" i tabellen, vil det være nødvendig med sammensatte tester for å dekke de aktuelle tilfellene.

Programliste 3-3: En beslutningstabell

// beslutn.cpp // Programmet leser inn en poengsum og skriver ut en karakter. // Sammenhengen mellom poengsummen og karakteren er gitt ved // en beslutningstabell. // #include using namespace std; int main() { // Maksimalt antall poeng. const int maks = 100; // Poenggrense for karakteren A const int grenseA = 85; // Poenggrense for karakteren B const int grenseE = 73; // Poenggrense for karakteren C const int grenseC = 59; // Poenggrense for karakteren D, const int grenseD = 45; // Poenggrense for karakteren E, const int grenseE = 33; // færre enn 33 poeng medfører stryk // Nedre grense for antall poeng. const int min = 0;

int poeng; cout > poeng;

89

Repetisjonsoppgaver

if

(poeng > maks) { cout = grenseB) cout « "Karakteren blir B"; else if (poeng >= grenseC) cout « "Karakteren blir C"; else if (poeng >= grenseD) cout = grenseE) cout « "Karakteren blir E"; else if (poeng >= min) cout talll >> regneart » tall2;

int svar = beregnSvar(talll,

tall2,

ordl >> ord2; if (ordl == ord2) cout > laanebeloep; cout > rentefot; cout > terminbeloep;

skrivOverskrift("

Rente

Avdrag

Nytt lån");

while (laanebeloep >0.0) { double rente = beregnRente(laanebeloep, rentefot); double avdrag = beregnAvdrag(terminbeloep, rente); laanebeloep = beregnNyttLaan(laanebeloep, avdrag); skrivFlyttall(rente, presisjon, vidde); skrivFlyttall(avdrag, presisjon, vidde); skrivFlyttall (laanebeloep, presisjon, vidde);

209

7-1 Verdioverføring

cout = tallC) byttVerdi(tallA, tallC); (tallB >= tallC) byttVerdi(tallB, tallC);

cout tallB) { byttVerdi(tallA, tallB); } cout 6. Venstresiden av > regnes ut, og sammenliknes med 6 (+ har høyere prioritet enn >).

= 8 er sant.

==

Er lik. Eksempel: talll = = taII2 sjekker om tallene er like.

!=

Ikke lik. Gir alltid motsatt resultat av = =.

Advarsel Pass på skillet mellom = = og tilordningsoperatoren. talll = ta!12 betyr at talll skal få samme verdi som talI2, mens talll = = tal!2 betyr at vi sjek­ ker om de har samme verdi. (Se også side 80.) = = og ’= har lavere prioritet enn de andre sammenlikningsoperatorene.

Eksempler på tolkning av uttrykk

Eksempel 1: Uttrykket 0 > x; int teller; for (teller = testomraade; teller >= -testomraade; teller--) { if (beregnPotens(x, teller, svar)) { cout > fravaer[elevNr]; }

{

I første runde i løkka får fravaer nr. 0 en verdi, i neste runde fravaer nr. 1 osv. til siste runde, der fravaer nr. 26 far en verdi. 274

9 Tabeller

Eksempel 2

Du ønsker å vite hva pengene dine går til, og deler opp utgiftspostene i flere kategorier, f.eks. mat, klær, reiser, fornøyelser, skolemateriell osv. Du ønsker å få regnet ut sum utgift for hver kategori. Denne oppgaven kan løses ved at vi har en variabel for hver kategori. For hver utgift må vi angi hvilken kategori den tilhører, og utgiften adderes inn i den tilsva­ rende kategorivariabelen. Hvis antall kategorier er få, er det mulig å løse oppgaven med ifsetninger av typen if (kategori == 1) suml += utgift; else if (kategori == 2) sum2 += utgift; OSV.

Men det blir fort mange if-setninger hvis vi lager en del kategorier. Det er også lite fleksibelt, for hvis vi seinere bestemmer oss for å legge inn en ny kategori, må vi legge inn en ny if.

Vi kan lage følgende tabell: const int antallKategorier = 10; double sum[antallKategorier];

Da får vi satt av plass til 10 flyttall, som alle heter sum, nummerert fra 0 til 9.

Nå kan alle if-setningene slås sammen til en setning: sum[kategori]

+= utgift;

Hvis vi f.eks. angir at vi har hatt en utgift på 300 kroner i kategori 3, så vil sum nr. 3 få økt sin verdi med 300.

Oppgaver 1

a)

Lag en tabell som skal ha plass til å lagre antall dager i hver må­ ned.

b) Lag ei løkke der du leser inn antallet dager i månedene, og plas­ serer verdiene i tabellen. 2

I hvilke av følgende tilfeller trenger du en tabell? a) Du skal finne det største av ei rekke innleste tall. 275

9-2 Å definere og bruke en tabell

b) Ei rekke tall skal leses inn og skrives ut igjen i motsatt rekke­ følge.

c)

Ei rekke tall skal leses inn og deles med det største av dem.

d) Du skal finne gjennomsnittet av ei rekke innleste tall. e) Ei rekke tall skal leses inn, og du skal finne det tallet som er nær­ mest gjennomsnittsverdien av tallene.

9-2 Å definere og bruke en tabell tabellengde

Lengden på en tabell er antall elementer det er satt av plass til. Lengden angis inni hakeparentesen når vi definerer tabellen.

indeks

Det nummeret et element har i tabellen, kaller vi tabellelementets indeks. En indeks må være et heltall (dvs. en eller annen heltallstype). Indeksen er et tall i området fra og med 0, og til, men ikke med, tabellengden. Ved å angi variabelnavnet samt en indeks omsluttet av en hakeparentes, får vi tak i et element i tabellen. Dette tilsvarer det vi gjør når vi skal ha tak i et tegn i en tekststreng. tabell x indeks

0

1

2

3

4

5

6

7

8

9

verdi

500

0

1000

300

0

0

0

0

0

0

x[0]

x[1]

x[2]

x[3]

x[4]

x[5]

x[6]

x[7]

x[8]

x[9]

Figur 9-1: En tabell med 10 elementer

Figur 9-1 viser en tabell som har navnet x. Elementet med indeks 0 har verdien 500, dette er variabelen x[0|. Vi kan forandre et av tabellelementene ved å skrive f.eks. x [4] = 200;

og finne fram til en verdi ved å skrive enVerdi = x[2] ;

Vi kan også kopiere verdien av et element til et annet: 276

9 Tabeller

x [6] = x[5] ;

Generelt har vi at et tabellelement kan behandles nøyaktig som en hvil­ ken som helst annen variabel av samme type som tabellelementet.

Dette gjelder også ved funksjonskall: tall = sqrt((double)x[0]);

beregner kvadratrota av den verdien som står i element nr. 0.

Å definere en tabell Syntaks:

type tabell [tabellengde]; type kan være en hvilken som helst datatype. Tabellengden må være et heltall. Dette heltallet må være en konstant, og verdien av konstanten må være kjent under kompileringen.

Tolkning.

Det blir satt av plass til så mange dataceller (elementer) av den angitte typen som tabellengden angir. Elementene nummereres fra 0 til tabellengde - 1.

Eksempel:

// Lager en tabell som skal inneholde // 20 flyttall, nummerert fra 0 til 19 const int antall = 20; double tall[antall];

Stil:

Vi bruker navngitte konstanter som tabellengde. Vi bru­ ker ikke mellomrom mellom hakeparentesene og tabellnavnet eller tabellengden.

I de foregående eksemplene har vi latt indeksen være konstanter, men vanligvis vil det være variabler: x[teller]

= etTall;

Indeksen er innholdet i datacella teller.

Pass på hvor du setter hakeparentesen:

277

9-2 Å definere og bruke en tabell

tall[teller + 1]

betyr at vi skal regne ut verdien av teller + 1, den verdien vi da får, bru­ kes som indeks i tabellen. tall[teller]

+ 1

betyr at vi skal finne verdien av tabellelement nr. teller. Denne verdien pluss 1 brukes som verdien til uttrykket. På samme måte: tall[teller++] betyr at det er indeksen som skal økes (etter at verdien er brukt til å beregne hvilket element vi skal ha), mens tall [teller]++ betyr at det er elementets verdi som skal økes.

A finne og sette tabellverdier Syntaks:

tabell [indeks] = uttrykk; variabel = tabell [indeks] ;

Tolkning:

Indeksen må være et heltall som er større eller lik 0 og mindre enn tabellengden. I første setning får element nr. indeks samme verdi som uttrykket har, i andre setning får variabelen samme verdi som tabellelement nr. indeks har.

Eksempel:

tall[4] = 23; etTall = tall [i]; tall[i] = tall [i - 1];

Stil:

Vi bruker ikke mellomrom mellom hakeparentesene og tabellnavnet eller indeksen.

Eksempler Utgiftseksempletfra side 274 Programmet vist i programliste 9-1, nullstiller først alle summene. Det gjøres ved å gå i løkke, og la telleren gjennomløpe alle de verdiene som kategori kan få. For hver verdi blir den tilsvarende sum-variabelen satt lik 0. Når teller f.eks. har verdien 4, vil elementet med indeks 4 i sum (det vil si sum|4] ) bli 0.

278

9 Tabeller

(Her ser vi samtidig en god grunn til at vi vanligvis lar telleren i ei for­ lokke starte på 0, ikke 1. En vanlig årsak til å bruke ei for-løkke er at vi skal behandle en tabell. Da blir det lettest hvis telleren starter på samme verdi som nummereringen i tabellen.)

Programmet går deretter inn i ei ny løkke. For hver runde leser det en kategori og en utgift, og det tilsvarende tabellelementet blir oppdatert. Til slutt skriver den siste løkka de oppnådde verdiene i hver kategori.

Dette er to typiske måter å bruke en tabell på. Enten går vi gjennom hele tabellen og gjør noe med alle elementene, og lar telleren representere indeksen. Eller så gjør vi noe med et spesielt element i tabellen. Da har vi en egen variabel som forteller hvilket tabellelement vi ønsker å behandle. Å summere alle elementene i en tabell

En vanlig oppgave i forbindelse med tabeller, er å summere alle elemen­ tene. Det gjøres med ei løkke som går gjennom tabellen. I utgiftseksemplet kan vi finne de totale utgiftene ved å legge inn ei slik løkke på slutten av programmet: double totalSum = 0.0; for (teller = 0; teller < antallKategorier; teller++) totalSum += sum[teller]; } cout « "Total utgift: " « totalSum « endl;

{

Programliste 9-1: Å fordele utgifter på kategorier //----------------------------------------------------------// // utgift.cpp // // Et program som regner ut hvor store utgifter du har i // de ulike kategoriene // #include using namespace std;

const int antallKategorier = 10; int main() { double sum[antallKategorier]; double utgift; int kategori; int teller;

279

9-2 A definere og bruke en tabell

for (teller = 0; teller < antallKategorier; teller++) { sum[teller] = 0.0; } cout etFravaer;

int elevNr = 0; while (etFravaer >= 0 && elevNr < maksAntallElever) { fravaer[elevNr ] = etFravaer; elevNr++; cin » etFravaer; } if (etFravaer >= 0) { cout > tall; while (!innfil.eof ()) sum += tall; innfil >> tall;

{

349

11-1 Enkel bruk av datafiler

eof()

innfil.eof() returnerer logisk sant dersom setningen innfil >> tall;

ikke klarte å lese inn data på grunn av at det ikke er flere data på filen.

Denne programbiten virker også dersom innfil er tom. Instruksjonen inn­ fil » tall foran while utføres, men den klarer ikke å lese inn noen data på grunn av at det ikke er noe å lese. Kallet på eof() registrerer dette, og returnerer logisk sant, med den følge at innholdet i løkka ikke utføres noen gang i dette tilfellet. Metoden kan også anvendes ved lesing av data fra tastaturet. Funksjons­ kallet blir da cin.eof(). Brukeren må angi at det er slutt på dataene ved et spesielt tastetrykk (MS-DOS krever ctrl-z, UNIX krever ctrl-d).

Merk Når først eof() er blitt sann, vil den fortsette å returnere verdien sann inntil filen lukkes. Ingen filoperasjoner blir utført. Dette gjelder også cin og cout. Filobjektets tilstand er dårlig. Funksjonen clear( ) setter tilstan­ den OK igjen: innfil.clear(); cin.clear ();

A prøve å åpne en fil flere ganger Hittil har vi satt filnavnet som en navngitt tekstkonstant. Det er aktuelt å lese inn filnavnet fra brukeren. Dersom programmet får problemer med filåpningen, bør brukeren spørres på nytt. Kanskje han har tastet inn nav­ net feil.

Følgende funksjon spør brukeren om filnavnet. Dersom den ikke klarer å åpne filen, spørres brukeren på nytt et visst antall ganger. Dersom det ikke lykkes, avsluttes programutførelsen med ei melding og et kall på exit(): void aapnelnnfil( int antForsok, ifstream &innfil) {

350

// Inn //Ut

11 Å bruke datafiler

cout ordnr; while (ordnr > 0) { if (ordnr > antallOrd) { cout