2.9.4.1 Pituus (strlen)

Funktiolla selvitetään merkkitaulukkoon tallennetun merkkijonon pituus. Funktiolla on yksi parametri, merkkijono, ja se palauttaa jonon pituuden kokonaislukuna:

char jono[] = "innostunut sonni";
char sukunimi[30] = "Virtala";
int pituus;
pituus = strlen(jono);     // pituus saa arvon 16
pituus = strlen(sukunimi); // pituus saa arvon 7

Huomioitavaa:

strlen ei laske pituuteen mukaan loppumerkkiä '\0'.

• Palautettu pituus ei riipu merkkijonolle varatusta tilasta vaan siitä, missä kohtaa loppumerkki sijaitsee. Edellisessä esimerkissä sukunimi-jonon pituudeksi palautetaan arvo 7 vaikka jonolle on varattu tilaa 30 merkkiä.

Minkä arvon strlen(mjono) palauttaa, jos funktion parametrina oleva mjono määritellään seuraavasti?
char mjono[190]= "Pitkääkin pidempi merkkijono";
char mjono[10] = "Lyhyt";

2.9.4.2 Kopiointi (strcpy ja strncpy)

Funktiokutsulla strcpy(mjono1, mjono2); kopioidaan merkkijonon mjono2 sisältö merkkijonomuuttujaan mjono1. Jälkimmäisen parametrin (mjono2) sisältöä ei muuteta mitenkään. Huomaa siis kopiointisuunta: oikealta vasemmalle.

Funktio ei tarkista, riitääkö kohdejonon pituus kopioitavalle merkkijonolle. Jos merkkijonoon kopioidaan pidempi jono kuin tilaa on varattu, kirjoittuu jonon loppuosa mahdollisesti jonkin toisen tiedon päälle. Ohjelmoijan on itse huolehdittava, ettei tällaista tilannetta pääse syntymään.

char lyhyt[5];
strcpy(lyhyt, "ylipitkä merkkijono"); /* näin EI saa tehdä!!! */
                          /* aiheuttaa muistialueen ylityksen */

Yllä oleva virheellinen merkkijonon kopiointi aiheuttaa muistissa seuraavan tilanteen:

Eli lyhyt-merkkijonoon mahtumaton teksti kirjoitetaan raa'asti merkkijonolle varatun muistialueen perään. Tämä aiheuttaa ennemmin tai myöhemmin ongelmia ohjelman toiminnassa.

Funktio strncpy on muutoin sama kuin strcpy, mutta sille annetaan kolmanneksi argumentiksi kokonaisluku, joka kertoo kopioitavien merkkien maksimimäärän. Tällä voidaan estää kirjoittaminen merkkijonon oman muistialueen yli antamalla maksimimääräksi kohdemerkkijonon pituus:

char jono[10];
strncpy(jono, "tili", 10);

Jos kopioitava merkkijono on lyhyempi kuin määritelty maksimipituus, lisää funktio merkkijonon loppuun loppumerkin (itse asiassa täyttää koko tyhjäksi jäävän alueen loppumerkeillä). Yllä olevan funktiokutsun jälkeen muuttujan jono sisältö on:

Jos kopioitava merkkijono on pidempi, niin loppumerkki voi jäädä asettamatta. Esimerkiksi kopiointilause

char jono[10];
strncpy(jono, "tilikkutäkki", 10);

voi aiheuttaa tilanteen, jossa merkkijonoon ei sijoiteta loppumerkkiä:

Seuraavan kerran kun jonoa yritetään käyttää, ei loppua voida tunnistaa ja ohjelma luulee jonon jatkuvan, kunnes muistista sattuu löytymään seuraava loppumerkki. Tuloksena voi tietysti olla minkälaista sotkua tahansa.

Ongelma voidaan välttää sijoittamalla kopioinnin jälkeen "käsin" merkkijonon viimeiseen paikkaan loppumerkki:

char jono[10];
strncpy(jono, "tilikkutäkki", 10);
jono[10-1] = '\0';

Funktiota strncpy kannattaa (ja pitää) käyttää, koska maksimipituuden määrittelyllä voidaan välttää muistialueen ylityksen mahdollisuus kopiointivaiheessa. On kuitenkin muistettava, että strncpy voi jättää loppumerkin kirjoittamatta.

