C-keel lõputu tsükkel: while, for ja do-while näited ning ohutu kasutamine

目次

1. Sissejuhatus: Mis on lõputu tsükkel C keeles?

Lõputu tsükkel C-keeles on põhiline juhtimisstruktuur, mis kordab käskude täitmist seni, kuni teatud tingimus on täidetud. Lõputult kestev tsükkel mängib olulist rolli programmide funktsioonides, näiteks süsteemi pidevas jälgimises või kasutaja sisendi ootamises.

Selles artiklis selgitame üksikasjalikult, kuidas C-keeles lõputuid tsükleid rakendada: alustades põhilisest süntaksist, liikudes praktiliste näidete ja probleemide lahendamiseni. Sihtgrupiks on algajad kuni kesktaseme programmeerijad ning kasutame selgitustes ka näidis­koode.

2. Lõputu tsükli põhisüntaks C keeles

2.1 Lõputu tsükkel kasutades while-lauset

while-lause kordab käske seni, kuni tingimus on tõene. See on üks kõige sagedamini kasutatavaid viise lõputu tsükli rakendamiseks.

Koodinäide

#include <stdio.h>

int main() {
    while (1) { // 1 tähendab alati tõene
        printf("See tsükkel kordub lõputult\n");
    }
    return 0;
}

See kood kuvab sõnumi „See tsükkel kordub lõputult” seni, kuni programm lõpetatakse.

Punktid

  • Kuna tingimus on alati tõene, muutub tsükkel lõputuks.
  • Kasutades tingimuses muutujat, saab lisada dünaamilisi lõpetamistingimusi.

2.2 Lõputu tsükkel kasutades for-lauset

for-lausega saab samuti teha lõputu tsükli. Kui lähtestamine, tingimuse kontroll ja uuendamine ära jätta, tekib lõputu tsükkel.

Koodinäide

#include <stdio.h>

int main() {
    for (;;) { // ilma tingimuseta lõputu tsükkel
        printf("See tsükkel kordub samuti lõputult\n");
    }
    return 0;
}

Punktid

  • for (;;) väljendab lõputut tsüklit lühidalt ja selgelt.
  • Kuigi for-lause on tavaliselt mõeldud korduste arvule, saab seda kasutada ka lõputute tsüklite jaoks.

2.3 Lõputu tsükkel kasutades do-while lauset

do-while-lause täidab kõigepealt käsud vähemalt korra ja kontrollib seejärel tingimust.

Koodinäide

#include <stdio.h>

int main() {
    do {
        printf("See tsükkel kordub samuti lõputult\n");
    } while (1); // tingimus on alati tõene
    return 0;
}

Punktid

  • Sobib siis, kui on vaja vähemalt üht käivitamist enne tingimuse kontrolli.
  • Tingimus kontrollitakse pärast käsu täitmist, seega töökorraldus erineb while-lausest.
侍エンジニア塾

3. Lõputu tsükli praktilised kasutusnäited

3.1 Kasutaja sisendi ootamise programm

Allpool on näide programmist, mis ootab pidevalt kasutaja sisendit.

Koodinäide

#include <stdio.h>

int main() {
    char input[100];
    while (1) {
        printf("Sisesta väärtus: ");
        scanf("%s", input);
        if (strcmp(input, "exit") == 0) { // kui sisend on "exit", lõpetatakse
            break;
        }
        printf("Sisestatud väärtus: %s\n", input);
    }
    return 0;
}

Selgitus

  • scanf-funktsioon loeb kasutaja sisendi ja jätkab tsüklit seni, kuni sisestatakse “exit”.
  • Kui tingimus on täidetud, katkestatakse tsükkel break-lausena.

3.2 Serveri jälgimise tsükkel

Allpool on näide süsteemist, mis kontrollib regulaarselt serveri olekut.

Koodinäide

#include <stdio.h>
#include <unistd.h> // vajalik sleep-funktsiooni jaoks

int main() {
    while (1) {
        printf("Serveri jälgimine...\n");
        sleep(5); // oota 5 sekundit
    }
    return 0;
}

Selgitus

  • sleep-funktsiooni abil reguleeritakse tsükli intervalli ja vähendatakse CPU koormust.
  • Seda tüüpi lõputuid tsükleid kasutatakse sageli süsteemi halduses ja monitooringutööriistades.

