C-keele stringi sisestamine: turvalised meetodid ja praktilised näited algajatele

目次

1. Sissejuhatus

C-keel on programmeerimise aluste õppimisel väga oluline keel. Nende hulgas on „stringi sisestamine“ hädavajalik funktsioon, kui on vaja kasutajalt andmeid vastu võtta. Selles artiklis selgitame üksikasjalikult, kuidas stringisisestust C-keeles kasutada, ja tutvustame tehnikaid ning ettevaatusabinõusid, et seda turvaliselt hallata.

Eriti algajatel tekivad sageli probleemid vigade ja turvariskidega, mis võivad ilmneda sisestatud stringe töödelda püüdes. Seetõttu katab see artikkel laia spektrit, alates põhilistest funktsioonidest kuni edasijõudnute koodinäideteni, eesmärgiga aidata teil omandada praktilisi oskusi.

Kui mõistate õigesti C-keele stringi sisestamise põhimõtteid ja suudate neid turvaliselt rakendada, saate astuda esimese sammu keerukamate programmide loomise poole. Alustame konkreetse sisuga.

2. Mis on stringisisestus C-keeles? Põhimõisted

Mis on string?

C-keeles esitatakse stringid tähemärkide massiivina. Stringi lõpus peab alati olema lõpetav sümbol „\0“, mis näitab stringi lõppu. Tänu sellele ei pea C-keeles stringi pikkust alati otseselt määrama.

Stringide ja massiivide seos

C-keeles on string tegelikult tähemärgimassiiv (char tüüpi). Näiteks saab stringi deklareerida järgmiselt:

char str[10];  // 10 tähemärgi pikkune puhver stringi jaoks

Selles näites reserveeritakse mälu kuni 10 tähemärgi jaoks. Kuid üks koht on reserveeritud lõpetavale märgile „\0“, seega saab tegelikult salvestada kuni 9 tähemärki.

Stringi literaali näide

Stringi literaal on tekst, mis on ümbritsetud jutumärkidega (“”). Näiteks:

char greeting[] = "Hello";

Sellisel juhul käsitletakse greeting-i automaatselt 6 elemendiga massiivina („Hello“ + lõpetav sümbol).

Miks on stringi sisestamine vajalik?

Programmides on sageli vaja kasutajalt andmeid sisestada. Näiteks nime või aadressi registreerimine, otsingusõna sisestamine jne. Seetõttu on oluline mõista, kuidas stringe turvaliselt ja tõhusalt käsitleda.

年収訴求

3. Stringi sisestamise põhifunktsioonid ja kasutusnäited

3-1. scanf funktsioon

scanf funktsiooni põhikasutus

scanf funktsiooni kasutatakse andmete saamiseks standardsisendist (klaviatuurilt). Stringi sisestamisel kasutatakse vormingumäärangut %s.

Koodinäide:

#include <stdio.h>

int main() {
    char str[50];  // Puhver kuni 50 tähemärgi jaoks
    printf("Sisesta string: ");
    scanf("%s", str);  // Loe string standardsisendist
    printf("Sisestatud string: %s\n", str);
    return 0;
}

See programm võtab kasutajalt stringi sisendi ja kuvab selle ekraanile.

scanf funktsiooni tähelepanekud

  1. Tühikuid ei töödelda:
    scanf käsitleb tühikuid, tabulaatoreid ja reavahetusi eraldajatena. Seetõttu katkeb string sisestamisel esimese tühiku juures.

Näide:
Sisend:

Hello World

Väljund:

Hello
  1. Puhvri ületäitumise oht:
    Kui sisestatud string ületab puhvri suuruse, võib see mälu rikkuda. Selle tagajärjeks võib olla programmi kokkujooksmine või turvanõrkuste ärakasutamine.

Lahendus:
Soovitatav on kasutada turvalisemaid funktsioone (näiteks fgets).

3-2. fgets funktsioon

fgets funktsiooni põhikasutus

fgets võimaldab turvaliselt lugeda stringi kuni määratud pikkuseni. See loeb kaasa ka reavahetuse märgi, kuid väldib puhvri ületäitumist.

Koodinäide:

#include <stdio.h>

int main() {
    char str[50];  // Puhver kuni 50 tähemärgi jaoks
    printf("Sisesta string: ");
    fgets(str, sizeof(str), stdin);  // Turvaline sisestus
    printf("Sisestatud string: %s", str);
    return 0;
}

