C-keelt õppides on kasutaja sisendi käsitlemine ehk “standardne sisend” vältimatu ja väga oluline funktsioon. Standardse sisendi õige mõistmine ja turvaline kasutamine võimaldab oluliselt parandada programmi paindlikkust ja töökindlust. Selles artiklis selgitame süsteemselt standardse sisendi kasutamist C-keeles – alustades põhialustest ja lõpetades rakenduslike näidetega. Ka algajatele arusaadavuse tagamiseks lisame näidiskoodi, et saaksite õpitut kohe oma programmide arenduses rakendada.
Standardse sisendi olulisus
Standardne sisend on programmide jaoks põhiline mehhanism andmete vastuvõtmiseks väljastpoolt. Seda kasutatakse näiteks järgmistes olukordades:
Arvutusäpp, mis kasutab kasutaja sisestatud numbreid
Otsingufunktsioon, mis kasutab tekstistringe
Dünaamilised programmid, mis reageerivad käsurealt antud käskudele
Sellistes olukordades võimaldab standardse sisendi õige käsitlemine luua tõhusaid ja turvalisi programme.
Mida selles artiklis õpid
Selles artiklis käsitleme järgmisi teemasid:
Standardse sisendi põhimõte ja selle teostus C-keeles
scanf ja fgets funktsioonide kasutamine
Kuidas rakendada turvalist ja töökindlat sisendi töötlemist
Edasijõudnutele mõeldud andmetöötluse tehnikad
Levinumad probleemid ja nende lahendused
Kellele see artikkel on mõeldud
Algajad, kes õpivad C-keelt esimest korda
Programmeerijad, kes ei tunne end kindlalt standardse sisendi kasutamisel
Need, kes soovivad luua turvalist ja tõhusat sisenditöötlust
2. Mis on standardne sisend
Standardne sisend C-keeles on põhiline mehhanism, mille kaudu programm saab andmeid välisest allikast. See on osa “standardsest sisendist ja väljundist” ning võimaldab kasutajal anda programmile andmeid terminali või käsurea kaudu. Selles jaotises selgitame standardse sisendi põhikontseptsiooni ja rolli.
Standardse sisendi määratlus
Standardne sisend (Standard Input, stdin) viitab andmevoole, mida programm kasutab andmete vastuvõtmiseks väljastpoolt. C-keeles saab standardset sisendit hõlpsasti kasutada stdio.h teegi abil.
Andmeid sisestatakse tavaliselt klaviatuuri kaudu.
Sisestatud andmeid töödeldakse programmis ning tulemused väljastatakse standardväljundisse.
Standardse sisendi ja väljundi mehhanism
C-keeles on saadaval kolm standardvoogu:
Standardne sisend (stdin): andmete vastuvõtmiseks väljastpoolt.
Standardne väljund (stdout): programmide tulemuste väljastamiseks.
Järgmine näide võtab standardse sisendi kaudu arvu ja väljastab selle standardväljundisse.
#include <stdio.h>
int main() {
int number;
printf("Sisesta arv: ");
scanf("%d", &number); // loe täisarv standardse sisendi kaudu
printf("Sisestatud arv on: %d\n", number); // väljasta standardväljundisse
return 0;
}
Standardse sisendi roll ja olulisus
Standardset sisendit kasutatakse järgmistes programmides:
Andmetöötlusprogrammid: numbrite või tekstistringide sisestamine ja nende põhjal arvutuste või analüüside tegemine.
Interaktiivsed rakendused: programmi töö muutmine vastavalt kasutaja käskudele.
Dünaamiline andmete töötlemine: kasutaja sisestatud andmete reaalajas töötlemine.
Standardse sisendi eelised
Paindlikkus: toetab erinevaid sisendiallikaid, nagu klaviatuur, torud ja ümbersuunamine.
Lihtsus: sisseehitatud funktsioonide scanf ja fgets abil on sisendi töötlemine lihtne.
3. Standardse sisendi põhitõed C-keeles
C-keeles on kasutajal andmete sisestamiseks saadaval mitu funktsiooni. Kõige tavalisemad on scanf ja fgets. Selles jaotises selgitame, kuidas kumbagi kasutada koos näidetega.
scanf funktsiooni kasutamine
scanf on funktsioon, mis analüüsib sisestatud andmeid vormingutunnuste abil ja salvestab need muutujatesse.
Põhisüntaks
int scanf(const char *format, ...);
format: määrab andmete vormingu stringina.
...: muutujate aadressid, kuhu sisestatud väärtused salvestatakse.
Peamised vormingutunnused
Tunnus
Selgitus
Näide
%d
Täisarv
42
%f
Koma-arv (ujukomaarv)
3.14
%c
Üks märk
A
%s
Sõnestring
Hello
Kasutusnäide
#include <stdio.h>
int main() {
int age;
printf("Sisesta oma vanus: ");
scanf("%d", &age); // loeb täisarvu
printf("Sisestatud vanus on: %d\n", age);
return 0;
}
Tähelepanekud
Kui andmeid ei sisestata õiges vormingus, võib tekkida vigu.
Oluline on piirata sisendi suurust, et vältida puhvermäluga seotud ületäitumisi (nt %s kasutamisel).
fgets funktsiooni kasutamine
fgets loeb sisendi ridade kaupa ja seda peetakse turvalisemaks kui scanf.
Põhisüntaks
char *fgets(char *str, int n, FILE *stream);
str: massiiv, kuhu sisend salvestatakse.
n: maksimaalne loetavate märkide arv (massiivi suurus).
stream: sisendi allikas (tavaliselt stdin).
Kasutusnäide
#include <stdio.h>
int main() {
char name[50];
printf("Sisesta oma nimi: ");
fgets(name, 50, stdin); // loeb kuni 49 märki
printf("Sisestatud nimi on: %s", name);
return 0;
}
Tähelepanekud
Kui sisestatud tekst ületab puhversuuruse, siis ülejäänud osa kärbitakse.
Kui sisendis on reavahetus, tuleb see käsitsi eemaldada.
Kuidas eemaldada reavahetusmärk
name[strcspn(name, "\n")] = '\0';
scanf ja fgets võrdlus
Omadus
scanf
fgets
Kasutus
Arvude või stringide lugemine kindla vormingu järgi
Tekstirea lugemine tervikuna
Turvalisus
Võib põhjustada puhvrimälu ületäitumist
Võimaldab kontrollida puhversuurust
Paindlikkus
Toetab vormingutunnuseid
Loeb kogu sisendi stringina
Kumb valida?
Kui kasutada scanf: sobib, kui on vaja otse lugeda numbreid või kindlat tüüpi andmeid.
Kui kasutada fgets: sobib, kui tähtis on turvalisus ja sisend võib olla pikk või keeruline.
4. Turvaline standardse sisendi kasutamine
Standardse sisendi töötlemisel C-keeles on turvalisuse tagamine äärmiselt oluline. Valesti teostatud sisend võib põhjustada puhvrimälu ületäitumisi või määratlemata käitumist ning vähendada programmi töökindlust. Selles jaotises käsitleme, kuidas standardset sisendit turvaliselt rakendada, koos praktiliste näidetega.
Kuidas vältida puhvrimälu ületäitumist
scanf on mugav, kuid ilma sisendi suurust piiramata võib tekkida puhvrimälu ületäitumine. Selle vältimiseks tuleb määrata maksimaalne sisendisuurus vormingutunnuses.
Näide sisendi piiramise kohta
#include <stdio.h>
int main() {
char input[10];
printf("Sisesta string (kuni 9 märki): ");
scanf("%9s", input); // loeb kuni 9 märki
printf("Sisestatud string: %s\n", input);
return 0;
}
Olulised punktid
Kasutades nt %9s, saab piirata sisendi pikkust ja vältida massiivi ületamist.
Turvaliseks sisendiks kasuta fgets
fgets võimaldab määrata loetavate märkide arvu, vähendades sellega puhvrimälu ületäitumise riski. See sobib eriti hästi pikkade stringide või terve rea lugemiseks.
sizeof(buffer) abil saab puhversuuruse määrata automaatselt.
strcspn funktsiooni abil eemaldatakse sisendist reavahetusmärk.
Sisendandmete kontrollimine
Et tagada turvaline sisendi töötlemine, tuleb kasutaja sisestatud andmeid alati kontrollida. Näiteks kui eeldatakse täisarvu sisestamist, tasub sisend esmalt lugeda stringina ning seejärel teha teisendus ja vigade kontroll.
strtol võimaldab avastada teisenduse käigus tekkivaid vigu.
errno ja endptr koos annavad teada, kas teisendustulemus oli korrektne.
Vigade käsitlemise parimad tavad
Standardse sisendi töötlemisel on korrektne veakontroll võtmetähtsusega töökindluse tagamiseks.
Näide veakontrollist
#include <stdio.h>
int main() {
int value;
printf("Sisesta täisarv: ");
if (scanf("%d", &value) != 1) { // kui sisend ebaõnnestub
printf("Sisend on vigane.\n");
return 1; // lõpetab veaga
}
printf("Sisestatud täisarv: %d\n", value);
return 0;
}
Olulised punktid
Tuleb kontrollida scanf tagastusväärtust ja teha veakäsitlus, kui sisend ei vasta oodatud vormingule.
Turvalise sisenditöötluse kokkuvõte
scanf kasutamisel tuleb alati piirata sisendi suurust vormingutunnusega.
Pikemate stringide või rea kaupa sisendi jaoks kasuta fgets.
Ära usalda pimesi kasutaja sisendit – tee alati kontroll ja veakäsitlus.
5. Standardse sisendi rakenduslik kasutamine
Kui oled õppinud standardse sisendi põhitõed, tasub edasi liikuda keerukamate kasutusjuhtude juurde. See võimaldab töödelda mitmekesisemaid sisendandmeid ja olukordi. Selles jaotises käsitleme näiteks mitme väärtuse korraga sisestamist ning reavahetuste ja tühikute käsitlemist.
Mitme andme sisestamine korraga
Sageli tuleb töödelda mitut väärtust, mis sisestatakse standardse sisendi kaudu. Allpool on toodud näited, kuidas lugeda andmeid, mis on eraldatud tühikute või komadega.
Näide tühikuga eraldatud sisendist
#include <stdio.h>
int main() {
int numbers[5];
printf("Sisesta 5 täisarvu, eraldades need tühikutega: ");
for (int i = 0; i < 5; i++) {
scanf("%d", &numbers[i]); // loeb tühikuga eraldatud arvud
}
printf("Sisestatud arvud: ");
for (int i = 0; i < 5; i++) {
printf("%d ", numbers[i]);
}
printf("\n");
return 0;
}
Näide komaga eraldatud sisendist
#include <stdio.h>
int main() {
int numbers[3];
printf("Sisesta 3 täisarvu, eraldades need komadega: ");
scanf("%d,%d,%d", &numbers[0], &numbers[1], &numbers[2]); // loeb komaga eraldatud arvud
printf("Sisestatud arvud: %d, %d, %d\n", numbers[0], numbers[1], numbers[2]);
return 0;
}
Sisendi käsitlemine, mis sisaldab reavahetusi ja tühikuid
Standardse sisendi korral võib sisendis olla nii reavahetusi kui ka tühikuid. Järgnevalt vaatame, kuidas neid õigesti töödelda.
Näide reavahetuse käsitlemisest
Kui sisendis on reavahetus, saab seda töödelda kasutades fgets funktsiooni ning eemaldades reavahetuse käsitsi.
Mõnikord on vaja lugeda mitut rida järjest ja töödelda neid ükshaaval. Seda kasutatakse näiteks tekstianalüüsis ja andmetöötluses.
Näide mitmerealisest sisendist
#include <stdio.h>
int main() {
char line[100];
printf("Sisesta mitu tekstirida (lõpetamiseks vajuta Ctrl+D):\n");
while (fgets(line, sizeof(line), stdin) != NULL) {
printf("Sisestatud rida: %s", line);
}
return 0;
}
Dünaamilise sisendi töötlemine
Kui sisendandmete arv ei ole ette teada, tuleb neid töödelda dünaamiliselt. Järgmises näites sisestatakse tundmatu arv täisarve ja arvutatakse nende summa.
Näide dünaamilise sisendi töötlemisest
#include <stdio.h>
int main() {
int number, sum = 0;
printf("Sisesta täisarve (lõpetamiseks vajuta Ctrl+D):\n");
while (scanf("%d", &number) == 1) {
sum += number;
}
printf("Sisestatud arvude summa: %d\n", sum);
return 0;
}
Kokkuvõte
Rakenduslike sisenditöötluse tehnikate abil saab luua programme, mis töötlevad keerulisemaid andmeid ja kohanduvad dünaamiliste olukordadega. Kui harjuda mitme andme korraga lugemise ja reavahetuste käsitlemisega, on võimalik luua veelgi arenenumaid programmilahendusi.
6. Levinumad probleemid ja nende lahendused
C-keeles standardse sisendi kasutamisel puutuvad algajad sageli kokku erinevate probleemidega. Allpool on toodud levinumad olukorrad ja nende lahendused, mis aitavad luua töökindlamaid programme.
scanf probleemid ja lahendused
Probleem 1: Sisendi vahelejätmine
scanf kasutamisel võivad reavahetused või tühikud mõjutada järgmist sisendilugemist.
Kui scanf abil loetakse liiga pikk string, võib see puhvrimälu ületada ja põhjustada programmi kokkujooksmise.
Näide
char input[10];
scanf("%s", input); // kui sisend on pikem kui 9 märki, tekib ületäitumine
Lahendus
Piira sisendi pikkust vormingutunnusega.
scanf("%9s", input); // piirab sisendi 9 märgiga
Või kasuta turvalisemat alternatiivi – fgets.
fgets probleemid ja lahendused
Probleem 1: Reavahetuse käsitlemine
fgets lisab sisestuse lõppu reavahetuse märgi, mis võib põhjustada ootamatut käitumist stringivõrdluse või andmete töötlemise ajal.
Näide
char input[20];
fgets(input, sizeof(input), stdin);
if (strcmp(input, "yes") == 0) {
printf("Sisend on 'yes'.\n");
}
Sellisel juhul loetakse stringiks "yes\n" ning võrdlus ebaõnnestub.
Lahendus
Eemalda reavahetuse märk.
input[strcspn(input, "\n")] = '\0';
Sisendvigade käsitlemine
Probleem 1: Vigane sisend
Kui oodatakse täisarvu, aga sisestatakse hoopis string, võib programm töötada valesti.
Näide
int number;
scanf("%d", &number); // kui sisestatakse tekst, võib programm käituda valesti
Lahendus
Kontrolli alati sisendi kehtivust.
if (scanf("%d", &number) != 1) {
printf("Vigane sisend.\n");
while (getchar() != '\n'); // puhasta sisendipuhver
}
Mitmerealise sisendi probleemid
Probleem: scanf ja fgets segakasutus
Kui programmis kasutatakse nii scanf kui ka fgets, võib tekkida ootamatu käitumine.
Põhjus
scanf jätab reavahetuse sisendipuhvrisse, mistõttu järgmine fgets loeb selle kohe ära.
Lahendus
Puhasta sisendipuhver pärast scanf kasutamist.
while (getchar() != '\n');
Kokkuvõte
C-keeles standardse sisendi kasutamisel on mitmeid ohukohti, kuid kui mõista probleemide põhjuseid ja neid õigesti lahendada, on võimalik kirjutada turvalisi ja tõhusaid programme. Eriti oluline on mõista scanf ja fgets erinevusi ning valida vastavalt vajadusele sobiv meetod.
7. Näited standardse sisendi kasutamisest
Siin toome praktilised näited, kuidas standardset sisendit kasutada erinevates olukordades – alates lihtsatest juhtumitest kuni veidi keerukamate lahendusteni.
Näide 1: Arvude summa ja keskmise leidmine
Programm võtab mitu täisarvu standardse sisendi kaudu ning arvutab nende summa ja keskmise.
#include <stdio.h>
int main() {
int numbers[100];
int count = 0, sum = 0;
float average;
printf("Sisesta täisarve, eralda need tühikutega (lõpetamiseks vajuta Ctrl+D):\n");
while (scanf("%d", &numbers[count]) == 1) {
sum += numbers[count];
count++;
}
if (count > 0) {
average = (float)sum / count;
printf("Summa: %d, Keskmine: %.2f\n", sum, average);
} else {
printf("Ühtegi arvu ei sisestatud.\n");
}
return 0;
}
Näide 2: Palindroomi kontroll
Programm kontrollib, kas sisestatud string on palindroom (loe sama nii eest- kui tagantpoolt).
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
bool isPalindrome(char str[]) {
int start = 0;
int end = strlen(str) - 1;
while (start < end) {
if (str[start] != str[end]) {
return false;
}
start++;
end--;
}
return true;
}
int main() {
char input[100];
printf("Sisesta string: ");
fgets(input, sizeof(input), stdin);
// eemalda reavahetus
input[strcspn(input, "\n")] = '\0';
if (isPalindrome(input)) {
printf("Sisestatud string on palindroom.\n");
} else {
printf("Sisestatud string ei ole palindroom.\n");
}
return 0;
}
Näide 3: CSV-andmete töötlemine
Programm loeb komaga eraldatud väärtusi ja töötleb neid ükshaaval.
Rakenduslikud näited standardse sisendi kasutamisest aitavad mõista, kuidas luua interaktiivseid ja praktilisi programme. Kasuta neid näiteid inspiratsiooniks ning kohanda neid vastavalt oma projektide vajadustele.
8. Kokkuvõte
Selles artiklis selgitasime standardse sisendi kasutamist C-keeles alates põhitõdedest kuni rakenduslike näideteni. Loodetavasti mõistad nüüd paremini, kuidas standardne sisend töötab, kuidas seda turvaliselt kasutada ja kuidas seda praktikas rakendada.
Standardse sisendi olulisuse kordamine
Standardne sisend on põhiline viis, kuidas programm saab andmeid väljastpoolt ja töötab dünaamiliselt.
C-keeles saab kasutada scanf ja fgets funktsioone numbrite ja stringide lugemiseks.
Turvalise ja tõhusa sisendi töötlemise põhipunktid
Väldi puhvrimälu ületäitumist
Kasuta scanf puhul sisendi pikkuse piiranguid (nt %9s).
Pikemate stringide või ridade lugemiseks kasuta fgets.
Sisendi valideerimine
Numbrilise sisendi korral kasuta strtol või strtod ning kontrolli vigu.
Vigase sisendi korral rakenda korrektset veakäsitlust.
Rakenduslikud tehnikad
Mitme andme korraga lugemisel ja reavahetuste töötlemisel kasuta õigeid meetodeid.
Järgmised sammud
Kui oled omandanud standardse sisendi põhitõed, saad oma oskusi täiendada järgmiste sammudega:
Standardne väljund ja veaväljund: õpi, kuidas väljastada veateateid ja logisid.
Failide töötlemine: kombineeri failisisend standardse sisendiga, et luua keerukamaid programme.
Praktilised ülesanded: loo ise väikseid projekte, võttes eeskujuks artiklis toodud näiteid.
Sõnum lugejale
Standardne sisend on C-keele programmeerimise üks alustalasid, kuid samas ka sügav teema. Selle artikli abil loodetavasti mõistad, kuidas sisendit turvaliselt ja tõhusalt töödelda. Õpi samm-sammult, lahenda väikeseid küsimusi ja liigu järk-järgult edasi – see on kindel tee programmeerimisoskuste arendamiseks.