3.3 Näide mängutsüklist

Mängude põhitsüklis korratakse töötlust iga kaadri kohta.

Koodinäide

#include <stdio.h>
#include <stdbool.h>

int main() {
    bool running = true; // mängu oleku juhtimine
    int count = 0;

    while (running) {
        // mängu loogika töötlus
        printf("Mäng töötab...\n");

        // Kasutaja lõpetamiskäsk (nt klaviatuuri sisend)
        char command;
        printf("Sisesta 'q' lõpetamiseks: ");
        scanf(" %c", &command);
        if (command == 'q') {
            running = false;
        }
    }
    printf("Mäng lõppenud\n");
    return 0;
}

Selgitus

  • Lipu-muutuja running abil juhitakse tsükli seisu.
  • Tingimuse korral saab tsükli ohutult lõpetada.

4. Lõputu tsükli juhtimise meetodid

4.1 Tsükli lõpetamine break-lausena

break-lause katkestab tsükli sunniviisiliselt. Seda kasutatakse siis, kui soovitakse tsüklist väljuda kindla tingimuse täitmisel.

Koodinäide: lõpetamine kasutaja sisendi põhjal

#include <stdio.h>

int main() {
    int input;
    while (1) {
        printf("Sisesta number (0 lõpetamiseks): ");
        scanf("%d", &input);
        if (input == 0) { // kui sisend on 0, lõpetatakse
            break;
        }
        printf("Sisestatud number: %d\n", input);
    }
    printf("Programm lõpetatud\n");
    return 0;
}

Selgitus

  • Kui tingimus input == 0 on tõene, katkestab break-lause tsükli kohe.
  • Kui tingimus on väär, jätkub tsükkel.

4.2 continue-lausena töötlemise vahelejätmine

continue-lause jätab tsükli käesoleva iteratsiooni ülejäänud käsud vahele ja liigub järgmise korduseni. Kasulik siis, kui soovitakse teatud tingimusi välistada.

Koodinäide: ainult paarisarvude kuvamine

#include <stdio.h>

int main() {
    for (int i = 1; i <= 10; i++) {
        if (i % 2 != 0) { // kui paaritu, jäta vahele
            continue;
        }
        printf("%d on paarisarv\n", i);
    }
    return 0;
}

Selgitus

  • Kui tingimus i % 2 != 0 on tõene, kasutatakse continue-lauset ja see kordus vahele jäetakse.
  • Näiteks kuvatakse ainult paarisarvud.

4.3 Lipumuutujaga juhtimine

Lipumuutujaga saab lõputule tsüklile lisada paindlikke lõpetamistingimusi. See on eriti kasulik keerukamate tingimustega programmides.

Koodinäide: lõpetamise juhtimine lipumuutujaga

#include <stdio.h>
#include <stdbool.h> // vajalik bool-tüübi jaoks

int main() {
    bool running = true; // lipumuutuja
    int count = 0;

    while (running) {
        printf("Loendus: %d\n", count++);
        if (count >= 5) { // kui loendus jõuab 5-ni, lõpetatakse
            running = false;
        }
    }
    printf("Tsükkel lõpetatud\n");
    return 0;
}

Selgitus

  • Lipumuutuja running juhib tsükli jätkumist või lõpetamist.
  • Muutes lipu väärtust, saab tingimusi paindlikult juhtida.

4.4 Tingimusliku tsükli disaini näide

Praktilistes olukordades on sageli vaja tsükli juhtimiseks mitut tingimust kombineerida.

Koodinäide: ajapiiranguga tsükkel

#include <stdio.h>
#include <time.h> // vajalik ajafunktsioonide jaoks

int main() {
    time_t start = time(NULL); // algusaja salvestamine
    int count = 0;

    while (1) { // lõputu tsükkel
        printf("Loendus: %d\n", count++);
        if (difftime(time(NULL), start) > 10) { // lõpetamine pärast 10 sekundi möödumist
            break;
        }
    }
    printf("10 sekundit möödus. Lõpetamine.\n");
    return 0;
}

Selgitus

  • time()-funktsiooniga saadakse algusaeg ja difftime()-funktsiooniga arvutatakse möödunud aeg.
  • Aja põhjal saab tsüklist väljuda ja luua ajapiiranguga programme.