See programm loeb stringi kuni 50 tähemärki ja väljastab selle turvaliselt.

fgets funktsiooni eelised

  1. Puhvri ületäitumise vältimine:
    Kasutaja sisestus piiratakse määratud suurusega.
  2. Tühikute töötlemine:
    Sisestatud string võib sisaldada ka tühikuid ja tabulaatoreid.

fgets funktsiooni tähelepanekud

  1. Reavahetuse töötlemine:
    Sisestatud stringi lõpus võib olla reavahetuse märk, mis võib väljundis põhjustada ootamatu tühja rea.

Näide reavahetuse eemaldamiseks:

str[strcspn(str, "\n")] = '\0';
  1. Sisendpuhvrisse jäävad andmed:
    Kui pärast fgets-i kasutatakse muid sisendmeetodeid, võib puhvris alles olla üleliigne sisend. Selle vältimiseks kasutatakse sageli fflush(stdin) või getchar().

3-3. Millist kasutada?

Funktsiooni nimiKasutusTähelepanekud
scanfLihtne stringi sisestus (ilma tühikuteta lühikesed stringid)Oht puhvri ületäitumisele, ei tööta tühikutega.
fgetsTurvaline, sobib ka tühikuid sisaldava sisendi jaoksTuleb eemaldada reavahetus ja vajadusel puhverdada sisend.

Algajatele ja praktiliste programmide puhul on soovitatav eelistada fgets-i turvalisuse tõttu.

4. Praktilised tehnikad turvaliseks stringi sisestamiseks

4-1. Puhvri ületäitumise vältimine

Mis on puhvri ületäitumine?

Puhvri ületäitumine tekib siis, kui sisend ületab ette nähtud mäluvahemiku suuruse ja kirjutab andmeid teistesse mälupiirkondadesse. Selle tagajärjeks võib olla programmi krahh või turvaaukude tekkimine.

Näide:
Järgmine kood on ohtlik:

char str[10];
scanf("%s", str);  // Ei piira sisendi pikkust

Kui kasutaja sisestab üle 10 tähemärgi, tekib puhvri ületäitumine.

Lahendus 1: Kasuta fgets funktsiooni

fgets võimaldab määrata puhvri suuruse ja piirata sisendi pikkust, mis suurendab turvalisust.

Turvaline näide:

#include <stdio.h>
#include <string.h>

int main() {
    char str[10];
    printf("Sisesta string: ");
    fgets(str, sizeof(str), stdin);
    str[strcspn(str, "\n")] = '\0';  // Eemalda reavahetus
    printf("Sisestatud string: %s\n", str);
    return 0;
}

See kood piirab sisendi maksimaalselt 9 tähemärgiga ja töötleb reavahetuse korrektselt.

Lahendus 2: Kontrolli sisendi pikkust

Kui sisend on pikem kui oodatud, tuleks kasutajale kuvada hoiatus või katkestada programm.

Näide:

#include <stdio.h>
#include <string.h>

int main() {
    char str[10];
    printf("Sisesta string (maksimaalselt 9 tähemärki): ");
    fgets(str, sizeof(str), stdin);
    if (strlen(str) >= sizeof(str) - 1 && str[strlen(str) - 1] != '\n') {
        printf("Sisend on liiga pikk.\n");
        return 1;  // Välju veaga
    }
    str[strcspn(str, "\n")] = '\0';  // Eemalda reavahetus
    printf("Sisestatud string: %s\n", str);
    return 0;
}

See programm kontrollib sisendi pikkust ja kuvab vea, kui sisend on liiga pikk.

4-2. Vigade käsitlemise rakendamine

Miks on vigade käsitlemine oluline?

Vigade käsitlemine on vajalik programmi töökindluse tagamiseks. Eriti kasutaja sisendi puhul tuleb arvestada ootamatute või sobimatute andmetega.

Lahendus 1: Sisendi kordamine (retry)

Kui kasutaja annab vigase sisendi, saab lasta tal proovida uuesti.

Näide:

#include <stdio.h>
#include <string.h>

