INF1000 Løkker Marit Nybakken marnybak@ifi.uio.no 10. februar 2004 Motivasjon En ting datamaskinen er veldig flink til er å gjøre den samme tingen mange mange ganger på rad. Oppgaver som skal utføres innebærer ofte, eller kan ofte oversettes til, det å gjøre en ting fryktelig mange ganger, ofte med små variasjoner for hver gang. Å få datamaskinen til å repetere det den driver med kaller vi å gå i løkke. Vi har to måter å få maskinen til å gå i løkke på i Java, for-løkker og while-løkker (disse løkkene er også vanlige i de fleste andre språk). For-løkker For-løkker bruker vi som oftest der vi skal utføre en oppgave et bestemt antall ganger. En for-løkke ser slik ut: for(int i=startverdi; i<sluttverdi; i+=økning) { <setninger som skal utføres> I tillegg til at setningene inni løkka utføres mange ganger, får vi med noe som kalles for en tellevariabel på kjøpet når vi bruker en for-løkke. Denne variabelen heter i løkka over i, men kan selvfølgelig hete hva som helst. 1
For-løkka oppfører seg slik: 1. Sett i lik startverdi 2. Utfør setninger 3. Ëndre i (som oftest øke eller minke) 4. Hvis testen i midten forsatt gir true, gå til steg 2. Hvis ikke, avslutt løkka Den første gangen setningene utføres, settes i lik startverdien. For hver gang løkka går, økes den med økning. Løkka stopper når i har blitt større enn eller lik sluttverdi. Tellevariabelen brukes ofte i setningene som skal utføres inni løkka. Her er et eksempel, en løkke som skriver ut alle partall mellom 0 og 100. for(int i=0;i<101;i+=2) { System.out.println(i); 2
Løkka starter på 0, går helt til i blir større enn eller lik 101 og øker med 2 for hver gang. Dermed skrives 0, 2, 4, 6,... osv ut på skjermen. Her bruker vi altså i både til å bestemme hvor lenge løkka skal gå og i setningene inni løkka. Her er nok en løkke som skriver ut de 50 første versene av Lutefisken lengter hjem til havet. for(int i=1; i<=50; i++) { System.out.println("Lutefisken lengter hjem til havet"); System.out.println("Lutefisken lengter hjem"); System.out.println("Dette var " + i + ". vers, nå kommer " + (i+1) + ". vers, det lyder sånn:"); System.out.println("bom-bom-bom-bom-bom"); Legg merke til at stopp-testen i midten er litt annerledes nå. Den sier at løkken skal gå så lenge i er mindre eller lik 50, i stedet for mindre enn 50. Vi kan faktisk ha hvilket som helst boolsk uttrykk i midten. Denne løkken går baklengs: for(int i=99; i>0; i ) { System.out.println(i + " bottles of beer on the wall, " + i + " bottles of beer. I took one down and passed it around, " + (i 1) + " bottles of beer on the wall."); Det går selvfølgelig an å bruke løkker til noe annet enn å skrive ut ting på skjermen. Denne summerer alle tallene fra 1 til 1000: int sum = 0; for(int i=1;i<=1000;i++) { sum = sum + i; For-løkker passer forøvrig flott til å gå gjennom arrayer (som vi snart skal ha om). Startverdien settes til 0 (første indeks), sluttverdien til arrayens lengde (siste indeks+1), og økningen blir 1. Da vil i kunne brukes som indeks. String [ ] tekster = new String[100];.... for(int i=0; i<=tekster.length; i++) { // bruker i for å si hvilken arrayplass vi skal gjøre noe med 3
System.out.println(tekster[i]); While-løkker While-løkker bruker vi vanligvis når en ting skal utføres et ubestemt antall ganger til en betingelse er oppfylt. En while-løkke ser slik ut: while(<boolsk uttrykk>) { <setninger som skal utføres> Altså, utfør setninger til det boolske uttrykket blir false. For at løkka skal ha noen sjans til å avslutte, må det gjøres endringer inne i løkka slik at det boolske uttrykket blir true når oppgaven er over. Eksempel: boolean ferdig = false; while(!ferdig) { // Utfør en eller annen passende oppgave // Test om vi skal fortsette System.out.print("Forsette? (J/N): "); char svar = tast.inchar(); if(svar == J ) { 10 ferdig = true; Det boolske uttrykket er her bare en boolsk variabel som vi setter til true når brukeren angir at han vil slutte. Nok et eksempel: char svar = X ; 4
while(svar!= J && svar!= N ) { System.out.print("(J/N): "); char svar = tast.inchar(); if(svar!= J svar!= N ) { System.out.println("Feil valg"); 10 Her skal løkken altså gå så lenge bruker ikke klarer å skrive inn enten J eller N. Vi gir også feilmelding for å prøve å stramme ham opp for hver gang han ikke makter denne oppgaven. Do-while-løkker Do-while-løkker oppfører seg nesten likt som while-løkker, men løkketesten utføres etter setningene er utført, ikke før: do { <setninger>; while(boolsk uttrykk); Dette betyr at setningene utføres minst en gang. Dette ønsker vi ofte, f.eks. er det praktisk i dette eksempelet: double sum = 0; double tall; do { System.out.print("Skriv inn et tall (-99 for å avslutte):"); double tall = tast.indouble(); if(tall!= 99) { sum = sum + tall; while(tall!= 99); 10 Det er ikke noe vits i å teste om tallet brukeren taster inn er -99 før setningene 5
utføres, for brukeren har jo ikke fått anledning til å taste inn noe som helst enda. Det passer best å teste etterpå, og derfor bruker vi do-while. Skop En variabels skop (engelsk: scope) er hvilke deler av programmet som kan se variabelen. Variable deklarert i metoder synes bare innenfor denne metoden og alle grener innenfor metoden (foreløpig har vi bare en metode - main). for-løkker synes bare innenfor for-løkken. Dette gjelder også variablene deklarert i løkketesten. while-løkker synes bare innenfor while-løkken. if-tester synes bare innenfor if-grenen. Det samme med else if og else. Variable deklarert mellom to tilhørende start- og slutt-krøllparenteser synes kun innenfor disse. Deklarerer du en variabel inne i en for-løkke, forsvinner den derfor når løkka er ferdig. /* Hvor variabler eksisterer og hvor de ikke eksisterer...*/ class Scope { public static void main(string[ ]args) { { int a = 55; System.out.println("Her fungerer a: " + a); 10 System.out.println("Her finnes ikke a lenger: " + a); mortana: inf101>javac Scope.java Scope.java:12: cannot resolve symbol symbol : variable a 6
location: class Scope 20 System.out.println("Her finnes ikke a lenger: " + a); ^ 1 error mortana: inf101> Veldig kort om arrayer fordi dere skal ha det i obligen Arrayer bruker vi når vi skal lagre veldig mange verdier av samme type. Hvis du er i gang med å deklarere 10 forskjellige variable og kaller dem noe slikt som a1, a2, a3, a4, osv, er dette et sikkert tegn på at du egentlig skulle brukt en array. Deklarasjon Vi deklarerer en array ved å skrive type [] arraynavn; Da får vi en peker til en array som kan inneholde verdier av typen type. Pekeren kan inneholde adressen til starten på arrayen i minnet. Selve arrayen er fremdeles ikke opprettet, og du kan ikke putte noe inn i den. Eksempler: String [] tekster; int [] tall; char [] bokstaver; Oppretting Vi oppretter en array ved å skrive arraynavn = new type[arrayens_lengde]; Vi får nå satt av en lang rekke med plasser i minnet der vi kan legge verdier, omtrent som en lang hylle. Det blir omtrent som å ha variablene a1, a2, a3 osv bortsett fra at de ikke lenger heter akkurat dette. 7
Figur 1: Heltallsarray 8
Eksempler: tekster = new String[100]; tall = new int[10]; bokstaver = new char[antall_bokstaver_i_alfabetet]; Innsetting Etter vi har opprettet arrayen, går bruken ut på å sette inn ting på plasser i arrayen og ta dem ut igjen. Det er da viktig å huske på et faktum: Du kan ikke putte noe inn i en array uten å oppgi indeksen som det skal ligge på. Indeksen sier hvilken hylle verdien skal ligge på. Hyllene er nummerert fra 0 opp til lengden på arrayen - 1. ARRAYNAVN [ INDEKS ] = VERDI ; Og indeksen/hyllenummeret må alltid være et heltall. Her er en rekke eksempler på bruk av løkker og arrayer sammen: /* Bruk av arrayer */ class Arrayer { public static void main(string[ ]args) { int [ ] tall = new int[100]; // Fyller en array med heltall 10 for (int i=0;i<tall.length;i++) { // arraynavn[indeks] = verdi; tall[i] = i; // Skriver ut en array til skjerm for(int i=0;i<tall.length;i++) { System.out.println(tall[i]); // Skriver ut en array baklengs for(int i=tall.length 1;i>=0;i ) { System.out.println(tall[i]); 20 9
// Summerer innholdet av en array int sum = 0; for(int i=0;i<tall.length;i++) { sum+=tall[i]; 30 // Lager en kopi av tabellen int[ ]tall2 = new int[tall.length]; for(int i=0;i<tall.length;i++) { tall2[i] = tall[i]; // eventuelt... int [ ] tall3 = (int[ ]) tall2.clone(); 40 // Søke etter en verdi i en tabell // med feilmelding hvis ikke funnet int søkeverdi = tast.inint(); boolean funnet = false; for(int i=0;i<tall.length &&!funnet;i++) { if(tall[i] == søkeverdi) { funnet = true; System.out.println("Fant en match!"); 50 if(!funnet) System.out.println("Verdien ikke funnet"); 60 10