5. Tähelepanekud: lõputu tsükli probleemid ja lahendused

5.1 Suurenenud CPU koormus

Kui lõputu tsükkel töötab väga kiiresti, võib CPU kasutus jõuda 100%-ni ja kogu süsteemi jõudlus väheneb. See on eriti tõsine probleem piiratud ressurssidega manussüsteemides.

Probleemi näide

while (1) {
    // mõttetu kordus ilma töötluseta
}

See kood kordab tühikäigul töötlemist ja kulutab liigseid CPU ressursse.

Lahendus: kasuta sleep-funktsiooni
CPU koormuse vähendamiseks on oluline lisada tsüklisse ootamisaeg.

Parandatud koodinäide

#include <stdio.h>
#include <unistd.h> // vajalik sleep-funktsiooni jaoks

int main() {
    while (1) {
        printf("Jälgin...\n");
        sleep(1); // oota 1 sekund
    }
    return 0;
}

Punktid

  • sleep()-funktsiooni abil saab vähendada tsükli tihedust ja hoida CPU koormust madalal.
  • Manussüsteemides on efektiivsem kasutada usleep()-i või taimerit millisekundite täpsusega.

5.2 Programmi hangumine või mittereageerimine

Kui lõputu tsükkel ei sisalda lõpetamistingimust, võib programm hanguda ega võta enam kasutaja sisendit või väliseid käske vastu.

Probleemi näide

while (1) {
    // puudub lõpetamistingimus
}

See kood töötab lõputult, kuni programm sunniviisiliselt katkestatakse.

Lahendus: lisa lõpetamistingimus
Parandatud koodinäide

#include <stdio.h>

int main() {
    int count = 0;
    while (count < 5) {
        printf("Loendus: %d\n", count);
        count++; // suurenda loendurit
    }
    return 0;
}

Väljund

Loendus: 0
Loendus: 1
Loendus: 2
Loendus: 3
Loendus: 4

Punktid

  • Oluline on alati uuendada tsüklimuutujat.
  • Lipumuutujate või loendurite kasutamine muudab tingimuste haldamise lihtsamaks ja aitab ka silumisel.

5.3 Silumise raskused

Lõputute tsüklite probleemide põhjuse leidmine on eriti suurtes programmides sageli keeruline. Sageli põhjustavad vigu valed tingimused või välised sisendid. Silumisel on oluline jälgida täpselt tsükli sisemist olekut.

Probleemi näide

int count = 0;
while (count != 10) { // tingimuse viga → lõputu tsükkel
    printf("Loendus: %d\n", count);
}

Kuna count ei muutu, satub programm lõputusse tsüklisse.

Lahendus: lisa logiväljund silumiseks
Parandatud koodinäide

#include <stdio.h>

int main() {
    int count = 0;
    while (count != 10) { // tingimus kontrollitud
        printf("Debug: loendus=%d\n", count); // oleku jälgimine
        count++; // suurenda loendurit
    }
    printf("Lõpetatud\n");
    return 0;
}

Punktid

  • Logiväljundite abil saab jälgida tsükli olekut.
  • Reaalses kasutuses tuleks debug-sõnumid välja kommenteerida või eemaldada.

5.4 Ohutu disain mitme tingimusega

Kui kasutatakse keerulisi tingimusi, tuleb rakendada mitut kontrolli, et tsükkel oleks ohutult juhitav.

Probleemi näide

while (1) {
    // töötamine ilma igasuguse tingimuseta
}

Lahendus: kombineeri mitu tingimust
Parandatud koodinäide

#include <stdio.h>
#include <stdbool.h>
#include <time.h>

int main() {
    bool running = true;
    time_t start = time(NULL);

    while (running) {
        printf("Jälgin...\n");

        // lõpetamine aja möödumise alusel
        if (difftime(time(NULL), start) > 10) { // lõpetamine pärast 10 sek
            running = false;
        }
    }
    printf("Jälgimine lõppenud\n");
    return 0;
}

Punktid

  • Tingimusi saab määrata mitut ja lisada erandeid või lõpetamise reegleid.
  • Aja või loenduri kasutamine võimaldab luua ohutult juhitava tsükli.

6. Praktilised ülesanded ja selgitused

6.1 Koodiviktoriin: ennusta tulemusi