int main() {
    char str[10];
    int valid = 0;

    while (!valid) {
        printf("Sisesta string (maksimaalselt 9 tähemärki): ");
        fgets(str, sizeof(str), stdin);

        if (strlen(str) >= sizeof(str) - 1 && str[strlen(str) - 1] != '\n') {
            printf("Sisend on liiga pikk. Proovi uuesti.\n");
            while (getchar() != '\n');  // Puhasta ülejäänud sisend
        } else {
            str[strcspn(str, "\n")] = '\0';
            valid = 1;
        }
    }

    printf("Sisestatud string: %s\n", str);
    return 0;
}

See programm lubab kasutajal uuesti sisestada, kuni kehtiv sisend on antud.

Lahendus 2: Sisendi filtreerimine

Sisendit saab kontrollida kindlate reeglitega (nt ainult tähed ja numbrid).

Näide:

#include <stdio.h>
#include <ctype.h>
#include <string.h>

int isValidInput(const char *str) {
    for (int i = 0; str[i] != '\0'; i++) {
        if (!isalnum(str[i])) {  // Ainult tähed ja numbrid on lubatud
            return 0;
        }
    }
    return 1;
}

int main() {
    char str[50];
    printf("Sisesta ainult tähed ja numbrid: ");
    fgets(str, sizeof(str), stdin);
    str[strcspn(str, "\n")] = '\0';

    if (isValidInput(str)) {
        printf("Sisestatud string: %s\n", str);
    } else {
        printf("Vigane sisend.\n");
    }

    return 0;
}

See programm lubab ainult tähti ja numbreid ning keeldub muust sisendist.

5. Mitte-soovitatavad funktsioonid ja nende alternatiivid

5-1. gets funktsiooni ohtlikkus

Mis on gets funktsioon?

gets funktsioon loeb kasutajalt stringi sisendi. Selle põhikasutus on järgmine:

Koodinäide:

char str[50];
gets(str);  // Loe string standardsisendist

See kood võib tunduda lihtne ja mugav, kuid sellega kaasneb tõsiseid probleeme.

Probleemid gets funktsiooniga

  1. Puhvri ületäitumise oht:
    gets ei piira sisendi pikkust. Kui sisestatud string ületab puhvri suuruse, rikutakse mälu ja tekib suur turvarisk.

Näide:

char str[10];
gets(str);  // Sisendi pikkust ei piirata

Kui sisestada 20 tähemärki, kirjutatakse mälu üle ja programm võib kokku joosta.

  1. Turvarisk:
    Puhvri ületäitumist saab ära kasutada rünnakuteks (nt buffer overflow attack), mis võib viia süsteemi ülevõtmiseni.
  2. Eemaldatud standardist:
    C99 standardis märgiti see mitte-soovitatavaks ja C11 standardis eemaldati. Tänapäeva kompilaatorid annavad hoiatuse või vea.

5-2. Turvalised alternatiivid

fgets funktsiooni kasutamine

gets asemel tuleks kasutada fgets-i, mis väldib puhvri ületäitumist.

Turvaline koodinäide:

#include <stdio.h>
#include <string.h>

int main() {
    char str[50];
    printf("Sisesta string: ");
    fgets(str, sizeof(str), stdin);  // Turvaline sisestus
    str[strcspn(str, "\n")] = '\0';  // Eemalda reavahetus
    printf("Sisestatud string: %s\n", str);
    return 0;
}

Võrdlus scanf funktsiooniga

scanf-i saab samuti kasutada stringide sisestamiseks, kuid nagu eelnevalt mainitud, ei suuda see töödelda tühikuid. Keerukamate stringide ja turvalisuse jaoks on parem kasutada fgets-i.

getline funktsiooni kasutamine

getline on POSIX-standardiga funktsioon (mitte C11 osa), mis võimaldab dünaamiliselt mälu eraldada ja töödelda pikki stringe ilma puhvri suurust muretsemata.

Näide:

#include <stdio.h>
#include <stdlib.h>

int main() {
    char *line = NULL;
    size_t len = 0;
    ssize_t read;

    printf("Sisesta string: ");
    read = getline(&line, &len, stdin);  // Dünaamiline mälu eraldamine

    if (read != -1) {
        printf("Sisestatud string: %s", line);
    }

    free(line);  // Vabasta mälu
    return 0;
}

Miks vältida vananenud funktsioone?

C-keeles on mitmed vanad funktsioonid turvalisuse kaalutlustel märgitud mitte-soovitatavaks. Kui sisend pärineb väljastpoolt (nt kasutajalt), suureneb turvarisk. Seetõttu tuleb alati kasutada turvalisi alternatiive.

