1. Mis on goto-lause
goto
-lause on üks C-keele juhtimisstruktuuridest, mida kasutatakse programmi täitmise voo suunamiseks määratud sildile hüppamise teel. Erinevalt paljudest teistest juhtimisstruktuuridest võimaldab goto
-lause hüpata suvalisse kohta programmis, muutes seega juhtimisvoo paindlikumaks. Kuid kontrollimatu kasutamine võib vähendada koodi loetavust ja hooldatavust, mistõttu tuleb seda kasutada ettevaatlikult.
goto
-lause põhisüntaks
goto
-lause süntaks on järgmine:
goto silt;
Kui goto
-lause on määratud, hüppab programmi täitmine vastava sildiga määratud kohta. Silt on identifikaator, mis määratakse hüppe sihtpunktiks ja kirjutatakse vahetult lause ette järgmiselt:
Sildi_nimi:
Vaatame lihtsa programmi näitel, kuidas goto
-lause töötab.
goto
-lause kasutamise näide
#include <stdio.h>
int main() {
int i = 0;
start: // Sildi määratlus
printf("i väärtus: %dn", i);
i++;
if (i < 5) {
goto start; // Hüppa sildile
}
printf("Tsükkel lõppenudn");
return 0;
}
Ülaltoodud kood kasutab goto
-lauset, et hüpata sildile start
ja korrata tsüklit kuni i
väärtus jõuab viieni. Nagu näha, võimaldab goto
-lause hüpata programmi soovitud kohta, kuid liigsel kasutamisel võib kood muutuda raskesti mõistetavaks. Seetõttu on soovitatav seda kasutada mõõdukalt.
goto
-lause kasutusalad ja ettevaatusabinõud
C-keeles kaalutakse goto
-lause kasutamist näiteks järgmistel juhtudel:
- Vigade käsitlemine: Kasulik, kui vea ilmnemisel tuleb vahele jätta teatud toimingud ja hüpata ressursi vabastamise koodini.
- Mitmekordsete tsüklite katkestamine: Sügavalt pesastatud tsüklitest väljumiseks võib
goto
-lause muuta koodi lihtsamaks.
Siiski muudab goto
-lause koodi voogu keerukamaks, mistõttu seda ei soovitata eriti suurtes programmides. Liigne kasutamine võib viia “spagetikoodi” tekkeni, mis on raskesti hooldatav. Seega tuleb goto
-lauset kasutada ainult siis, kui see on tõesti vajalik ja koodi loetavus jääb säilinuks.
2. goto-lause ajalugu ja vaidlused
goto
-lause on üks vanimaid programmeerimiskeelte juhtimisstruktuure, mida kasutati juba enne C-keele tekkimist. Kuid selle kasutamine on tekitanud palju arutelusid, eriti pärast struktureeritud programmeerimise levikut, kus arvamused jagunesid selgelt poolt- ja vastuväideteks. Selles jaotises käsitleme goto
-lause ajalugu ja sellega seotud vaidlusi.
goto
-lause päritolu ja varajane roll
Programmeerimise varajases arengus oli goto
-lause üks väheseid viise programmi täitmise voo muutmiseks kindlasse kohta hüppamise kaudu. Tollal puudusid arenenud juhtimisstruktuurid, mistõttu kasutati goto
-lauset tsüklite ja tingimuslike harude realiseerimiseks. Selle tulemusel koosnesid programmid sageli koodist, kus täitmine liikus hüpetega ühest kohast teise.
Kuid liigne hüpete kasutamine muutis koodi keerukaks ja raskesti jälgitavaks, mida hakati nimetama „spagetikoodiks“. Selle probleemi tõttu loodi selgemad juhtimisstruktuurid, nagu tingimuslaused ja tsüklid (if
, for
, while
), ning goto
-lause kasutamine vähenes.
Struktureeritud programmeerimine ja goto
-lause sobivus
1970. aastatel väitis tuntud arvutiteadlane Edsger Dijkstra oma kuulsas essees „Goto Statement Considered Harmful“, et goto
-lause on kahjulik. Tema sõnul muudab see programmi juhtimisvoo raskesti mõistetavaks ja seda tuleks vältida. See arvamus mõjutas tugevalt struktureeritud programmeerimise levikut, kus koodi soovitati kirjutada selgete juhtimisstruktuuridega, ilma goto
-lauseta.
goto-lause roll tänapäeval
Tänapäeval ei soovitata goto
-lauset enamasti kasutada, kuid see on endiselt olemas mõnes keeles, sealhulgas C-keeles. Mõnes olukorras, näiteks vigade käsitlemisel, võib selle kasutamine siiski olla praktiline. Üldiselt eelistatakse aga muid juhtimisstruktuure (if
, while
jne), mis hoiavad koodi selgemana.
goto
-lause ümber käivad arutelud peegeldavad programmeerimisparadigmade arengut. Isegi täna on see teema, kus arvamused võivad lahkneda, kuid loetavuse ja hooldatavuse seisukohast tuleks seda kasutada ainult läbimõeldult.
3. goto-lause eelised ja puudused
goto
-lause võib pakkuda paindlikku juhtimisvoogu, mida muude struktuuridega on keeruline saavutada, kuid samal ajal võib see kahjustada koodi loetavust ja hooldatavust. Selles jaotises käsitleme nii eeliseid kui ka puudusi koos näidetega.
goto-lause eelised
- Keerulise vigade käsitlemise lihtsustamine —
goto
-lause abil saab tsentraalselt hallata ressursi vabastamist, kui viga ilmneb sügavalt pesastatud tingimustes.
#include <stdio.h>
#include <stdlib.h>
int main() {
FILE *file = fopen("example.txt", "r");
if (!file) {
printf("Faili ei saanud avada\n");
goto cleanup;
}
char *buffer = (char *)malloc(256);
if (!buffer) {
printf("Mälu broneerimine ebaõnnestus\n");
goto cleanup;
}
// Muu töötlemine
cleanup:
if (file) fclose(file);
if (buffer) free(buffer);
printf("Ressursid vabastatud\n");
return 0;
}
- Mitmekordsest tsüklist väljumise lihtsus — sügavalt pesastatud tsüklitest saab
goto
-lause abil korraga väljuda.
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 10; j++) {
if (i * j > 30) {
goto exit_loop;
}
printf("i=%d, j=%d\n", i, j);
}
}
exit_loop:
printf("Tsükkel lõpetatud\n");
goto-lause puudused
- Loetavuse vähenemine — hüpped muudavad koodi voolu raskesti jälgitavaks.
- Vigade tekkeoht — keeruline juhtimisvoog võib viia ootamatute vigadeni.
- Spagetikoodi risk — liigne kasutamine muudab koodi hooldamise raskeks.
Kokkuvõte
goto
-lause võib olla kasulik spetsiifilistes olukordades, kuid üldiselt eelistatakse muid struktuure. Vigade käsitlemine ja sügavate tsüklite katkestamine on peamised juhtumid, kus see võib olla õigustatud.
4. goto-lause sobivad kasutusjuhud
goto
-lause võib teatud olukordades olla väga kasulik juhtimisstruktuur. Selles jaotises toome näiteid olukordadest, kus selle kasutamine on asjakohane — eriti vigade käsitlemisel ja mitmekordsest tsüklist väljumisel.
goto-lause kasutamine vigade käsitlemisel
C-keeles puuduvad eraldi erandkäsitluse mehhanismid (nagu try-catch), mistõttu mitme ressursi haldamisel võib goto
-lause lihtsustada koodi. See võimaldab kõik vabastamistoimingud koondada ühte kohta, muutes koodi selgemaks.
Näide: vigade käsitlemine mitme ressursi avamisel
#include <stdio.h>
#include <stdlib.h>
int main() {
FILE *file1 = NULL;
FILE *file2 = NULL;
char *buffer = NULL;
file1 = fopen("file1.txt", "r");
if (!file1) {
printf("Ei saanud avada file1.txt\n");
goto error;
}
file2 = fopen("file2.txt", "r");
if (!file2) {
printf("Ei saanud avada file2.txt\n");
goto error;
}
buffer = (char *)malloc(1024);
if (!buffer) {
printf("Mälu broneerimine ebaõnnestus\n");
goto error;
}
printf("Failid ja mälu edukalt töödeldud\n");
free(buffer);
fclose(file2);
fclose(file1);
return 0;
error:
if (buffer) free(buffer);
if (file2) fclose(file2);
if (file1) fclose(file1);
printf("Viga ilmnes, ressursid vabastatud\n");
return -1;
}
Väljumine mitmekordsest tsüklist
Kui sügavalt pesastatud tsüklites on vaja kindla tingimuse korral korraga kõigist tsüklitest väljuda, võib goto
-lause pakkuda lihtsat lahendust.
Näide: kahekordsest tsüklist väljumine tingimuse täitmisel
#include <stdio.h>
int main() {
int i, j;
for (i = 0; i < 10; i++) {
for (j = 0; j < 10; j++) {
if (i * j > 30) {
goto exit_loop;
}
printf("i = %d, j = %d\n", i, j);
}
}
exit_loop:
printf("Tingimus täidetud, tsükkel lõpetatud\n");
return 0;
}
Olukorrad, kus goto-lause kasutamine võib olla põhjendatud
- Ressursside vabastamine: kui hallatakse mitut ressurssi ja vabastamiskood on keerukas.
- Sügavate tsüklite katkestamine: kui on vaja korraga väljuda mitmest pesastatud tsüklist.
Ettevaatusabinõud
Kuigi goto
-lause võib olla mugav, tuleb seda kasutada ainult siis, kui muid lihtsamaid lahendusi ei ole. Liigne kasutamine vähendab koodi loetavust ja võib tekitada hooldusprobleeme.
5. Juhtumid, kus goto-lause tuleks vältida, ja alternatiivid
goto
-lause liigne kasutamine võib muuta programmi keerukaks ja vigadele kalduvaks. Selles jaotises selgitame, millal see tuleks vältida ja milliseid alternatiive kasutada.
Juhtumid, kus goto-lause tuleks vältida
- Kõrge loetavusnõudega kood — ühiskasutatavates projektides on selge kood ülioluline.
- Kui saab kasutada struktureeritud veahaldust — C-keeles saab sageli eraldada funktsioone nii, et goto pole vajalik.
- Sügavad pesastused — goto võib muuta kontrollvoo raskesti jälgitavaks.
Alternatiivid
1. Lipumuutujate kasutamine
#include <stdio.h>
int main() {
int i, j;
int exit_flag = 0;
for (i = 0; i < 10; i++) {
for (j = 0; j < 10; j++) {
if (i * j > 30) {
exit_flag = 1;
break;
}
printf("i = %d, j = %d\n", i, j);
}
if (exit_flag) break;
}
printf("Tsükkel lõpetatud\n");
return 0;
}
2. Funktsioonide eraldamine
#include <stdio.h>
#include <stdlib.h>
int read_file(FILE **file, const char *filename) {
*file = fopen(filename, "r");
if (!*file) {
printf("Ei saanud avada %s\n", filename);
return -1;
}
return 0;
}
int allocate_memory(char **buffer, size_t size) {
*buffer = (char *)malloc(size);
if (!*buffer) {
printf("Mälu broneerimine ebaõnnestus\n");
return -1;
}
return 0;
}
int main() {
FILE *file1 = NULL;
char *buffer = NULL;
if (read_file(&file1, "file1.txt") < 0) {
return -1;
}
if (allocate_memory(&buffer, 1024) < 0) {
fclose(file1);
return -1;
}
free(buffer);
fclose(file1);
printf("Protsess edukalt lõpetatud\n");
return 0;
}
3. break ja continue kasutamine
Kui on vaja tsüklist väljuda, võib sageli piisata break- või continue-lause kasutamisest, eriti kui pesastamine on madal.
6. goto-lause parimad praktikad
Kui goto-lause kasutamine on vältimatu, tuleks järgida mõningaid juhiseid:
- Kasutada ainult hädavajalikes kohtades (nt vigade käsitlemine, sügavate tsüklite katkestamine).
- Ressursside vabastamise koondamine ühte kohta.
- Siltidele arusaadavate nimede andmine (nt
cleanup
,error
). - Liigset kasutamist vältida, et kood ei muutuks spagetiks.
- Vältida keeruliste juhtimisstruktuuridega kombineerimist.
- Lasta kood üle vaadata teistel arendajatel.
7. Kokkuvõte
Käesolevas artiklis käsitlesime C-keele goto
-lauset, selle süntaksit, ajalugu, eeliseid ja puudusi, sobivaid kasutusviise, vältimise juhte ning alternatiive. goto
-lause on paindlik ja võimas, kuid selle kasutamine nõuab ettevaatust. Parim on seda kasutada vaid piiratud olukordades, kus muud lahendused muudaksid koodi oluliselt keerukamaks.
Järgides parimaid tavasid — kasutades selgeid siltide nimesid, koondades ressursihalduse ja vältides liigset kasutamist — saab goto
-lauset kasutada nii, et kood jääb arusaadav ja hooldatav.