2.9.5 Merkkijonoluokka

Kuten edellä nähtiin, C++:n "tavalliset" merkkijonot eivät aina ole kovin käytännöllisiä. Niiden käsittely vaatii kirjastofunktioiden käyttöä, ja maksimipituuden ylittäminen aiheuttaa helposti vaaratilanteita. Tästä syystä kieleen on lisätty merkkijonoluokka, jonka käyttö on luonnollisempaa (merkkijonoilla voidaan operoida lähes kuten yksinkertaisillakin muuttujilla) ja myös huolettomampaa (maksimipituuksista ei juuri tarvitse välittää).

Vaikka merkkijonoluokka kuuluu C++:n standardiin, niin valitettavasti sitä ei kuitenkaan löydy ihan kaikista kääntäjistä. Mutta sellainen on onneksi suhteellisen helppo ohjelmoida itsekin (ei tosin tämän kurssin tiedoilla).

Merkkijonoluokan saa käyttöönsä direktiivillä

#include <string>   // HUOM: ei string.h

Lisäksi standardi vaatii ohjelman alkuun lauseen

using namespace std;

jonka merkityksestä ei tässä vaihessa tarvitse välittää.

Muuttujien esittelyssä käytetään char-sanan tilalla sanaa string ja merkkijonon pituutta ei ilmoiteta:

string sukunimi;

Merkkijono voidaan myös alustaa esittelynsä yhteydessä:

string etunimi = "Toivo"; // tai: string etunimi("Toivo");

Tulostus tapahtuu kuten ennenkin, mutta syöttö täytyy tehdä hieman eri tavalla:

cout << "Anna merkkijono    > ";
getline(cin, mjono); // HUOM: ei cin.getline
cout << "Annoit merkkijonon > " << mjono << endl;

Syötössä siis funktiokutsu on erilainen. Funktiolla getline voi olla myös kolmas char-tyyppinen argumentti, joka ilmoittaa syötön lopetusmerkin. Oletuksena tuo lopetusmerkki on rivinvaihtomerkki '\n'.

Merkkijonoja voi käsitellä merkeittäin kuten taulukoita:

string mjono1 = "kasa";
string mjono2 = "abcd";
...
mjono1[0] = mjono2[3];
mjono1[2] = 't';
cout << mjono1 << endl; // tulostaa: data

Tärkein syy merkkijonoluokan käytölle kuitenkin on, että sen jonoilla voidaan operoida paljon helpommin kuin tavallisilla merkkijonoilla. Sijoitus tapahtuu =-operaattorilla:

string etunimi, sukunimi;
etunimi = "Esko";
sukunimi = etunimi;

ja liittäminen +-operaattorilla:

string malli, otsikko;
string tytto = "Julia", poika = "Romeo";
...
malli = "Alfa " + poika;
cout << malli << endl;   // tulostaa: Alfa Romeo
...
otsikko = poika + " ja " + tytto;
cout << otsikko << endl; // tulostaa: Romeo ja Julia

Lisäksi vertailut onnistuvat tavalliseen tapaan:

if (mjono1 == mjono2) cout << "Samat!" << endl;
if ("Aaltonen" < mjono2) cout << "Aaltonen ensin." << endl;
while (mjono1 >= "Loppu") { ... };

(Tietenkin myös operaattoreita !=, > ja <= voi käyttää.) Näin ollen edellä esitetyt kirjastofunktiot strcpy, strcat, jne. voidaan merkkijonoluokan osalta unohtaa.

Jos tarvitaan merkkijonon pituutta, sen saa selville jäsenfunktiolla length seuraavasti:

string mjono;
int pituus;
...
pituus = mjono.length();

Myös edellä esitettyä strlen-funktiota voi käyttää, mutta koska ko. funktio olettaa, että argumenttina tulee "tavallinen" merkkijono, täytyy merkkijonoluokan jonot erikseen muuntaa sellaisiksi jäsenfunktiolla c_str:

string mjono;
int pituus;
...
pituus = strlen(mjono.c_str()); // HUOM: ei strlen(mjono)

Esimerkki

/* *********************************************************
NIMI.CPP
  Harjoitellaan C++:n merkkijonoluokan käyttöä.
  Lukee näppäimistöltä nimen ja osoitteen, ja tulostaa ne
  näytölle.
********************************************************* */

#include <iostream.h>
#include <string>

using namespace std;

void kysy_nimi(string &etunimi, string &sukunimi)
{
  cout << "Anna nimesi, ensin etunimi > ";
  getline(cin, etunimi);
  cout << "           sitten sukunimi > ";
  getline(cin, sukunimi);
}

void kysy_osoite(string &katuosoite, string &postitoimipaikka)
{
  cout << "Anna osoitteesi, ensin katuosoite > ";
  getline(cin, katuosoite);
  cout << "          sitten postitoimipaikka > ";
  getline(cin, postitoimipaikka);
}

void tulosta_tiedot(string nimi, string osoite)
{
  cout << "\n";
  cout << "Nimesi ja osoitteesi:\n";
  cout << nimi << endl;
  cout << osoite << endl;
}

int main(void)
{
  string etunimi, sukunimi, katuosoite, postitoimipaikka;
  string nimi, osoite;

  kysy_nimi(etunimi, sukunimi);
  kysy_osoite(katuosoite, postitoimipaikka);
  nimi = etunimi + " " + sukunimi;
  osoite = katuosoite + "\n" + postitoimipaikka;
  tulosta_tiedot(nimi, osoite);

  return 0;
}