Mitte-soovitatav funktsioonAlternatiivKasutus ja eelised
getsfgetsTurvaline sisestus fikseeritud puhvri suurusega.
getsgetlineSobib pikkade stringide jaoks, kasutab dünaamilist mälu.
scanf("%s")fgetsTöötleb turvaliselt ka tühikuid sisaldavaid stringe.

 

6. Praktilised näited ja laiendatud kasutus|mitmerealise stringi sisestamine ja töötlemine

6-1. Mitme rea sisestuse vastuvõtmine

Mitmerealise sisendi ülevaade

Mõnes programmis on vaja kasutajalt võtta mitmerealine tekst ja töödelda seda tervikuna. Näiteks märkmiku rakendustes on mitmerealine sisend hädavajalik.

Näide 1: 3 rea sisendi vastuvõtmine

#include <stdio.h>
#include <string.h>

#define MAX_LINES 3     // Reakogus
#define MAX_LENGTH 100  // Maksimaalne pikkus rea kohta

int main() {
    char lines[MAX_LINES][MAX_LENGTH];

    printf("Palun sisesta %d rida:\n", MAX_LINES);

    for (int i = 0; i < MAX_LINES; i++) {
        printf("%d. rida: ", i + 1);
        fgets(lines[i], sizeof(lines[i]), stdin);
        lines[i][strcspn(lines[i], "\n")] = '\0';  // Eemalda reavahetus
    }

    printf("\nSisestatud read:\n");
    for (int i = 0; i < MAX_LINES; i++) {
        printf("%d. rida: %s\n", i + 1, lines[i]);
    }

    return 0;
}

Põhipunktid:

  1. Kahemõõtmeline massiiv: Iga rida salvestatakse eraldi massiivi.
  2. Turvaline sisestus fgets-iga: Piirab maksimaalset pikkust ja eemaldab reavahetuse.
  3. for-tsükkel: Võimaldab mugavalt mitut sisendit töödelda.

Kasutusnäide:

Palun sisesta 3 rida:
1. rida: Hello
2. rida: World
3. rida: C Language

Sisestatud read:
1. rida: Hello
2. rida: World
3. rida: C Language

6-2. Tühikute ja erimärkidega stringide töötlemine

Näide tühikutega sisendist

Tühikuid sisaldavate stringide sisestamiseks tuleks kasutada fgets-i.

Näide 2: Tühikuid sisaldava sisendi töötlemine

#include <stdio.h>
#include <string.h>

int main() {
    char str[100];

    printf("Sisesta lause: ");
    fgets(str, sizeof(str), stdin);
    str[strcspn(str, "\n")] = '\0';

    printf("Sisestatud lause: %s\n", str);
    return 0;
}

Põhipunktid:

  • Funktsioon fgets võimaldab turvaliselt sisestada ka tühikuid sisaldavat teksti.
  • Reavahetuse eemaldamine tagab korrektse väljundi.

Kasutusnäide:

Sisesta lause: Hello World with spaces
Sisestatud lause: Hello World with spaces

6-3. Erimärkide ja escape-seeriatega töötlemine

Näide erimärkidega sisendist

C-keeles tuleb mõnikord töödelda ka sisendeid, mis sisaldavad erimärke või escape-seeriaid.

Näide 3: Erimärkide loendamine

#include <stdio.h>
#include <string.h>
#include <ctype.h>

int main() {
    char str[100];
    int specialCharCount = 0;

    printf("Sisesta string: ");
    fgets(str, sizeof(str), stdin);
    str[strcspn(str, "\n")] = '\0';

    for (int i = 0; str[i] != '\0'; i++) {
        if (!isalnum(str[i]) && !isspace(str[i])) {
            specialCharCount++;
        }
    }

    printf("Erimärkide arv: %d\n", specialCharCount);
    return 0;
}

Põhipunktid:

  • isalnum kontrollib, kas märk on täht või number.
  • isspace kontrollib, kas märk on tühik.
  • Muud märgid loetakse erimärkideks.

Kasutusnäide:

Sisesta string: Hello, World! 123
Erimärkide arv: 2

6-4. Laiendus: lihtne märkmiku programm

Lõpetuseks toome näite programmist, mis kombineerib mitmerealise sisendi ja faili salvestamise.

