Kirjautuminen

Haku

Tehtävät

Opasarkisto: Aloittelijan QBasic-opas: Osa 2 - DEFX, IF...ELSE...END IF, FOR...NEXT ...

  1. Osa 1 - PRINT, CLS, INPUT
  2. Osa 2 - DEFX, IF...ELSE...END IF, FOR...NEXT ...
  3. Osa 3 - SUB, FUNCTION, GOTO/GOSUB ...

Kirjoittaja: thefox

Opetettavat käskyt: DEFINT, DEFSNG, DEFDBL, DEFLNG, DEFSTR, DIM, IF, THEN, ELSE, ELSEIF, END IF, AND, OR, XOR, FOR, NEXT

Jos et ole vielä lukenut ensimmäistä osaa, hae se nyt heti jostain... ;-) Tässä toisessa osassa, kuten ensimmäisessä lupasin, opetettavat asiat ovat:

Ja aloitammekin loogisesti alusta, eli ohjelmien rakenteesta.

Ohjelmien rakenne

Otetaan heti alkuun jotain analysoitavaa, eli viimekertainen "Hello world"-esimerkki.

PRINT "Hello world!"

Kuten näet, ei yksinkertaisimmissa QB-koodipätkissä tarvita ollenkaan alkumäärittelyjä tms. vaan koodia voi alkaa kirjoittamaan heti kun on saanut QB:n avatuksi. Yllä olevan kaltainen esimerkkihän menisi C:llä seuraavasti:

#include <stdio.h>
int main()
{
   printf("Hello world!\n");
   return 0;
}

Mihin QB:llä tarvitsimme yhden rivin, kului C:llä tehdessä kuusi riviä! Tällä QB:n "ominaisuudella" (tai pitäisikö sanoa omituisuudella...) on sekä hyvät että huonot puolensa. Näissä esimerkeissä QB:n ja C:n erot eivät vielä tule helposti esille, ja näyttääkin että QB-koodi on paljon yksinkertaisempaa ja tehokkaampaa. Kuitenkin kirjoitettaessa pidempiä ohjelmia, C on varmasti (ei vastaväitteitä!) tehokkaampi kieli kuin QB, johtuen juuri QB:n käyttäjäystävällisyydestä.

Eräissä tapauksissa QB-koodiinkin joudutaan lisäämän "alkuhilpekkeitä", mm. funktioiden tapauksissa. Ajattelin kuitenkin käydä QB:n rakennetta tarkemmin läpi vasta osassa kolme, joten nyt se saa jäädä väliin. Sitten siirrymekin taas kerran hieman mielenkiintoisempiin aiheisiin.. eli muuttujiin.

Muuttujat

Mikä on muuttuja? Yksinkertaisesti sanottuna, muuttuja on arvo, jota voi muuttaa ;-) Jokaisella muuttujalla on nimi, jolla siihen viitataan. Otetaanpa hieman koodia:

CLS
PRINT "Käytä pilkkua nimien eroittamiseen!"
INPUT "Kirjoita etu- ja sukunimesi: ", Etunimi$, Sukunimi$
PRINT "Terve " + Etunimi$ + "! (Sukua " + Sukunimi$ + ")"

Yllä olevassa esimerkissä muuttujia ovat Etunimi$ ja Sukunimi$. '$' muuttujan perässä ilmoittaa, että kyseessä on merkkijonomuuttuja. Tässä muut muuttujatyypit ja niiden tunnukset:

Datan tyyppiTunnusMaksimiarvoMinimiarvo
Merkkijono (STRING)$32,767 kirjainta (tavua)0 tavua
Kokonaisluku (INTEGER)%32,767-32,768
Pitkä kokonaisluku (LONG)&2,147,483,647-2,147,483,648
7-numeroinen liukuluku (SINGLE)!±3.402823 E+3±1.401298 E-45
15-numeroinen liukuluku (DOUBLE)#±1.7976931 D+308±4.940656 D-324

Jos muuttujan perässä ei ole merkkiä, QB tekee siitä automaattisesti single-liukuluvun. Poikkeuksiakin toki löytyy jopa kaksin kappalein. Jos jossain kohtaa koodia on seuraavan näköinen pätkä...

DEFINT A-Z

...tekeekin QB jokaisesta merkittömästä muuttujasta automaattisesti kokonaisluvun. DEFINT:in paikalle mahdollisia ovat myöskin DEFINT (integer), DEFSNG (single), DEFDBL (double), DEFLNG (long) ja DEFSTR (string). DEFINT A-Z:aa kannattaa käyttää aina kuin mahdollista... eli aina!

Entäs se toinen poikkeus sitten? Poikkeuksen nimi on DIM, ja niin opimmekin uuden käskyn.