Ülesanne 1: tsükli töö kontroll

Kuidas töötab järgmine kood? Ennusta väljundit.

Koodinäide

#include <stdio.h>

int main() {
    int i = 0;
    for (;;) { // lõputu tsükkel
        printf("%d\n", i++);
        if (i > 5) { // lõpetamise tingimus
            break;
        }
    }
    return 0;
}

Vihjed

  • for (;;) loob lõputu tsükli.
  • i++ suurendab muutujat i ühe võrra.
  • if (i > 5) katkestab tsükli break-lausena.

Vastus ja selgitus

Kood kuvab numbrid 0-st kuni 5-ni ja lõpetab enne 6 kuvamist.

Väljund

0
1
2
3
4
5

Punktid

  • See on põhiline näide, kuidas break-lause abil lõpetada lõputu tsükkel.
  • Pärast tsükli lõppu jätkub programm tavapäraselt.

6.2 Koodi parandamise ülesanne: vea parandamine

Ülesanne 2: tingimuse seadistamise viga

Allolev kood ei lõpeta tsüklit. Leia probleem ja paranda kood.

Koodinäide

#include <stdio.h>

int main() {
    int count = 0;
    while (count < 5) { // tingimuslik tsükkel
        printf("Loendus: %d\n", count);
    }
    return 0;
}

Vihjed

  • Muutuja count ei muutu.
  • Tsükli sees on vaja lisada loenduri suurendamine.

Vastus ja selgitus

Probleem seisneb selles, et count ei muutu ja tingimus jääb igavesti tõeseks. See viib lõputu tsüklini.

Parandatud kood

#include <stdio.h>

int main() {
    int count = 0;
    while (count < 5) {
        printf("Loendus: %d\n", count);
        count++; // suurenda loendurit
    }
    return 0;
}

Väljund

Loendus: 0
Loendus: 1
Loendus: 2
Loendus: 3
Loendus: 4

Punktid

  • Oluline on alati uuendada tsüklimuutujat.
  • Lipumuutujate või loendurite kasutamine on kasulik ka silumisel.

6.3 Rakendusülesanne: ajapiiranguga tsükkel

Ülesanne 3: programm, mis lõpeb teatud aja järel

Järgmine kood töötab 10 sekundit ja lõpetab seejärel. Selgita koodi tööpõhimõtet ja mõtle välja rakendusnäiteid.

Koodinäide

#include <stdio.h>
#include <time.h>

int main() {
    time_t start = time(NULL); // algusaeg
    while (1) { // lõputu tsükkel
        printf("Töötab...\n");

        // lõpetamine ajapiirangu järgi
        if (difftime(time(NULL), start) > 10) { 
            break;
        }
    }
    printf("10 sekundit möödas. Lõpetan.\n");
    return 0;
}

Vastus ja selgitus

Kood kasutab time()-funktsiooni praeguse aja saamiseks ja arvutab difftime()-iga möödunud aja.

Punktid

  • difftime() abil mõõdetakse kulunud aeg ja seega rakendatakse ajapiirang.
  • Rakendusnäidetena sobib näiteks serveri jälgimine või automaattöötlus.

Rakendusnäited

  1. Andmete kogumine andurilt kindla aja järel.
  2. Serveri vastamata jätmisel automaatne korduskatse.

6.4 Vigade käsitlemise ülesanne: ebaõige sisendi tuvastamine

Ülesanne 4: ebaõige sisendi tuvastamine ja tsükli lõpetamine

Paranda allolev kood nii, et ebaõige sisendi korral kuvatakse veateade ja programm lõpetatakse.

Koodinäide

#include <stdio.h>

int main() {
    int number;
    while (1) {
        printf("Sisesta number: ");
        if (scanf("%d", &number) != 1) { // kui sisend pole number
            break;
        }
        printf("Sisestatud number: %d\n", number);
    }
    printf("Tekkis viga. Programm lõpetatud.\n");
    return 0;
}

Selgitus

  • scanf()-i tagastusväärtust kontrollides saab tuvastada ebaõige sisendi.
  • Tõrke töötlemine on oluline turvaliste programmide loomisel.

7. KKK: korduma kippuvad küsimused lõputute tsüklite kohta C keeles

7.1 Põhitõed lõputute tsüklite kohta