Näide 4: Märkmiku programm

#include <stdio.h>
#include <string.h>

#define MAX_LINES 5
#define MAX_LENGTH 100

int main() {
    char lines[MAX_LINES][MAX_LENGTH];

    printf("Saad sisestada kuni %d rida.\n", MAX_LINES);
    for (int i = 0; i < MAX_LINES; i++) {
        printf("%d. rida: ", i + 1);
        fgets(lines[i], sizeof(lines[i]), stdin);
        lines[i][strcspn(lines[i], "\n")] = '\0';
    }

    FILE *file = fopen("memo.txt", "w");
    if (file == NULL) {
        printf("Faili ei õnnestunud avada.\n");
        return 1;
    }

    for (int i = 0; i < MAX_LINES; i++) {
        fprintf(file, "%s\n", lines[i]);
    }

    fclose(file);
    printf("Märge salvestatud.\n");
    return 0;
}

Põhipunktid:

  • Kasutaja sisend salvestatakse faili.
  • Praktiline näide failitöötluse õppimiseks.

7. Korduma kippuvad küsimused (K&V vormis)

K1: Miks ei tohiks kasutada gets funktsiooni?

V:
gets loeb stringi ilma pikkust piiramata, mis tekitab puhvri ületäitumise riski. See turvanõrkus võib põhjustada tõsiseid probleeme, mistõttu eemaldati see C11 standardist. Soovitatav on kasutada turvalist fgets-i.

Näide (turvaline alternatiiv):

char str[50];
fgets(str, sizeof(str), stdin);
str[strcspn(str, "\n")] = '\0';  // Eemalda reavahetus

K2: Miks scanf ei saa töödelda tühikuid sisaldavat sisendit?

V:
scanf käsitleb tühikuid, tabulaatoreid ja reavahetusi eraldajatena, mistõttu string katkeb esimese tühiku juures.

Näide:
Sisend:

Hello World

Väljund:

Hello

Lahendus:
Kui sisend sisaldab tühikuid, kasuta fgets-i.

char str[100];
fgets(str, sizeof(str), stdin);
str[strcspn(str, "\n")] = '\0';
printf("Sisestatud string: %s\n", str);

K3: Mis juhtub, kui fgets sisend ületab puhvri suuruse?

V:
fgets loeb ainult määratud suuruse ulatuses. Kui sisend on liiga pikk, kärbitakse seda.

Lahendus:

  1. Rakenda vigade käsitlemist, et kuvada hoiatus või lubada uus sisend.
  2. Kasuta getline funktsiooni, mis eraldab mälu dünaamiliselt (ainult POSIX keskkonnas).

Näide getline-iga:

#include <stdio.h>
#include <stdlib.h>

int main() {
    char *line = NULL;
    size_t len = 0;
    printf("Sisesta string: ");
    getline(&line, &len, stdin);
    printf("Sisestatud string: %s", line);
    free(line);
    return 0;
}

K4: Kuidas eemaldada fgets-i jäetud reavahetus?

V:
fgets lisab reavahetuse märgi, mis võib põhjustada ootamatu tühja rea.

Lahendus:
Eemalda see käsitsi.

char str[100];
fgets(str, sizeof(str), stdin);
str[strcspn(str, "\n")] = '\0';
printf("Sisestatud string: %s\n", str);

K5: Kuidas puhastada ülejäänud sisendit, kui fgets ei mahuta kogu stringi?

V:
Kui sisend ületab puhvri, jäävad ülejäänud tähemärgid sisendpuhvrisse. Selle saab puhastada getchar-iga.

Näide:

char str[10];
fgets(str, sizeof(str), stdin);

if (strchr(str, '\n') == NULL) {
    int c;
    while ((c = getchar()) != '\n' && c != EOF);
}

printf("Sisestatud string: %s\n", str);

K6: Kuidas lubada ainult tähed ja numbrid?

V:
Rakenda sisendi filtreerimine ja luba ainult sobivad märgid.

Näide:

#include <stdio.h>
#include <ctype.h>
#include <string.h>

int isValidInput(const char *str) {
    for (int i = 0; str[i] != '\0'; i++) {
        if (!isalnum(str[i])) {
            return 0;
        }
    }
    return 1;
}

