Formatoidulla tulostuksella tarkoitetaan mm. muuttujien ulkoasun määräämistä tulostusvaiheessa. Esimerkiksi liukuluvusta voidaan määrätä tulostumaan ainoastaan kaksi ensimmäistä desimaalia. Tämä voidaan kyllä tehdä myös cout:lla, mutta ehkä helpommin se onnistuu paljon käytetyllä (C-kieleen kuuluvalla) printf-funktiolla, joka on määritelty stdio-kirjastossa.
Formatoidussa tulostuksessa kääntäjälle annetaan malli, jonka mukaan tulostuksen ulkoasu tulisi muokata. Annettava malli, formaatti, on merkkijono, joka kertoo miten tulostetaan. Yleiseen merkkijonojen tapaan se esitetään "-merkkien välissä. Formaatti voi sisältää vakiotekstejä, eli tekstinpätkiä, jotka kerrasta toiseen tulostuvat samanlaisina, sekä muuntuvia osia, joiden sisältö määräytyy tulostettavan aineiston, eli muuttujien sisällön mukaan.
Tulostusformaatissa voitaisiin määritellä vaikkapa seuraavia asioita (suluissa vastaavan tulostuksen määräävä C++-kielinen formaatti):
Formaatit voidaan kirjoittaa yhtenä kokonaisuutena, jolloin niistä saadaan yhtenäisen lauseen tulostusmuoto (formaatti):
"Appelsiinin hinta on %.2lf mk.\n %d appelsiinia maksaa %.2lf mk.\n"
Formatoitu tulostus näytölle tapahtuu funktiolla printf, jonka yleinen muoto on
printf(formaatti, lausekkeet);
Komennon sisältämään formaattiin voidaan sijoittaa ns. konversiomäärittimiä, jotka kertovat, millä tavoin formaatin perässä esiintyvien lausekkeiden arvot tulee tulkita.
Konversiomäärittimen pakolliset osat ovat konversiomerkki % ja tyypin määritin. Näiden väliin voidaan lisätä ns. lippuja: kentän leveyden määrittely (merkkijonoille, kokonaisluvuille, liukuluvuille) tai tulostettavan arvon tarkkuuden määrittely (liukuluvuille).
Tyypin määritin voi saada mm. seuraavat arvot:
Kentän leveydeksi kirjoitetaan kokonaisluku, joka määrää kuinka monta merkkiä tulostettavalle tiedolle varataan. Kyseessä on minimileveys; jos tulostus ei mahdu annettuun kenttään, leveyttä kasvatetaan tarvittava määrä (siis tulostuksesta ei häviä mitään).
Tarkkuuden määrittely aloitetaan pisteellä, jonka jälkeen kirjoitetaan kokonaisluku, joka osoittaa halutun tarkkuuden. Tarkkuuden määrittelyä voi käyttää joko yhdessä kentän leveyden kanssa tai yksinään.
Parhaiten asia selvinnee esimerkin avulla:
/* ********************************************************* FORM1.CPP Tulostetaan näytölle eri tyyppisten muuttujien arvoja. Huomaa formaatin vaihtuminen muuttujan tyypin mukaan. ********************************************************* */ #include <stdio.h> // kirjasto, jossa määritelty mm. printf int main(void) { int luku = 20 ; // kokonaisluku long int isoluku = 23000 ; // pitkä kokonaisluku float numero1 = 7.548; // liukuluku double numero2 = 5.6741; // kaksoistarkkuuden liukuluku char merkki = 'A'; // merkki char mjono[] = "ohjelmointi"; // merkkijonot opitaan myöhemmin printf("luku on %5d \n", luku); // kentän leveys 5 printf("isoluku on %ld \n", isoluku); // leveyttä ei annettu printf("numero1 on %4.2f \n", numero1); // leveys 4, tarkkuus 2 printf("numero2 on %lf \n", numero2); // huomaa oletustarkkuus printf("merkki on %c \n", merkki); printf("mjono on %7s \n", mjono); // liian lyhyt leveys! return 0; }
Ohjelma tulostus näyttää seuraavalta:
luku on 20 isoluku on 23000 numero1 on 7.55 numero2 on 5.674100 merkki on A mjono on ohjelmointi
Mikä on esimerkin printf -lauseiden formaateissa esiintyvän \n -osan merkitys?
Jos esimerkin
merkkimuuttuja merkki tulostettaisiin kokonaislukuformaatilla,
printf("merkki on %d \n", merkki);
niin mitä lause tulostaisi?
Koska merkki % (prosentti) on varattu konversiomäärittimen aloitusmerkiksi, ei sitä voida tulostaa suoraan, vaan prosenttimerkki saadaan tulostumaan merkkiparilla %%.
Funktion printf kutsussa kunkin formaatin jälkeen mainitun lausekkeen arvo liitetään vuorollaan formaatin sisältämään merkkijonoon konversiomäärittimen määräämässä muodossa. Olkoon muuttujassa luku arvo 7 ja muuttujassa tulos arvo 49. Tällöin lause
printf("%d kertaa %d on %d !!\n", luku, luku, tulos);
antaa tulostukseksi
7 kertaa 7 on 49 !!
Jälleen on huomattava, että formaatin jäljessä esiintyy nimenomaan lausekkeita: Lause
printf("Luvun %d neliö on %d.\n", luku, luku*luku);
tulostaa
Luvun 7 neliö on 49.
Oletuksena liukuluvut tulostetaan kuudella desimaalilla (Borland C++-kääntäjää käytettäessä). Jos double-tyyppiä olevan muuttujan hinta arvo on 2.5, saadaan lauseesta
printf("Appelsiinin hinta on %lf markkaa.\n", hinta);
tuloste
Appelsiinin hinta on 2.500000 markkaa.
Saatu tuloste näyttää huonolta, sillä hinnat yleensä ilmoitetaan kahta desimaalia käyttäen. Lisätään tulostusformaattiin halutuksi tarkkuudeksi kaksi desimaalia. Tällöin lauseesta
printf("Appelsiinin hinta on %.2lf markkaa.\n", hinta);
saadaan tuloste
Appelsiinin hinta on 2.50 markkaa.
Esimerkki
/* ********************************************************* APPELS.CPP Lasketaan tuotteen hinnasta alennus, ja tulostetaan vanha hinta, aleprosentti ja alennettu hinta. ********************************************************* */ #include <stdio.h> int main(void) { double hinta = 195.90; int ale_pros = 25; printf("Entinen hinta on %.2lf mk.\n", hinta); printf("Alennus on %d %%.\n", ale_pros); printf("Uusi hinta on %.2lf mk.\n", hinta-(ale_pros*hinta)/100); return 0; }
Mitä tekevät esimerkin keskimmäisessä printf -lauseessa peräkkäiset prosenttimerkit %% ?
Jos viimeinen printf -lause olisi muotoa
printf("Uusi hinta on %lf mk.\n", hinta-(ale_pros*hinta)/100);
miten ohjelman toiminta muuttuisi?