Huomaa, että edellisissä esimerkeissä jonojen pituudet on annettu suoraan lukuarvoilla. Nämä lukuarvot kannattaa tietenkin määritellä symbolisiksi vakioiksi, esimerkiksi

#define PITUUS 10
...
char jono[PITUUS];
strncpy(jono, "tili", PITUUS);
jono[PITUUS-1] = '\0';

2.9.4.3 Liittäminen (strcat ja strncat)

Funktioilla voidaan liittää merkkijono toisen merkkijonon perään. Kohdejonon aiempaa sisältöä ei kirjoiteta yli, vaan jonoa "jatketaan". Funktioiden keskinäinen ero on sama kuin funktioiden strcpy ja strncpy kohdalla: "n"-versioon annetaan kolmanneksi argumentiksi liitettävien merkkien maksimimäärä kokonaislukuna. On huomattava, että ensimmäisenä parametrina olevassa merkkijonossa saattaa olla jo valmiiksi merkkejä, jolloin käytettävissä oleva pituus ei olekaan koko merkkijonon pituus:

#define MAXPIT 20
...
char jono[MAXPIT] = "tilikku";
strcat(jono, "täkki");          // riittääkö varattu tila?

Käyttämällä funktiota strncat yhdessä funktion strlen kanssa voidaan huoletta liittää merkkijono ilman pelkoa siitä, että varattu alue loppuu kesken:

#define MAXPIT 20
...
char jono[MAXPIT] = "tilikku";
strncat(jono, "täkki", MAXPIT-(strlen(jono)+1));

Funktio strncat laittaa merkkijonon loppuun aina loppumerkin (toisin kuin strncpy).

2.9.4.4 Vertailu (strcmp ja strncmp)

Funktiollastrcmp vertaillaan merkkijonojen samuutta. Funktio palauttaa kokonaislukuarvon, josta voidaan päätellä kumpi merkkijono oli suurempi vai olivatko jonot samoja:

< 0 jos ensimmäinen jono on pienempi kuin toinen,

== 0 jos jonot ovat samat,

> 0 jos ensimmäinen jono on suurempi kuin toinen.

Jonojen "suuruudella" tarkoitetaan merkkien sijoittumista ASCII-taulukossa. Vertailu aloitetaan luonnollisesti merkkijonojen alusta. Jos ensimmäiset merkit ovat samat, vertaillaan toisia, jos toiset ovat samat, vertaillaan kolmansia, jne. On muistettava, että isot kirjaimet ovat ASCII-taulussa ennen pieniä kirjaimia. Lyhyempi merkkijono on pienempi, jos jonot ovat lyhyemmän loppuun asti samat. Esimerkkejä:

strcmp("ayyyyy", "yaaaaa")    < 0
strcmp("Lepo", "lepo")        < 0
strcmp("sadesää", "sadeasu")  > 0
strcmp("Susi", "Susi")        == 0
strcmp("apinatarha", "apina") > 0

Funktio strncmp on muutoin sama kuin strcmp, mutta sille annetaan kolmanneksi argumentiksi verrattavien merkkien maksimimäärä. Jos toinen merkkijonoista on lyhyempi kuin annettu maksimimäärä, toiminta on täsmälleen sama kuin edellisessä. Muutoin merkkejä verrataan annettuun maksimiin asti ja palautetaan järjestys, joka siihen mennessä on selvinnyt:

strncmp("apuva", "apuvaunu", 5) == 0
strncmp("apuva", "apuvaunu", 8) < 0
strncmp("kapula", "kanuuna", 7) > 0

2.9.4.5 Muut funktiot

C++-standardista löytyy paljon lisää merkkijonojen käsittelyyn tarkoitettuja funktioita. Lisäksi kääntäjien mukana tulee usein standardin ulkopuolisiakin funktioita.

Etsi manuaalien tai ohjelmankehitysympäristön Help-järjestelmän avulla muita merkkijonojen käsittelyyn tarkoitettuja funktiota. (Funktioiden nimeäminen on standardikirjastossa yhtenäistä; niiden alku on joko str- tai strn-).