int main() {
    char str[50];
    printf("Sisesta ainult tähed ja numbrid: ");
    fgets(str, sizeof(str), stdin);
    str[strcspn(str, "\n")] = '\0';

    if (isValidInput(str)) {
        printf("Kehtiv sisend: %s\n", str);
    } else {
        printf("Vigane sisend.\n");
    }
    return 0;
}

K7: Kuidas töödelda väga pikki stringe, mis ületavad puhvri suuruse?

V:
fgets puhul tuleb string jagada mitmeks osaks või kasutada getline-i, mis eraldab mälu dünaamiliselt ja sobib pikkade sisendite jaoks.

Näide:
getline võimaldab lugeda suurt hulka andmeid ilma mälupiiranguteta.

8. Kokkuvõte

Selles artiklis selgitasime C-keele stringi sisestamist alates põhialustest kuni edasijõudnud kasutuseni. Õppisime, kuidas valida sobivaid funktsioone ja rakendada praktilisi tehnikaid, et hallata stringe turvaliselt ja tõhusalt.

1. Stringi sisestamise põhialused

C-keeles esitatakse string tähemärgi massiivina ja see lõpeb lõpetava märgiga \0. Selle põhimõtte mõistmine on aluseks stringide töötlemisele.

2. Sisestusfunktsioonide omadused ja valik

  • scanf: Ei toeta tühikuid ja võib põhjustada puhvri ületäitumise riski.
  • fgets: Võimaldab määrata sisendi suuruse ja töödelda turvaliselt ka tühikuid. Vajalik on reavahetuse eemaldamine.
  • getline: Dünaamilise mälu kasutus, sobib suurte sisendite jaoks (ainult POSIX keskkonnas).

3. Turvalise sisendi praktika

Turvalisuse suurendamiseks õppisime:

  1. Puhvri suuruse kontroll: Väldi liiga suuri sisendeid.
  2. Reavahetuse eemaldamine: Hoia sisend puhtana.
  3. Sisendi valideerimine: Kontrolli andmeid ja rakenda vigade käsitlemist.

Tänu sellele saab kirjutada töökindlamaid ja turvalisemaid programme.

4. Praktiliste näidete kaudu oskuste tugevdamine

Mitmerealine sisend ja failide kirjutamine andsid kogemuse praktiliste programmide loomiseks. Kasutades kahemõõtmelisi massiive või dünaamilist mälu, saab ehitada keerukamaid rakendusi.

5. Korduvate probleemide lahendamine

K&V jaotis käsitles sagedasi küsimusi, sealhulgas:

  • gets funktsiooni ohtlikkus ja alternatiivid (fgets, getline).
  • Tühikute ja erimärkide käsitlemine.
  • Puhvri ületäitumise vältimine ja reavahetuse eemaldamine.

6. Järgmised sammud ja laiendatud õppimine

Stringi sisestamise mõistmine loob aluse järgmistele teemadele:

  1. Stringi teekide kasutamine: Funktsioonid nagu strlen, strcmp, strcpy.
  2. Dünaamiline mälu haldus: malloc, realloc paindlikuks stringide töötlemiseks.
  3. Failide sisend/väljund: Suurte andmekoguste töötlemine failides.
  4. Andmestruktuurid ja algoritmid: Otsingu- ja sorteerimisalgoritmide rakendamine stringidega.

7. Praktilised ülesanded õppimiseks

Õpitu kinnistamiseks võite proovida järgmisi ülesandeid:

  1. Ülesanne 1: Loo nimekirjahaldussüsteem mitmerealise sisendiga (nt nimi ja vanus).
  2. Ülesanne 2: Kirjuta programm, mis otsib stringidest kasutaja antud märksõna.
  3. Ülesanne 3: Ehita logisüsteem, mis salvestab sisendi faili ja võimaldab hiljem andmeid lugeda.

Kokkuvõtte kokkuvõte

Selles artiklis käsitlesime C-keele stringi sisestamist nii teoorias kui praktikas.
Olulisemad punktid:

  • Turvalisus: Kasuta fgets või getline ohtlike funktsioonide asemel.
  • Puhvri ja vigade käsitlemine: Kontrolli sisendi suurust ja filtreeri andmeid.
  • Praktiline rakendamine: Mitmerealised sisendid ja failidega töötamine.

Kui need põhimõtted on omandatud, on võimalik edasi liikuda keerukamate programmide ja professionaalse arenduse poole.

年収訴求