DIM [SHARED] variable[(subscripts)] [AS type] [,variable[(subscripts)] [AS type]...

DIM-käskyllä voimme määritellä tietyn muuttujan tiettyyn tyyppiin. Esim:

DIM nimi AS STRING

Nyt nimi on tyyppiä merkkijono, eikä tarvitse käyttää rumaa '$'-merkkiä! Sama homma toimii tietenkin myös muilla tyypeillä, eli "DIM ika AS INTEGER" tekisi 'ika'-muuttujasta kokonaisluku (INTEGER) muuttujan oletusarvo SINGLE:n sijasta. Yhdellä DIM-käskyllä voit kerralla määritellä useita muuttujia:

DIM nimi AS STRING, ika AS INTEGER

Analysoidaanpa nyt DIM:in rakenne alusta loppuun kunnolla. Ensimmäinen parametri, [SHARED], määrittelee onko muuttujamme globaali ("näkyy" kaikille ohjelman funktioille). Jos muuttuja on paikallinen, voi sitä muokata vain funktiossa, jossa se on määritelty. Esimerkkiä tulossa:

DIM nimi AS STRING
Muuta
PRINT nimi

' "Muuta"-aliohjelma
SUB Muuta
   nimi = "foo"
END SUB

Jos ylläolevaa esimerkkiä yrittää ajaa, näyttää se virhettä 'Muuta'-funktion rivillä kaksi: "Type mismatch". Tämä johtuu siitä, että pääohjelman 'nimi'-muuttuja ei ole SHARED-tyyppiä, joten se ei näy 'Muuta'-funktiolle. Aliohjelmassa QB tekee kokonaan uuden muuttujan, nimeltään 'nimi', joka on tyyppiä SINGLE. Ja SINGLE-tyypillehän merkkijono ei kelpaa. Muuttamalla ensimmäisen rivin "DIM nimi AS STRING" => "DIM SHARED nimi AS STRING" toimisi esimerkki. Tälloin muuttuja on globaali ja näkyvissä jokaiselle funktiolle.

Muistathan ohjelmoidessasi että globaalien muuttujien käyttö kuvastaa yleensä huonoja ohjelmointitapoja, niinpä globaaleja muuttujia tulisi välttää parhaimpansa mukaan, esim. ylläolevaa esimerkkiä ei missään nimessä olisi pitänyt tehdä globaalin muuttujan avulla.

Seuraava parametrimme on variable[(subscripts)]. "variable" on juuri muuttujan nimi, mutta osa joka meitä kiinnostaa onkin ei-pakollinen [(subscripts)]. Se määrittelee montako "solua" muuttujalla on.

DIM nimi(10) AS STRING
nimi(5) = "fawkz"

Oletuksena muuttujalla, jos sitä ei DIM:ata, on 11-solua (0-10). Ylläolevassa esimerkissämekin määritellään 'nimi'-muuttujalle 11 solua, joihin jokaiseen voimme sijoittaa merkkijonon. Toisella rivillä onkin esimerkki merkkijonon sijoittamisesta. DIM:issä voi myös käyttää TO-rakennetta jos haluaa vaikka solut välille 5-10.

DIM nimi(5 TO 10) AS STRING
nimi(5) = "fawkz"
nimi(4) = "foo"

Ylläolevan ohjelmapätkän kolmas rivi tuottaa virheen "Subscript out of range", koska muuttujassa on vain solut 5-10. Mutta ei tässä vielä kaikki, nimittäin muuttujat voivat olla myös moniulotteisia.

DIM nimi(1 to 10, 1 to 5) AS STRING
nimi(1, 1) = "fawkz"
nimi(2, 5) = "foo"

Ja näin meillä on kaksiuloitteinen muuttuja, ensimmäisessä "kerroksessa" arvot voivat olla väliltä 1-10, toisessa kerroksessa väliltä 1-5. Kätevää eikö? Ulottuvuuksia voi tietysti olla enemmänkin, käyttötarpeiden mukaan. Ja siinäpä olikin melkein kaikki mitä sinun tulee DIM-käskystä tietää, joten siirtykäämme eteenpäin.

Ehtolauseet

Ehtolauseet ovat yksi ohjelmoinnin tukipilareista. Ehtolauseilla voimme vertailla muuttujia, ja tuloksesta riippuen tehdä haluttuja asioita. Tässä taas esimerkki:

DIM nimi AS STRING
INPUT "Anna nimesi: ", nimi
IF nimi = "fawkz" THEN PRINT "You're teh man!!!1" ELSE PRINT "Go away.."

Kaksi ensimmäistä riviä ovatkin jo tuttua kamaa. Kolmannessa opimme jälleen uuden käskyn, joka on IF. IF-lause koostuu käytännössä kolmesta käskystä: IF, THEN ja ELSE.

IF booleanexpression THEN thenpart [ELSE elsepart]

booleanexpression on esimerkissämme "nimi = fawkz", joka palauttaa joko arvon TRUE (tosi) tai FALSE (epätosi) riippuen lauseen oikeellisuudesta. Jos arvo on TRUE, suorittaa ohjelma thenpart-osion. Jos lausessa on ELSE, suoritetaan elsepart jos booleanexpression on FALSE. Tämä voi olla hieman sekaannuttavaa, mutta sellaista on elämä. ELSE ei ole pakollinen, jos et halua mitään tapahtuvan lauseen ollessa FALSE.

IF:in voi jakaa myös useammalle riville, jolloin se on sekä monipuolisempi että -mutkaisempi.

DIM nimi AS STRING
INPUT "Anna nimesi: ", nimi
IF nimi = "fawkz" THEN
   PRINT "You're teh man!!!1"
ELSE
   PRINT "Go away.."
END IF

Rakenteen pitäis jo olla melko selvä, joten en takerru siihen. Useamman rivin IF:issä saamme käyttöömme muutaman uuden käskyn. Ensimmäinen on END IF, joka lopettaa IF-lauseen, ei muuta. Toinen melko hyödyllinen käsky on ELSEIF, jolla voimme pistää toisen vertailun samaan lauseeseen. Ja taas esimerkkiä.

DIM nimi AS STRING
INPUT "Anna nimesi: ", nimi
IF nimi = "fawkz" THEN
   PRINT "You're teh man!!!1"
ELSEIF nimi = "foo" THEN
   PRINT "Who're ya??"
ELSE
   PRINT "Go away.."
END IF

Jos nimi on "fawkz", tulosta "You're teh man!!!1", jos nimi on "foo" tulosta "Who're ya??". Muussa tapauksessa tulosta "Go away..". Helppoa kun sen osaa. Sitten hieman tarkempaa tietoa booleanexpression-osasta.

booleanexpression:issa voimme käyttää boolean operaattoreita AND (ja), OR (tai) ja XOR (poissulkeva tai). Esimerkkiä taasen:

PRINT (5 = 5 AND 6 = 6) ' TRUE
PRINT (5 = 5 AND 5 = 6) ' FALSE
PRINT (5 = 5 OR 5 = 6)  ' TRUE
PRINT (5 = 5 OR 6 = 6)  ' TRUE
PRINT (5 = 4 OR 3 = 2)  ' FALSE
PRINT (5 = 5 XOR 6 = 6) ' FALSE
PRINT (5 = 4 XOR 6 = 6) ' TRUE

Ensimmäinen palauttaa TRUE, koska 5 on 5 ja 6 on 6. Toinen palauttaa FALSE, koska 5 on 5 mutta 5 ei ole 6. Ja niin edelleen. XOR voi tuntua hieman oudolta, etkä sitä luultavasti tule tarvitsemaankan. Logiikkahan on, että AND:issä kummankin parametrin pitää olla TRUE, OR:issa riittää kun jompikumpi on TRUE. XOR onkin hieman erikoisempi, ja se palauttaa TRUE vain jos jompikumpi (ei siis kumpikin) parametreista on tosi. Siitä nimi "poissulkeva tai". AND:ejä ja OR:eja voi olla lauseessa myös useampia:

PRINT (5 = 5 AND 6 = 6 OR 7 = 4) ' TRUE

Vielä sellainen pikku nootti tähän loppuun, että QB:ssä nolla (0) on yhtäkuin FALSE, ja mikä muu tahansa arvo on TRUE. Tämän voi testata helposti:

IF -1 THEN PRINT "-1 on TRUE"
IF 65 THEN PRINT "Myös 65 on TRUE"
IF 0 THEN PRINT "Tämä ei tulostu!"

Kolmas rivi ei todellakaan tulosta mitään, koska 0=FALSE. Loogista, ah, niin loogista. Mutta sitten seuraavaan – viimeiseen – asiaan, eli silmukkarakenteisiin.

Silmukat

Silmukoilla voit toistaa tiettyä lausetta, tai lauseita useamman kerran. Tietyn pituisille silmukoille käytetään usein käskyä FOR.

FOR counter = start TO end [STEP increment]
    [statements]
NEXT [counter [,counter...]]

FOR:in rakenne on melko yksinkertainen. counter on muuttuja, joka toimii laskurina. start on aloitusluku, ja end on lopetusluku. "STEP increment" on, kuten nimikin sanoo, "askellus", eli paljonko muuttujaan (laskuriin) lisätään jokaisen kierroksen jälkeen. Tämä parametri ei ole pakollinen, oletusarvo on yksi (1).

"statements" määrittelee lauseet, jotka silmukassa suoritetaan. Niitä voi olla useita usealle riville jaettuna kuten QB:ssä yleensäkin. FOR-silmukka loppuu NEXT-käskyyn, jossa ei-pakolliset counter-parametrit määrittelevät laskurin (tai laskureiden, jos on silmukan sisäinen silmukka) nimen. Esimerkki olisi varmaan asiaa:

DIM c AS INTEGER
FOR c = 1 TO 10
   PRINT c
NEXT

Tämä esimerkkihän ottaa ja tulosta ruilauttaa luvut väliltä 1-10. Toista esimerkkiä heti perään.

DIM c AS INTEGER
FOR c = 1 TO 10 STEP 2
   PRINT c
NEXT

Ja katsos kummaa, tämä esimerkki tulostaa luvut 1, 3, 5, 7 ja 9. Sitten vielä lisää STEP esimerkkiä:

DIM c AS INTEGER
FOR c = 10 TO 1 STEP -1
   PRINT c
NEXT

Ja näin esimerkkimme tulostaa luvut 10-1! Kuten huomaat, emme antaneet NEXT-käskylle parametria. Olisimme toki voineet antaa sille parametriksi muuttujan 'c', mutta näin pienissä silmukoissa se ei ole tarpeen. Sitten kun alamme puhua silmukan sisäisistä silmukoista, voi NEXT:in parametri jo tulla tarpeeseen, vähintään koodia selventämään.

DIM c AS INTEGER, d AS INTEGER
FOR c = 1 TO 5
   FOR d = 1 TO 5
      PRINT c * d;
   NEXT d
   PRINT
NEXT c

Ja siinähän se on, silmukan sisäinen silmukka. Ohjelmanpätkä tulostaa '5 kertaa 5'-kokoisen kertotaulun. 'c' ja 'd' kumpikin käyvät läpi arvot 1-5. Huomaa, että nyt käytimme NEXT:in parametria, joka selventää (kö?) koodia hieman. Muistathan, että NEXT:illä voi olla myös useampi parametri. Tässä koodissa sen käyttö ei ole mahdollista (johtuen rivinvaihto PRINT:istä) mutta otetaan esimerkki:

DIM c AS INTEGER, d AS INTEGER
FOR c = 1 TO 10
FOR d = 1 TO 5
   ' tänne oma koodi :-)
NEXT d, c

Itse en ole ko. "taktiikkaa" koskaan käyttänyt, enkä käytä. Mielestäni se vain saa koodin vaikeaselkoisemmaksi... jokainen tallaa tavallaan.

Loppusanat

Ja siinäpä se oikeastaan olikin. Käytä osan 1 ja 2 oppeja nyt hyödyksesi ja koodaa joku mukava pikkuohjelma. Muistathan hakea sitten myös seuraavaan osan, jossa aiheinamme ovat ainakin (suluissa muutama opetettava käsky):

Nähdään seuraavassa osassa, joka ilmestyy kun sen jaksan kirjoittaa. Laiskuudestani johtuen se voi tosin viedä jopa viikkoja... Jos haluat seuraavan osan kirjoittamiseen vauhtia, niin tipauta sähköpostia osoitteeseen _____@luukku.com.


Kommentit

Jesoft [03.04.2003 14:53:22]

#

Hui!tostahan oppii ceetä!

D4_B34M [09.12.2004 16:27:08]

#

Lisää nyt vielä että vb se menisi:

Private sub form1_load ()
Print "Hello world!"
End sub

Juhko [22.12.2006 18:58:42]

#

VOVA

öö osaan jo qbtä mut jos en osais ni oppisin täst

Are0100 [03.08.2007 21:34:07]

#

Mitä meinaa type misthmath?

Juhko [04.08.2008 15:30:53]

#

Jos kahden muuttujan tms. lajit eivät täsmää, QB antaa Type mismatch -ilmoituksen.

Esim.

a$ = b%

Merkkijonoa ei voida muuttaa kokonaisluvuksi, ja QB antaa Type mismatch -ilmoituksen.

sammakkomies [30.11.2009 22:37:09]

#

jess. Hyvä. Vähän koodia muuttaa niin saa hauskasti. Esm. Nimi = if = "tyhmä" print = "tämä peli on fiksuille. Mene pois. If name = fiksu print = neropatti vai? Sehän kiva. Else = "tervetuloa"

hauskasti kaverit yllättyy... :) hyvä ja selkeä ohje oli.

Kirjoita kommentti

Huomio! Kommentoi tässä ainoastaan tämän oppaan hyviä ja huonoja puolia. Älä kirjoita muita kysymyksiä tähän. Jos koodisi ei toimi tai tarvitset muuten vain apua ohjelmoinnissa, lähetä viesti keskusteluun.

Muista lukea kirjoitusohjeet.
Tietoa sivustosta