K1. Millistes olukordades tuleks kasutada lõputut tsüklit?
Vastus: Lõputuid tsükleid kasutatakse järgmistes olukordades:

  • Serveri jälgimisprogrammid: süsteemi pidev monitoorimine ja vigade tuvastamine.
  • Kasutaja sisendi ootamine: programm ootab pidevalt klaviatuuri või anduri sisendit.
  • Reaalaja töötlus: mängude kaadrite töötlemine või animatsiooni pidev värskendamine.

K2. Miks programm ei reageeri, kui kasutan lõputut tsüklit?
Vastus: Kui lõpetamistingimust pole, jätkab tsükkel lõputult ja programm jääb reageerimatuks.
Selle vältimiseks tuleb lisada lõpetamistingimus, näiteks järgmine:

Näide: lõpetamistingimusega tsükkel

#include <stdio.h>
int main() {
    int count = 0;
    while (1) {
        printf("Loendus: %d\n", count++);
        if (count > 10) { // kui tingimus täidetud
            break;
        }
    }
    return 0;
}

Selle abil saab tsükli turvaliselt katkestada, kasutades break-lauset või lipumuutujat.

K3. Kui palju koormab lõputu tsükkel protsessorit?
Vastus: Kui tsüklis pole ootamisi ega tingimusi, võib CPU kasutus ulatuda 100%-ni.

Lahendus

  • Lisa ootamine tsükli sisse.
#include <unistd.h> // sleep-funktsiooni kasutamiseks
while (1) {
    printf("Jälgin...\n");
    sleep(1); // oota 1 sekund
}
  • Sündmuspõhine disain
    Kasuta sündmusi (nt nuppude vajutamine, võrgusõnumid), et vältida pidevat kontrollimist.

7.2 Küsimused silumise ja vigade töötlemise kohta

K4. Millele pöörata tähelepanu lõputu tsükli silumisel?
Vastus: Olulised punktid on:

  1. Silumislogid
    Lisa tsükli sisse logiväljundid muutujate jälgimiseks.
printf("Debug: x=%d\n", x);
  1. Murdepunkte kasutamine
    Sea tsüklisse murdepunktid ja jälgi käitumist.
  2. Loenduri lisamine
    Piira korduste arvu, et testida tsükli tööd.
if (counter > 100) break;

K5. Mida teha, kui programm ei lõpeta lõputut tsüklit?
Vastus: Seda saab käsitsi lõpetada järgmiselt:

  1. Käsureal/terminalis
  • Vajuta Ctrl + C, et katkestada programm.
  1. IDE-s või editoris
  • Peata töötav protsess stopp-nupuga.
  1. Ülesannete halduri kaudu
  • Ava Task Manager ja lõpeta vastav protsess.

Ennetus
Lisa alati lõpetamistingimused või ajalised katkestused.

7.3 Küsimused lõputu tsükli rakenduste kohta

K6. Kuidas kirjutada efektiivne lõputu tsükkel?
Vastus: Soovitused:

  1. Sündmuspõhine disain
    Kasuta sündmusi (nt nuppude vajutamine, võrguandmete saabumine) pideva kontrolli asemel.
  2. Ajastatud tsüklid
    Kasuta taimerit või sleep()-i, et vähendada CPU koormust.
  3. Ressursside haldus
    Vabasta mälu ja failikäepidemed, et vältida lekkeid.

K7. Kuidas muuta tsükli lõpetamise tingimusi paindlikuks?
Vastus: Kasuta lipumuutujat, et hallata tsükli lõpetamist.

Näide: lipu abil lõpetamine

#include <stdio.h>
#include <stdbool.h>

int main() {
    bool running = true; // lipumuutuja
    int count = 0;

    while (running) {
        printf("Loendus: %d\n", count++);
        if (count > 10) {
            running = false; // muuda lipp ja lõpeta
        }
    }
    printf("Lõpetatud\n");
    return 0;
}

Selle abil saab tsükli lõpetamise tingimusi dünaamiliselt muuta.

8. Kokkuvõte: lõputute tsüklite eelised ja turvaline kasutamine

8.1 Lõputu tsükli eelised

