L?sningsforslag ukeoppg. 3:  7. - 11. sep (INF1000 - H?st 2009)

Mer om forgreninger (kap. 4.1 - 4.2); l?kker (kap. 4.3 - 4.4), og arrayer (kap. 5.1 - 5.5 og 5.7).
NB! Husk at l?sningene dine ikke trenger ? v?re like med disse for ? v?re riktige.  Det er typisk for programmering at samme oppgave kan l?ses p? mange vidt forskjellige m?ter, og alle disse er ok p? INF1000 s? lenge svaret er riktig.

M?l
?ve p? bruk av forgreninger, l?kker, og arrayer.

Oppgaver til teoritimen

  1. Enkel kalkulator med if-else og switch:
    (a) Lag en enkel kalkulator som st?tter de fire regneartene (+ - * /).  Programmet skal begynne med ? sp?rre hvilken regneart bruker ?nsker ? benytte seg av.  Brukeren svarer da f.eks. * og programmet leser regnearten med .inChar() og lagrer dette i en char-variabel.  Programmet skal s? be om to heltall (disse lagres i hver sin int-variabel).

    Bruk if-else-setninger til ? sjekke hvilken regneart brukeren valgte, og skriv ut resultatet av ? utf?re den valgte regneoperasjonen p? de to tallene, f.eks. slik:
       Regneart: +
    F?rste tall: 3
     Andre tall: 5
    Resultat = 8
    
    Tips: Hvis du vil endre rekkef?lgen slik at bruker kan taste inn et tall, s? regneart, og s? siste tall, sett inn f?lgende kode: tast.skipWhite(); som en egen programsetning rett f?r setningen din med inChar().  Dette er n?dvendig for at inChar skal hoppe over linjeskiftet eller mellomrommet som bruker taster inn f?r regneart-tegnet (fordi inChar ogs? leser inn blanke tegn!).   Regnestykke: 3 + 5 

    (b) Hvordan kan programmet endres for ? bruke en switch-setning i stedet for if-else?  Se eksemplet p? side 78 i l?reboka, og husk ? ta med break;-setningene.
    import easyIO.*;
    
    class Kalkulator { // (a)
        public static void main(String[] args) {      
            Out skjerm = new Out();
            In tast = new In();
    
    	skjerm.out("   Regneart: ");
    	int regneart = tast.inChar();
    
    	skjerm.out("F?rste tall: ");
    	int tall1 = tast.inInt();
    
    	skjerm.out(" Andre tall: ");
    	int tall2 = tast.inInt();
    
    	int svar = 0;
    
    	if (regneart == '+') {
    	    svar = tall1 + tall2;
    
    	} else if (regneart == '-') {
    	    svar = tall1 - tall2;
    
    	} else if (regneart == '*') {
    	    svar = tall1 * tall2;
    
    	} else if (regneart == '/') {
    	    svar = tall1 / tall2;
    	}
    
    
    	skjerm.outln("Resultat = " + svar);
        }
    }
    
    import easyIO.*;
    
    class Kalkulator { // (b)
        public static void main(String[] args) {
            Out skjerm = new Out();
            In tast = new In();
    
    	skjerm.out("   Regneart: ");
    	int regneart = tast.inChar();
    
    	skjerm.out("F?rste tall: ");
    	int tall1 = tast.inInt();
    
    	skjerm.out(" Andre tall: ");
    	int tall2 = tast.inInt();
    
    	int svar = 0;
    
    	switch (regneart) {
    	  case '+':
     	           svar = tall1 + tall2;
    	           break;
    	  case '-':
    	           svar = tall1 - tall2;
    		   break;
    	  case '*':
    	           svar = tall1 * tall2;
    		   break;
    	  case '/':
    	           svar = tall1 / tall2;
    		   break;
    	}
    	skjerm.outln("Resultat = " + svar);
        }
    }
    
    For at kalkulatoren skal takle input som: 3 + 5 er det nok ? endre linje 8-15 til f.eks.:
    	skjerm.out("Regnestykke: ");
    	int tall1 = tast.inInt();
    	tast.skipWhite();
    	int regneart = tast.inChar();
    	int tall2 = tast.inInt();
    

    (c) Tenk gjennom hva skjer ved divisjon (hva slags divisjon f?r vi utf?rt?).  Kan vi endre utregningen for ? f? utf?rt den andre typen divisjon uten ? endre deklarasjonen av de to innleste heltall?
    Programmet over gir heltallsdivisjon. For ? f? vanlig flyttallsdivisjon kan vi deklarere svar som double, og endre siste regnestykke til f.eks. ett av disse:
    	svar = (double) tall1 / tall2;
    	svar = 1.0 * tall1 / tall2;
    


  2. Blokker og skop:
    Hvilke av disse programmene er lovlige?
    class Prog1 {  // Ulovlig
        public static void main(String[] args) {
            int k = 0;
            if (k >= 0) {
                int n = k + 1;
            }
            System.out.println(n);
        }
    }
    
    class Prog2 {  // Ulovlig
        public static void main(String[] args) {
            int k = 0;
            if (k >= 0) {
                int n = k + 1;
            }
            if (k < 0) {
                System.out.println(n);
            }
        }
    }
    
    class Prog3 {  // Ok
        public static void main(String[] args) {
            int k = 0;
            if (k >= 0) {
                k++;
                System.out.println(k);
            }
        }
    }
    


  3. For-l?kke: kap. 4, oppg. 4 (side 83)
    Lag et program som skriver ut p? skjermen omkretsene til sirkler med radiusene r = 1, 2, ..., 10 (omkretsen O beregnes etter formelen O = 2 π r.  Sett π = 3.14).  Utskriften skal f?lge m?nsteret:
    Radius = 1 gir omkrets = 6.28
    Radius = 2 gir omkrets = 12.57
    ..osv..
    
    import easyIO.*;
    
    class Omkrets1 {
        public static void main(String[] args) {
            Out skjerm = new Out();
            double omkrets;
    
            for (int radius = 1; radius <= 10; radius++) {
                omkrets = 2.0 * 3.14 * radius;
                skjerm.out("Radius = " + radius + " gir omkrets = ");
                skjerm.outln(omkrets, 2);
            }
        }
    }
    
    KJ?REEKSEMPEL:
    > java Omkrets
    Radius = 1 gir omkrets = 6.28
    Radius = 2 gir omkrets = 12.57
    Radius = 3 gir omkrets = 18.85
    Radius = 4 gir omkrets = 25.13
    Radius = 5 gir omkrets = 31.42
    Radius = 6 gir omkrets = 37.70
    Radius = 7 gir omkrets = 43.98
    Radius = 8 gir omkrets = 50.27
    Radius = 9 gir omkrets = 56.55
    Radius = 10 gir omkrets = 62.83
    


  4. While-l?kke: (b): kap. 4, oppg. 5 (side 83)
    (a) Gjenta forrige oppgave, men bruk while-l?kke i stedet.
    import easyIO.*;
    class Omkrets2 {
        public static void main(String[] args) {
            Out skjerm = new Out();
            double omkrets;
    
            int radius = 1;
            while (radius <= 10) {
                omkrets = 2.0 * 3.14 * radius;
                skjerm.out("Radius = " + radius + " gir omkrets = ");
                skjerm.outln(omkrets, 2);
    	    radius++;
            }
        }
    }
    

    (b) Som forrige oppgave, men utskriften skal n? f?rst stoppe n?r omkretsen overstiger 1000.  Tips: Bruk while-l?kken til ? kontrollere O.
    import easyIO.*;
    class Omkrets3 {
        public static void main(String[] args) {
            Out skjerm = new Out();
            double omkrets = 0;
    
            int radius = 1;
            while (omkrets <= 1000) {
                omkrets = 2.0 * 3.14 * radius;
                skjerm.out("Radius = " + radius + " gir omkrets = ");
                skjerm.outln(omkrets, 2);
    	    radius++;
            }
        }
    }
    


  5. L?kker: Hva blir skrevet ut?
    Anta at f?lgende programsetninger utf?res. Hva skrives ut p? skjermen?
    class Oppg5_3 {
        public static void main(String[] args) {
    
    //(a)
           int a = 1;
           while (a < 5) {
               a = a + 1;
           }
           System.out.println("a = " + a);
    
    
    a = 5
    
    
    //(b)
           int b = 11;
           while (b < 14) {
               b++;
               System.out.println(b);
           }
    
    
    12
    13
    14
    
    
    //(c)
           int c = 1;
           while (c < 10) {
               c = -2 * c;
           }
           System.out.println("c = " + c);
    
    
    c = 16
    
    
    //(d)
           for (int d = 0; d < 3; d++) {
               System.out.println(d);
           }
    
    
    0
    1
    2
    
    
    //(e)
           for (int e = 1; e <= 3; e++) {
               for (int f = 1; f <= 2; f++) {
                   System.out.println(e + " " + f);
               }
           }
    
    
    1 1
    1 2
    2 1
    2 2
    3 1
    3 2
    
    
    //(f)
           for (int ytre = 0; ytre < 2; ytre++) {
               System.out.print("[");
    
               for (int indre = 0; indre < 3; indre++) {  
                   System.out.print(".");
               }
               System.out.println("]");
           }
    [...]
    [...]
    


  6. En enkel array:
    int[] a = new int[20];
    
    (a) N?r setningen over utf?res, skjer det b?de en deklarasjon og en oppretting av et array-objekt. Forklar hvilken del av setningen som gj?r hva, og vis hvordan setningen kunne v?rt splittet opp i to setninger: en deklarasjonssetning og en setning som oppretter array-objektet.
    int[] a;
    a = new int[20];
    

    (b) Her er eksempler p? bruk av ovennevnte array.  Hva blir skrevet ut p? skjermen?
    int[] a = new int[20];
    a[0] = 100;
    a[1] = a[0] * 2;
    System.out.println(a[1]);
    a[0]++;
    System.out.println(a[0]);
    System.out.println(a.length);
    
    200
    101
    20
    


  7. Finne minste verdi i en array:
    (a) Studér f?lgende program (fra forelesningen uke 4 (PDF), side 15), som finner minste verdi i en array hvor bruker fyller inn 4 verdier; og finn ut hva som blir skrevet ut n?r bruker taster inn tallene 4, 2, 1, 3?  Hva blir skrevet ut hvis bruker taster det minste tallet to ganger, f.eks. 0, 1, 0, 2?
    import easyIO.*;
    
    class MinsteVerdi {
    
        public static void main(String[] args) {
            In tast = new In();
            Out skjerm = new Out();
    
    	double[] verdier = new double[4];
    
            // Leser inn verdier:
    	for (int i = 0; i < verdier.length; i++) {
    	    skjerm.out("Oppgi en verdi: ");
    	    verdier[i] = tast.inDouble();
    	}
    
            // Finner minste verdi:
    	double minste = verdier[0];
    	int indeksMinste = 0;
    	for (int i = 1; i < verdier.length; i++) {
    	    if (verdier[i] < minste) {
    		minste = verdier[i];
    		indeksMinste = i;
    	    }
    	}
    	skjerm.outln("Minste verdi er " + minste);
    	skjerm.outln("Den ligger i indeks " + indeksMinste);
        }
    }
    
    KJ?REEKSEMPEL:
    > java MinsteVerdi
    Oppgi en verdi: 4
    Oppgi en verdi: 2
    Oppgi en verdi: 1
    Oppgi en verdi: 3
    Minste verdi er 1.0
    Den ligger i indeks ?    <- Hva blir skrevet ut her?
    
    > java MinsteVerdi
    Oppgi en verdi: 4
    Oppgi en verdi: 2
    Oppgi en verdi: 1
    Oppgi en verdi: 3
    Minste verdi er 1.0
    Den ligger i indeks 2
    
    > java MinsteVerdi
    Oppgi en verdi: 0
    Oppgi en verdi: 1
    Oppgi en verdi: 0
    Oppgi en verdi: 2
    Minste verdi er 0.0
    Den ligger i indeks 0
    
    (b) Legg til kode som finner og skriver ut gjennomsnittet av verdiene i arrayen.
    	double sum = 0.0;
    	for (int i = 0; i < a.length; i++) {
    	    sum = sum + a[i];
    	}
    	System.out.println("Gjennomsnitt: " + (sum / a.length));
    

    (c) Legg til kode som sjekker om alle verdiene i arrayen er mindre enn 10.0, og gir en passende melding til bruker om det stemte eller ikke.  Hint: Bruk en l?kke og en boolsk variabel "boolean h?yFunnet" som initialiseres til false og settes til true inne i l?kka (under gjennomgangen av verdiene) hvis en verdi ≥ 10 blir funnet.  Se ogs? eksemplet ?verst p? side 90 i l?reboka.
    	boolean h?yFunnet = false;
    	for (int i = 0; i < a.length; i++) {
    	    if (a[i] >= 10.0) {
    		h?yFunnet = true;
    	    }
    	}
    	if (h?yFunnet) {
    	    System.out.println("Ikke alle verdiene er < 10.0");
    	} else {
    	    System.out.println("Alle verdiene er < 10.0");
    	}
    



  8. Flerdimensjonal array:
    To-dimensjonale arrayer brukes p? samme m?te som en-dimensjonale, men har to sett med klammer, og gjennomg?s best vha. to nestede for-l?kker:
    import easyIO.*;
    class Array2D {
       public static void main(String[] args) {
    
            int[][] b = new int[3][4];
    
            for (int i = 0; i < 3; i++) {
                for (int j = 0; j < 4; j++) {
    
                    b[i][j] = i * j;
    
                    System.out.println( <Hva mangler her?> );    
                }
            }
       }
    }
    KJ?REEKSEMPEL:
    > java Array2D     
    b[0][0] = 0
    b[0][1] = 0
    b[0][2] = 0
    b[0][3] = 0
    b[1][0] = 0
    b[1][1] = 1
    b[1][2] = 2
    b[1][3] = 3
    b[2][0] = 0
    b[2][1] = 2
    b[2][2] = 4
    b[2][3] = 6
    Arrayen kan illustreres slik:
       0  1  2  3
     0
     1  X
     2
    (a) Fullf?r println-setningen slik at programmet gir utskriften vist under Kj?reeksempel.
    (b) Hvor mange elementer er det plass til i arrayen b vist over?
    (c) Hva er indeksene til elementet markert med "x" i figuren, og hvilken verdi f?r elementet utdelt i programmet?
    (a) System.out.println("b[" + i + "][" + j + "] = "  + b[i][j]);
    (b) 12 elementer (dvs. 3 x 4)
    (c) b[1][2] == 2
    


Oppgaver til terminaltimen

  1. Enkel kalkulator med if-else og switch:
    (Samme oppgave som i punkt 1. for teoritimen.) Test programmet p? datamaskin og se hvilke feilmeldinger du f?r n?r du pr?ver ? dele et tall p? 0.


  2. Summerings-l?kke: kap. 4, oppg. 6 (side 83)
    (a) Skriv et program som leser et heltall n fra terminal og beregner summen av tallene fra 1 til n.  Utskriften skal f?lge dette m?nsteret (n?r n = 5):
      1    1
      2    3
      3    6
      4   10
      5   15
    
    import easyIO.*;
    
    class Heltallssum {
        public static void main(String[] args) {
    	Out skjerm = new Out();
    	In tast = new In();
    
    	skjerm.out("Angi n: ");
    	int n = tast.inInt();
    
    	int sum = 0;
    	for (int i = 1; i <= n; i++) {
    	    sum = sum + i;
    	    skjerm.out(i, 3);
    	    skjerm.outln(sum, 5);
    	}
        }
    }
    
    KJ?REEKSEMPEL:
    > java Heltallssum
    Angi n: 5
      1    1
      2    3
      3    6
      4   10
      5   15
    

    (b) Det finnes ogs? en formel som gir summen av tallene 1, 2, 3, ...., n direkte: n * (n + 1) / 2.  Utvid programmet slik at det til slutt sammenligner siste sum med resultatet av formelen, og gir en melding til bruker p? om de to svarene var like eller ikke.
    	if (sum == n * (n + 1) / 2) {
    	    System.out.println("Formelen stemmer!");
    	} else {
    	    System.out.println("Formelen stemmer ikke.");
    	}
    


  3. Utskrift av oddetalls-array: kap. 5, oppg. 1 (side 97)
    Skriv et program som inneholder en heltalls-array med f?lgende elementer: 1, 3, 5, 7, 9, 11, 13, 15, 17, 19.  Programmet skal inneholde en l?kke som skriver ut indeksen og verdien for alle elementene i arrayen.
    class Oddetall {
        public static void main(String[] args) {
    	int[] oddetall = { 1, 3, 5, 7, 9, 11, 13, 15, 17, 19 };
    
    	for (int i = 0; i < oddetall.length; i++) {
    	    System.out.println("oddetall[" + i + "] = " + oddetall[i]);
    	}
        }
    }
    


  4. Sum av elementene i en array: kap. 5, oppg. 2 (side 97)
    Vi bruker her samme array som i forrige oppgave: Beregn summen av elementene og skriv ut resultatet.
    	int sum = 0;
    	for (int i = 0; i < oddetall.length; i++) {
    	    sum = sum + oddetall[i];
    	}
    	System.out.println("sum = " + sum);
    


  5. Finne minste verdi i en array:
    (Samme oppgave som i punkt 7. for teoritimen.)


  6. Ekstraoppgave: (vanskelig!, for spesielt interesserte)
    Ta utgangspunkt i programmet fra punkt 7. for teoritimen. Utvid det til ? ta imot 5 verdier fra bruker, og legg til kode som finner ut og skriver hvilke verdier som er gjentatt blant de 5 som bruker tastet inn som input.  F.eks. hvis bruker tastet inn 6, 6, 3, 6, 3 skal programmet gi meldingen: Verdier som er gjentatt: 6 3



  7. Tips til Emacs: (for spesielt interesserte)
    • Undo: For ? angre siste redigering trykk C-_ (dvs. Ctrl-understrek), eller klikk p? ikonet med bilde av en ?b?yd pil? ?verst i Emacs-vinduet.
    • Copy/paste: For ? kopiere tekst fra et hvilket som helst sted p? skjermen til Emacs, start med ? markere teksten vha. musa. Deretter flytter du mus-pekeren til det stedet i Emacs-vinduet der du vil lime inn teksten, og trykker musens midt-knapp (dvs. hjul-tasten) rett ned. Ferdig! Du trenger alts? ikke trykke Ctrl-c eller h?yreklikk > Copy for ? velge teksten p? Linux, det er nok ? markere det.
    • Cut/paste: Hvis du vil klippe bort tekst og flytte det til et annet sted i Emacs-vinduet: markér teksten; trykk Delete-tasten eller C-w for ? klippe det bort; flytt tekst-mark?ren til ?nsket sted; og trykk Insert-tasten eller C-y for ? lime inn.
    • Splittet vindu: For ? kunne se to filer samtidig kan du dele Emacs-vinduet i to ved ? trykke C-x 2 ("C-" st?r for Ctrl-tasten). For ? g? tilbake til ? vise én fil klikk med musa p? ?nsket del av splitt-vinduet og trykk C-x 1.
    • Flere vinduer: For ? ?pne et ekstra-Emacs-vindu slik at du kan se to filer samtidig enda lettere trykk C-x 52. Husk C-x C-f for ? ?pne en fil i det nye vinduet.
    • Innrykk: Du kan la Emacs sette riktig innrykk i hele programmet ved ? trykke C-x h og deretter velge i menyene ?verst: Java > Indent Line or Region.
    • Abbrevs.:
      1. Legg til f?lgende som en linje i din ~/.emacs-fil:
      (abbrev-mode 1)
      2. Opprett en fil kalt ~/.abbrev_defs og legg inn f?lgende 4 linjer som innhold i filen:
      (define-abbrev-table 'java-mode-abbrev-table '(
          ("psv" "public static void main(String[] args) {" nil 0)
          ("sop" "System.out.println(" nil 0)
      ))
      
      Deretter starter du Emacs p? nytt. N?r du skriver psv i et Java-program (etterfulgt av mellomrom eller linjeskift) s? vil det n? bli utvidet til: public static void main(String[] args) {, og tilsvarende for sop. Legg gjerne til flere forkortelser. Fremgangsm?ten for ? opprette filen ~/.abbrev_defs er den samme som den for ? opprette filen ~/.emacs forklart forrige uke.



Kommentarer om dette oppgavesettet kan du sende til josek [at] ifi.uio.no