Løsningsforslag ukeoppg. 4: 14. - 20. sep (INF1000 - Høst 2011) Metoder, flerdimensjonale arrayer (kapittel 7.1-7.7, 5.7 i "Rett på Java" 3. utg.) NB! Legg merke til at disse er løsningsforslag. Løsningene dine trenger ikke å være like med disse forslag for å være riktige. Det er vanlig i programmering at samme oppgave kan løses på mange vidt forskjellige måter, og alle fremgangsmåter er ok i INF1000 så lenge de leder fram til riktig resultat og oppfyller kravene som står i oppgaveteksten. Mål Øve på bruk av forgreninger, løkker, arrayer, og metoder. Oppgave merket med nøkkelsymbol er plukket ut som spesielt representativ for de viktigste temaene fra ukens forelesning, og alle bør ha som minimumsmål å løse denne selvstendig. Oppgaver 1. Enkel kalkulator med if-else og switch: [ NB! Vi bruker en litt spesiell måte å gi input i denne oppgaven, der bruker må taste mellomrom mellom de tre delene av regnestykket (f.eks. "4 + 5"), men du vil lære hvordan programmet kan godta andre skrivemåter neste uke. ] (a) Lag en kalkulator som støtter enkle regnestykker på formen: tall operator tall, hvor de tre elementene er adskilt med mellomrom. Tall er heltall, og operator er en av de fire regneartene: + - * /. Eksempel på kjøring av programmet: Regnestykke: 4 + 5 Resultat: 9 Bruk tast.inint() og tast.inchar(" ") for å lese tall og regneart fra tastaturet (hvis du bruker EasyIO, hvis ikke se "Hint" nedenfor). Mellomrommet i parentesene til inchar angir at den skal betrakte mellomrom som et skilletegn før og etter regnearten. Dette er nødvendig å si fra til inchar, fordi den leser inn ett tegn av gangen. Lagre tallene og operator i passende variabler, og bruk if-else-setninger til å velge hvilken regneart skal utføres. Hint for å løse det uten EasyIO: Bruk scan.nextint() i stedet for tast.inint(), og scan.next().charat(0) i stedet for tast.inchar(" ");. // Løsning på (a) med EasyIO: // Løsning på (a) uten EasyIO: import java.util.scanner; skjerm.out("regnestykke: "); int a = tast.inint(); char op = tast.inchar(" "); int b = tast.inint(); if (op == '+') { else if (op == '-') { else if (op == '*') { else if (op == '/') { skjerm.outln("resultat: " + svar); Scanner tast = new Scanner(System.in); System.out.print("Regnestykke: "); int a = tast.nextint(); char op = tast.next().charat(0); int b = tast.nextint(); if (op == '+') { else if (op == '-') { else if (op == '*') { else if (op == '/') { System.out.println("Resultat: " + svar); (b) Hvordan kan programmet endres for å bruke en switch-setning i stedet for if-else? (Hint: Se eksemplet på side 80 i læreboka, og husk å ta med -setningene.) // Løsning på (b) med EasyIO: // Løsning på (b) uten EasyIO: import java.util.scanner; skjerm.out("regnestykke: "); int a = tast.inint(); Scanner tast = new Scanner(System.in); System.out.print("Regnestykke: "); int a = tast.nextint(); char op = tast.next().charat(0); 1/7
int a = tast.inint(); char op = tast.inchar(" "); int b = tast.inint(); switch (op) { case '+': case '-': case '*': case '/': skjerm.outln("resultat: " + svar); char op = tast.next().charat(0); int b = tast.nextint(); switch (op) { case '+': case '-': case '*': case '/': System.out.println("Resultat: " + svar); (c) Hva slags divisjon får vi utført?, og hvordan kan vi endre programmet 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) a / b; svar = 1.0 * a / b; 2. Løkker: Hva blir skrevet ut? Avgjør uten å bruke datamaskin hva som blir skrevet ut når følgende programsetninger utføres. //(a) //(b) int a = 10; while (a < 20) { a += 4; System.out.println("a = " + a); a = 22 int sum = 0; for (int b = 1; b < 6; b += 2) { sum += b; System.out.println("sum = " + sum); sum = 9 //(c) int produkt = 1; //(d) for (int c = 1; c < 4; c++) { produkt = produkt * c; System.out.println(produkt); for (int d = 3; d >= 1; d--) { for (int e = 1; e <= 3; e++) { System.out.println(d d + e); 1 2 6 4 5 6 3 4 5 2 3 4 //(e) int teller = 0; for (int ytre = 0; ytre < 3; ytre++) { teller++; for (int indre = 0; indre < 3; indre++) { teller++; System.out.println(teller); 12 3. Utskrift og sum av oddetalls-array: kap. 5, oppg. 1-2 (side 99) (a) 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 { int[] oddetall = { 1, 3, 5, 7, 9, 11, 13, 15, 17, 19 ; 2/7
System.out.println("oddetall[" + i + "] = " + oddetall[i]); (b) Sum av elementene i en array: Vi bruker her samme array som i forrige oppgave: Beregn summen av elementene og skriv ut resultatet. int sum = 0; sum = sum + oddetall[i]; System.out.println("sum = " + sum); 4. Søke etter tall i array: (a) Utvid programmet fra forrige oppgave slik at det ber bruker taste inn et tall, og deretter skriver ut en beskjed om det inntastede tallet finnes eller ikke finnes i arrayen. (b) Legg også til en løkke som skriver ut alle verdiene i arrayen som er mindre enn det inntastede tallet. class Uke3_Terminaloppg3 { int[] oddetall = { 1, 3, 5, 7, 9, 11, 13, 15, 17, 19 ; // (a) Finnes tallet? System.out.print("Tast inn et tall: "); int tall = tast.inint(); boolean funnet = false; if (oddetall[i] == tall) { funnet = true; System.out.print("Tallet " + tall); if (funnet) { System.out.println(" finnes i arrayen"); else { System.out.println(" finnes ikke i arrayen"); // (b) Skriv ut verdiene < tall: System.out.print("Verdier i arrayen som er < " + tall + ": "); if (oddetall[i] < tall) { System.out.print(oddetall[i] + " "); System.out.println(); KJØREEKSEMPEL: Tast inn et tall: 5 Tallet 5 finnes i arrayen Verdier i arrayen som er < 5: 1 3 5. Flerdimensjonal array: To-dimensjonale arrayer brukes på samme måte som en-dimensjonale, men har to sett med klammer, og gjennomgås best ved hjelp av to nestede for-løkker, som vist i følgende program: class Array2D { 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?>); Arrayen kan illustreres slik: 0 1 2 3 0 _ 1 _ 2 _ 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 (a) Hvor mange elementer er det plass til i arrayen b vist over? (b) Hva er array-indeksene til array-elementene i tredje kolonne, og hvilke verdier får disse elementene i programmet over? (c) Fullfør println-setningen i programmet ovenfor slik at det gir utskriften vist under "Kjøreeksempel". (a) 12 elementer (dvs. 3 x 4) (b) Tredje kolonne består av array-plassene b[0][2], b[1][2], og b[2][2], og verdiene i disse plassene er henholdsvis: 0, 2, og 4. (c) System.out.println("b[" + i + "][" + j + "] = " + b[i][j]); Her kan du finne første utkastet til denne oppgaven (som var lagt ut 14. sep sammen med beskjed øverst på denne siden 3/7
Her kan du finne første utkastet til denne oppgaven (som var lagt ut 14. sep sammen med beskjed øverst på denne siden om at oppgavesettet ikke var ferdig), og løsningsforslag finner du der også. 6. Blokker og skop: Hvilke av disse programmene er lovlige? class Prog1 { int k = 0; if (k >= 0) { int n = k + 1; System.out.println(n); class Prog2 { int k = 0; if (k >= 0) { int n = k + 1; if (k < 0) { System.out.println(n); class Prog3 { int k = 0; if (k >= 0) { k++; System.out.println(k); Prog1 og Prog2 er ulovlige, mens Prog3 er ok. 7. inline(), inchar(), og ordreløkke: Lag et program som spør bruker etter et navn. Programmet leser navnet inn ved hjelp av inline() (hvis du bruker EasyIO) eller med nextline (hvis du bruker Scanner); og "fyller" så skjermen med navnet ved å skrive det ut 100 ganger. Videre skal programmet spørre bruker om hun vil gi et nytt navn (j/n). Svaret leses nå med.inchar("\n\r") hvis du bruker EasyIO (for tips uten EasyIO se "Hint" nedenfor), og hvis det er 'j' gjentas hele prosessen; hvis svaret ikke er 'j' avsluttes programmet. Kjøreeksempel: Skriv et navn: Ola Nordmann Ola Nordmann Ola Nordmann Ola Nordmann Ola Nordmann Ola Nordmann O la Nordmann Ola Nordmann Ola Nordmann Ola Nordmann Ola Nordmann Ol a Nordmann Ola Nordmann Ola Nordmann Ola Nordmann Ola...osv... Gi nytt navn? (j/n): j Skriv et navn: // Løsning med EasyIO: char svar = 'j'; // Startverdi String navn = tast.inline(); // Løsning uten EasyIO: import java.util.*; Scanner scan = new Scanner(System.in); char svar = 'j'; // Startverdi System.out.print("Skriv et navn: "); String navn = scan.nextline(); System.out.print(navn + " "); System.out.println(); System.out.print("Gi nytt navn? (j/n): "); svar = scan.nextline().charat(0); Hint: Legg merke til det som står i parentesene til.inchar("\n\r") ovenfor (i varianten med EasyIO). Det som man skriver i disse parentesene kalles for "skilletegn" og angir hvilke tegn som ikke skal regnes som svaret (men i stedet regnes bare som skilletegn som adskiller evt. forskjellige svar). I dette tilfellet skal programmet hoppe over evt. linjeskift (\n) eller vognretur (\r) som bruker har tastet inn, og i stedet lese inn en vanlig bokstav fra tastatur, f.eks. 'j'. Det samme kan man også få til uten EasyIO, f.eks. ved hjelp av scan.nextline().charat(0); tips om dette finner du i kommentar #4 i bloggposten EasyIO. 4/7
bloggposten EasyIO. 8. Metoder: (a) Endre strukturen til programmet ditt fra oppgave nr. 7 over slik at det følger den typen programstruktur som vi skal bruke i Oblig 2 (vist i skissen nedenfor), dvs. med en liten kontrollklasse øverst, etterfulgt av en egen klasse for metodene. Hele programmet med begge klassene lagres i én fil, kalt Navn100.java (dvs. navnet til klassen med metoden main()). Lag bare én metode i hjelpeklassen, kalt ordreløkke(), som gjør alt som står i nr. 7 ovenfor. hj.ordreløkke(); // Kjører metoden ordreløkke() i hjelpeklassen // Klargjøring for innlesing/utskrift, gjelder for hele klassen: String navn; char ginyttnavn = 'j'; // Startverdi while (ginyttnavn!= 'n') { // - Be bruker taste et navn og les det inn med.inline(); // - Utskrift av navn 100 ganger. // - Spør om bruker vil "Gi nytt navn? (j/n):", og.inchar("\n\r"): Mer info: Grunnen til at vi skriver programmet på denne måten med to klasser vil bli klarere når vi kommer til kapittel 8, men har sammenheng med at vi ønsker å lage gode "objektorienterte" program der vi jobber med "objekter". I denne skissen er det fem pekere til objekter: args[], hj, tast, skjerm, og navn. hj.ordreløkke(); // Kjører metoden ordreløkke() i hjelpeklassen // Klargjøring for innlesing/utskrift, gjelder for hele klassen: String navn; char svar = 'j'; // Startverdi // - Be bruker taste et navn og les det inn med.inline(); navn = tast.inline(); // - Utskrift av navn 100 ganger. // - Spør om bruker vil "Gi nytt navn? (j/n):", og.inchar("\n\r"): (b) Flere metoder: Endre programmet slik at koden som skriver ut navnet 100 ganger flyttes til en egen metode kalt utskrift(). Husk å legge inn et kall på metoden på det stedet i programmet du flyttet koden fra. hj.ordreløkke(); String navn; char svar = 'j'; // Be bruker taste et navn og les det inn med.inline(): 5/7
// Be bruker taste et navn og les det inn med.inline(): navn = tast.inline(); // Kaller metoden utskrift(): utskrift(); // - Spør om bruker vil "Gi nytt navn? (j/n):" void utskrift() { (c) Inn-parameter: Endre programmet slik at det også spør bruker hvor mange ganger navnet skal skrives ut. Verdien som bruker taster skal overføres som parameter til metoden utskrift() som du lagde i del (b). Endre også metoden utskrift(..) slik at den tar imot argumentet ved hjelp av parameteren int antall, slik: void utskrift(int antall) { hj.ordreløkke(); char svar = 'j'; // Be bruker taste et navn og les det inn med.inline(): String navn = tast.inline(); // Kaller metoden utskrift(): utskrift(navn) (navn); // - Spør om bruker vil "Gi nytt navn? (j/n):" void utskrift(string navn) { 9. Ukens nøtt 1: (vanskelig!) Lag et program som ber om 5 tall fra bruker, og deretter finner og skriver ut hvilke tall som er gjentatt blant disse. F.eks. hvis bruker tastet inn 6 6 3 6 3, så skal programmet gi meldingen: Tall som er gjentatt: 6 3 Send løsningen din til josek [at] ifi.uio.no, så legger jeg den ut i løsningsforslagene! Send løsningen din til josek [at] ifi.uio.no, så legger jeg den ut i løsningsforslagene! Løsningsforslag laget av Vegard Knutsen Lillevoll i gruppe 5 -- En veldig oversiktlig og godt kommentert løsning, som lett kan utvides til flere enn 5 tall (bare ved å bytte forekomstene av "5" til ønsket antall). 10. Ukens nøtt 2: (vanskelig!) Lag en metode som skriver ut alle anagrammer av et ord på 4 bokstaver som ligger i en char-array. Anagrammene skal ha de samme 4 bokstavene, i alle mulige rekkefølger og uten å gjenta noen bokstav. For eksempel, hvis ordet er deklarert som følger, er 4 av anagrammene som vist under, og totalt 24. Send løsningen din til josek [at] ifi.uio.no, så legger jeg den ut i løsningsforslagene! char[] ord = { 'A', 'R', 'N', 'E' ; Kjøreeksempel: ARNE AREN ANRE ANER...20 ord til... Tips: En måte å løse dette på er med nestede løkker som i utgangspunktet kan gå innom alle mulige kombinasjoner, inkludert AAAA, AAAE, osv. men slik at det bare blir utskrift av de med 4 forskjellige bokstaver. Bruk den tomme strengen "" og + i utskriftssetningen for å konvertere char-ene til tekst: System.out.println("" + ord[3] + ord[2]!!! 6/7
11. Tips til Emacs: (for spesielt interesserte) Emacs-forkortelser: Legg til følgende fem linjer i din ~/.emacs-fil: (define-abbrev-table 'java-mode-abbrev-table '( ("psv" "" nil 0) ("sop" "System.out.println" nil 0) )) (abbrev-mode 1) 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:, og tilsvarende for sop etterfulgt av (. Legg gjerne til flere forkortelser. Mer info om filen ~/.emacs kan du finne i Ukeoppgaver 2. 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 ved hjelp av 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 i Emacs, 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 Deletetasten 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. Flere tips til Emacs kan du finne i Emacs-oppgavene fra Forkurs i informatikk Tibakemelding om dette oppgavesettet kan du skrive i bloggen eller sende på mail til josek [a] ifi.uio.no 7/7