Lõputud tsüklid on kasulikud järgmistes olukordades:

  1. Pidev jälgimine ja töötlemine
  • Serveri või süsteemi jälgimistööriistad kasutavad tsükleid oleku regulaarseks kontrolliks.
  1. Reaalajas rakendused
  • Mängudes ja kasutajaliidestes töötlevad tsüklid pidevalt sündmusi.
  1. Kasutaja sisendi ootamine
  • Süsteemid, mis ootavad pidevat sisendit, saavad lõputu tsükli abil dünaamiliselt reageerida.
  1. Tõrketöötlus ja korduskatse
  • Andmete hankimisel või võrguühenduse katkestuse korral saab tsükkel käivitada korduskatseid.

8.2 Lõputute tsüklite riskid ja vältimine

Samas kaasnevad lõputute tsüklitega ka riskid:

1. Liigne CPU koormus

  • Põhjus: kui tsüklis pole ootamisi, koormab see protsessorit.
  • Lahendus: kasuta sleep()-i või taimerit tsükli tiheduse reguleerimiseks.

Näide: CPU koormuse vähendamine

#include <stdio.h>
#include <unistd.h>

while (1) {
    printf("Jälgin...\n");
    sleep(1); // oota 1 sekund
}

2. Programmi hangumine

  • Põhjus: lõpetamistingimuse puudumisel ei saa programmi peatada.
  • Lahendus: kasuta lipumuutujat või break-lauset turvaliseks lõpetamiseks.

Näide: lõpetamistingimusega tsükkel

#include <stdio.h>
int main() {
    int count = 0;
    while (count < 5) {
        printf("Loendus: %d\n", count);
        count++;
    }
    return 0;
}

3. Silumise raskused

  • Põhjus: tahtmatud lõputud tsüklid raskendavad vea tuvastamist.
  • Lahendus: lisa tsükli sisse logiväljundid ja kontrollpunktid.

Näide: logiväljund silumiseks

#include <stdio.h>
int main() {
    int count = 0;
    while (1) {
        printf("Debug: count=%d\n", count++);
        if (count > 10) break;
    }
    return 0;
}

8.3 Tõhusa disaini põhimõtted

Lõputute tsüklite ohutuks ja tõhusaks kasutamiseks järgi järgmisi põhimõtteid:

  1. Lõpetamistingimuste selgus
  • Kasuta lippe või ajapiiranguid, et tagada turvaline lõpetamine.
  1. Ootamiste kasutamine
  • Kasuta sleep()-i või taimerit CPU koormuse vähendamiseks.
  1. Tõrketöötluse lisamine
  • Halda ebasobivat sisendit ja ootamatuid vigu turvalise lõpetamisega.
  1. Silumisfunktsioonide lisamine
  • Logid ja murdepunktid lihtsustavad tsükli töö jälgimist.

8.4 Õpitu kordamine

Selles artiklis vaatasime üle järgmised teemad:

  1. Põhisüntaks
  • Õppisime while-, for– ja do-while-tsüklite põhivorme.
  1. Praktilised näited
  • Kasutaja sisendi ootamine, serveri jälgimine, mängutsüklid.
  1. Juhtimismeetodid
  • break, continue ja lipumuutujate kasutamine.
  1. Probleemid ja lahendused
  • CPU koormus, hangumine ja silumisraskuste vältimine.
  1. Praktilised ülesanded
  • Koodiviktoriinid, vea parandamine ja ajapiiranguga tsüklid.

8.5 Lõppsõna

Lõputud tsüklid mängivad olulist rolli C-keele programmides. Õppides selgeks põhisüntaksi, juhtimismeetodid ja ohutud kasutusviisid, on võimalik kirjutada turvalisi ja tõhusaid programme.

Kasuta selles artiklis õpitut, et ise luua ja rakendada lõputuid tsükleid oma programmides.

Soovitatud järgmised teemad õppimiseks

  • Tingimuslaused ja funktsioonid: keerukamate loogikate loomiseks.
  • Andmestruktuurid ja algoritmid C-keeles: samm edasi tõhusa programmeerimise suunas.
  • Silumistööriistade kasutamine: koodi kvaliteedi tõstmiseks.

Jätka C-keele õppimist ja katseta julgelt, et arendada oma programmeerimisoskusi veelgi!

Küsimuste või täiendavate selgituste korral kirjuta julgelt kommentaaridesse!

年収訴求