1. Sissejuhatus
C-keelt kasutatakse endiselt laialdaselt süsteemiprogrammeerimise ja manustatud programmeerimise valdkonnas. Selles keeles on stringid ja massiivid olulised elemendid andmete haldamiseks. C-keelt õppides on vältimatu mõista selle keele ainulaadset omadust, mille järgi stringi käsitletakse kui “tähemärkide massiivi”.
Selles artiklis süveneme C-keele stringide ja massiivide põhikontseptsioonidesse, et lahendada algajatel ja kesktasemel programmeerijatel sageli tekkivad küsimused „stringide ja massiivide erinevuse ning seoste“ kohta.
Lisaks vaatleme reaalsete programmide näidete kaudu, kuidas deklareerida massiive ja stringe, millised on põhilised stringifunktsioonid ning millistele mäluhalduse aspektidele tuleb tähelepanu pöörata. Nii muutub stringide töötlemine C-keeles turvalisemaks ja tõhusamaks.
2. Massiivide põhitõed
Massiivide mõistmine C-keeles on aluseks stringide töötlemisele. Selles jaotises selgitame massiivi kontseptsiooni ja kasutamist.
Mis on massiiv?
Massiiv on struktuur, mis salvestab sama tüüpi andmed järjestikustesse mälukohtadesse. Näiteks int
-tüüpi massiivi deklareerides saab korraga hallata mitut täisarvu. C-keeles deklareeritakse massiiv järgmiselt:
int numbers[5]; // Massiiv, mis talletab 5 täisarvu
See kood deklareerib täisarvumassiivi numbers
ja eraldab mälu 5 täisarvu jaoks. Iga elemendi juurde pääseb, kasutades indeksit.
Massiivi deklareerimine ja initsialiseerimine
Lisaks deklareerimisele saab massiivi ka kohe initsialiseerida, st määrata algväärtused.
int numbers[5] = {1, 2, 3, 4, 5}; // Deklareerimine ja initsialiseerimine
Siin salvestatakse massiivi numbers
täisarvud 1 kuni 5. Kui initsialiseerimist ei tehta, jäävad massiivi väärtused määramata (mälujääkandmed).
Mälu paigutus ja elementide kasutamine
C-keeles paiknevad massiivi elemendid mälus järjestikku. Näiteks int numbers[5]
korral on numbers[0]
kuni numbers[4]
kõrvuti mälus.
Massiivi elementidele pääseb ligi indeksiga, mis algab nullist ja kehtib kuni massiivi suurus miinus üks.
printf("%d", numbers[0]); // Kuvab esimese elemendi
Massiivid võimaldavad hallata sama tüüpi andmeid ühe muutujaga ja neid tõhusalt töödelda.
3. Stringide põhitõed
C-keeles ei ole string lihtsalt tähemärkide jada, vaid seda käsitletakse erilise massiivina. Selles jaotises õpime tundma C-keele stringide ülesehitust ja töötlusmeetodeid.
Mis on string?
C-keeles esitatakse string tähemärgimassiivina, mille lõppu lisatakse nullmärk ('\0'
). See nullmärk tähistab stringi lõppu ja on oluline stringide töötlemisel.
Näiteks saab stringi defineerida järgmiselt:
char greeting[6] = {'H', 'e', 'l', 'l', 'o', '\0'};
Siin talletatakse massiivi greeting
viis tähemärki „Hello” ja seejärel nullmärk. C-keeles tuvastatakse stringi lõpp '\0'
märgi abil.
Stringi deklareerimine ja initsialiseerimine
C-keeles saab stringi initsialiseerida otse tähemärgimassiivina. Tavaliselt kasutatakse selleks stringilitteraali:
char greeting[] = "Hello";
Selle kirjutamisviisi korral lisab kompilaator automaatselt lõppu nullmärgi. Seega on greeting
-massiivi pikkus 6 (5 tähemärki + nullmärk). Kui nullmärgi olemasolu eirata, võib see põhjustada vale tulemuse.
Stringilitteraali ja tähemärgimassiivi erinevus
Stringilitteraal ja tähemärgimassiiv tunduvad sarnased, kuid C-keeles on need erinevad. Stringilitteraal deklareeritakse const char*
tüübina ja seda ei saa muuta.
const char *greeting = "Hello"; // Stringilitteraal
Tähemärgimassiivi sisu on aga muudetav. Näiteks, kui see on deklareeritud char greeting[] = "Hello";
, saab üksikuid tähemärke muuta.
greeting[0] = 'h'; // Muudab "Hello" -> "hello"
Stringilitteraali ja tähemärgimassiivi erinevuse mõistmine aitab vältida mäluvigade ja vigade teket.
4. Stringide ja massiivide seos
C-keeles on string tegelikult „tähemärkide massiiv“. Selles jaotises selgitame, mida see tähendab ja kuidas stringe deklareerida ning initsialiseerida.
String on tähemärgimassiiv
C-keeles hallatakse stringe char-tüüpi massiivide abil. Näiteks saab massiivi deklareerida ja sinna stringi salvestada järgmiselt:
char name[10] = "Alice";
Selle koodi puhul sisaldab name
-massiiv sõna „Alice” ning ülejäänud elemendid täidetakse automaatselt nullmärkidega ('\0'
).
{'A', 'l', 'i', 'c', 'e', '\0', '\0', '\0', '\0', '\0'}
Stringi deklareerimise tähelepanekud
Stringi massiivina deklareerimisel tuleb määrata piisav suurus. Kui suurus on väiksem kui stringi pikkus + nullmärk, tekib viga või ootamatu käitumine.
char name[3] = "Alice"; // Viga - liiga väike massiiv
„Alice“ vajab 6 baiti (5 tähemärki + nullmärk), kuid massiivis on ainult 3 baiti.
Stringi muutmine ja kopeerimine
C-keeles ei saa kogu massiivile väärtust otse omistada. Stringi muutmiseks tuleb muuta üksikuid elemente:
name[0] = 'B'; // Alice -> Blice
Kogu stringi kopeerimiseks kasutatakse standardfunktsiooni strcpy
:
strcpy(name, "Bob"); // Asendab sisu sõnaga "Bob"
5. Põhilised stringifunktsioonid
C-keeles on standardses teegis mugavad funktsioonid stringide tõhusaks töötlemiseks. Selles jaotises käsitleme põhilisi funktsioone, mis kopeerivad, ühendavad, mõõdavad pikkust ja võrdlevad stringe.
Stringi kopeerimise funktsioon strcpy
strcpy
kopeerib ühe stringi teise. See säästab vaeva, et mitte kopeerida tähemärke ükshaaval käsitsi.
#include <string.h>
char source[] = "Hello";
char destination[10];
strcpy(destination, source); // Kopeerib source -> destination
Selles näites kopeeritakse source
sisu destination
-isse, mille tulemusena sisaldab see stringi “Hello”. Tuleb tagada, et destination
oleks piisavalt suur, et vältida puhvrivigu.
Stringide ühendamine funktsiooniga strcat
strcat
lisab teise stringi esimese lõppu.
#include <string.h>
char greeting[20] = "Hello";
char name[] = " World";
strcat(greeting, name); // greeting -> "Hello World"
Tuleb tagada, et esimene string mahutaks ühendamise järel kogu tulemuse.
Stringi pikkuse leidmine strlen
strlen
tagastab stringi pikkuse, jättes nullmärgi arvestamata.
#include <string.h>
char greeting[] = "Hello";
int length = strlen(greeting); // length = 5
Märkus: saadud pikkus ei pruugi kattuda massiivi kogusuurusega.
Stringide võrdlemine strcmp
strcmp
võrdleb kahte stringi ja tagastab 0, kui need on identsed, või positiivse/negatiivse väärtuse, kui need erinevad.
#include <string.h>
char str1[] = "Hello";
char str2[] = "Hello";
char str3[] = "World";
int result1 = strcmp(str1, str2); // 0 (samad)
int result2 = strcmp(str1, str3); // != 0 (erinevad)
6. Stringide massiiv (kahemõõtmeline massiiv)
Mitme stringi käsitlemiseks kasutatakse tihti kahemõõtmelist massiivi. Nii saab mitu stringi ühes massiivis hallata.
Kahemõõtmelise massiivi põhitõed
Kahemõõtmeline massiiv on massiiv massiivist, mida saab käsitleda nagu tabelit.
char names[3][10] = {
"Alice",
"Bob",
"Carol"
};
Siin on 3 rida ja iga rida mahutab kuni 10 tähemärki.
Elementidele juurdepääs
char first_char = names[0][0]; // 'A' massiivist "Alice"
Kõigi stringide väljastamiseks:
for (int i = 0; i < 3; i++) {
printf("%s\n", names[i]);
}
Initsialiseerimise ja suuruse tähelepanekud
Vaja on määrata piisavad mõõtmed. Kui string on pikem kui ridade veerupikkus, tekib viga.
char colors[3][10] = {"Red", "Green", "Blue"};
Näide kahemõõtmelise massiivi kasutamisest
#include <stdio.h>
#include <string.h>
int main() {
char names[3][10] = {"Bob", "Alice", "Carol"};
char temp[10];
for (int i = 0; i < 2; i++) {
for (int j = i + 1; j < 3; j++) {
if (strcmp(names[i], names[j]) > 0) {
strcpy(temp, names[i]);
strcpy(names[i], names[j]);
strcpy(names[j], temp);
}
}
}
for (int i = 0; i < 3; i++) {
printf("%s\n", names[i]);
}
return 0;
}
7. Mäluhaldus ja ettevaatusabinõud
C-keeles on stringide ja massiividega töötamisel mäluhaldus äärmiselt oluline. Vigane mäluhaldus võib põhjustada puhvrivigu ja mälulekkeid.
Mis on puhvriviga?
Puhvriviga tekib, kui kirjutatakse andmeid väljapoole massiivi eraldatud mäluala. C-keeles seda automaatselt ei kontrollita.
char buffer[10];
strcpy(buffer, "This is a very long string"); // Puhvriviga
Turvaline kopeerimine: strncpy
char buffer[10];
strncpy(buffer, "This is a very long string", sizeof(buffer) - 1);
buffer[sizeof(buffer) - 1] = '\0'; // Lõputähis käsitsi
Dünaamiline mäluhaldus
#include <stdlib.h>
#include <string.h>
char *str = (char *)malloc(20 * sizeof(char));
strcpy(str, "Dynamic allocation");
free(str);
Mälulekke vältimine
char *name = (char *)malloc(50 * sizeof(char));
strcpy(name, "John Doe");
free(name);
8. Kokkuvõte
Selles artiklis õppisime tundma C-keele stringe ja massiive, standardseid stringifunktsioone, kahemõõtmeliste massiivide kasutamist ning mäluhalduse põhimõtteid.
Massiivide ja stringide põhitõed
String on C-keeles „tähemärkide massiiv“ ja selle lõpus on nullmärk ('\0'
).
Põhilised stringifunktsioonid
Olulised funktsioonid: strcpy
, strcat
, strlen
, strcmp
.
Kahemõõtmelised massiivid
Kasulikud mitme stringi haldamiseks ühe muutuja abil.
Mäluhaldus
Puhvrivigade ja mäluleke vältimine, strncpy
ja dünaamilise mälu kasutamine.
Lõppsõna
C-keele stringide ja massiivide töötlemine võib tunduda alguses keeruline, kuid põhitõdesid ja mäluhaldust järgides saab seda teha turvaliselt ja tõhusalt.