- 1 1. C keeles argumentide põhitõed
- 2 2. Tegeliku ja formaalse argumendi erinevus
- 3 3. Argumentide edastamise viisid
- 4 4. Argumentide ja tagastusväärtuste kombinatsioonid
- 5 5. Rekursiivne väljakutse ja argumendid
- 6 6. Funktsioonimakrod ja argumendid
- 7 7. C keele standardraamatukogu funktsioonid ja argumendid
- 8 8. Kokkuvõte
- 9 9. Argumentidega seotud edasijõudnud tehnikad
- 10 10. Funktsioonide argumendid ja mäluhaldus
1. C keeles argumentide põhitõed
Mis on argument?
Argument on andmed, mis edastatakse funktsioonile selle väljakutsumise ajal. Argumentide abil saab funktsioon vastu võtta erinevaid väärtusi ning töödelda neid vastavalt sisendile. Argumentide kasutamise mõistmine C keeles on oluline programmi taaskasutatavuse ja paindlikkuse suurendamiseks.
Tegelik argument ja formaalne argument
Väärtusi, mida annab funktsioonile kutsuv pool, nimetatakse tegelikeks argumentideks (real argument), ning väärtusi, mida funktsioon ise vastu võtab, nimetatakse formaalseteks argumentideks (formal argument). Näiteks PrintScore(score);
puhul on score
tegelik argument, ning void PrintScore(int score)
puhul on score
formaalne argument. Funktsioonide õige kasutamise jaoks on oluline mõista nende kahe erinevust.
2. Tegeliku ja formaalse argumendi erinevus
Tegelik argument
Tegelik argument on väärtus, mis antakse funktsioonile selle väljakutsumise ajal. Näiteks PrintScore(100);
puhul on 100
tegelik argument. Tegelik argument edastatakse funktsioonile ja seda kasutatakse funktsiooni sees.
Formaalne argument
Formaalne argument on ajutine nimi, mille kaudu funktsioon vastu võtab andmeid. Formaalse argumendi väärtust ei saa funktsiooni väljast muuta. Näiteks void PrintScore(int score)
puhul on score
formaalne argument.
3. Argumentide edastamise viisid
Väärtuse järgi edastamine
Väärtuse järgi edastamine tähendab, et tegeliku argumendi väärtus kopeeritakse formaalsele argumendile. Sellel juhul, kui funktsiooni sees formaalse argumendi väärtust muudetakse, siis see ei mõjuta tegelikku argumenti. Vaatame järgmist näidet.
void LevelUp(int lv) {
lv++;
}
int main() {
int level = 1;
LevelUp(level);
printf("Level: %dn", level); // Väljund: Level: 1
}
Selles näites LevelUp
funktsioonis lv
suureneb, kuid main
funktsioonis level
ei muutu. Väärtuse järgi edastamise eelis on, et see kaitseb algset andmestikku, kuid suurte andmete korral suureneb mälukasutus.
Viitamise järgi edastamine (pointer)
Viitamise järgi edastamine tähendab, et tegeliku argumendi aadress antakse formaalsele argumendile. Sel viisil saab funktsioon muuta otse tegeliku argumendi väärtust.
void LevelUp(int *plv) {
(*plv)++;
}
int main() {
int level = 1;
LevelUp(&level);
printf("Level: %dn", level); // Väljund: Level: 2
}
Selles näites muudetakse LevelUp
funktsioonis otse level
väärtust. Viitamise järgi edastamise eelis on, et saab muuta või tagastada mitut väärtust, kuid viitade vale kasutamine võib põhjustada vigu või mälulekkeid, seega tuleb olla ettevaatlik.
4. Argumentide ja tagastusväärtuste kombinatsioonid
Argumendiga, kuid tagastuseta funktsioon
See on funktsioon, mis võtab vastu argumente, kuid ei tagasta midagi. Näiteks void PrintScore(int score)
– võtab vastu skoori, kuid ei tagasta väärtust.
Ilma argumendita, tagastusväärtusega funktsioon
See on funktsioon, mis ei võta vastu argumente, kuid tagastab väärtuse. Näiteks int GetCurrentScore()
– arvutab ja tagastab hetke skoori.
Argumendiga ja tagastusväärtusega funktsioon
See on funktsioon, mis võtab vastu argumente ja tagastab väärtuse. Näiteks int Add(int a, int b)
– võtab vastu kaks arvu ning tagastab nende summa. Sellised funktsioonid on paindlikud ja neid saab kasutada erinevates olukordades.
5. Rekursiivne väljakutse ja argumendid
Mis on rekursiivne väljakutse?
Rekursiivne väljakutse tähendab, et funktsioon kutsub iseennast. See on kasulik, kui tuleb lahendada probleem väiksemateks osadeks, kuid kontrollimatu kasutamine võib põhjustada stack overflow vea.
Rekursiooni näide
Allpool on näide, kus funktsioon kasutab argumenti, et jagada arvu kahega rekursiivselt.
int funcA(int num) {
if(num % 2 != 0) {
return num;
}
return funcA(num / 2);
}
int main() {
int result = funcA(20);
printf("Result: %dn", result); // Väljund: Result: 5
}
Selles näites kutsub funcA
iseennast, kasutades argumenti korduva töötluse jaoks. Rekursiivsed funktsioonid lihtsustavad korduva loogika kirjutamist, kuid lõpetamistingimused peavad olema selged, et vältida lõputut tsüklit.
6. Funktsioonimakrod ja argumendid
Mis on funktsioonimakro?
Funktsioonimakro on makro, mis võtab vastu argumente ja mille kood asendatakse kompileerimise ajal. See võib parandada programmi jõudlust.
Funktsioonimakro näide
Allpool on makro näide massiivi elementide arvu leidmiseks.
#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
int main() {
int arr[10];
printf("Array size: %dn", ARRAY_SIZE(arr)); // Väljund: Array size: 10
}
Kuna funktsioonimakrod asendatakse juba enne käivitamist, pole neil täitmisel lisakoormust. Samas, tüübi kontrolli puudumise tõttu tuleb neid hoolikalt kasutada.
7. C keele standardraamatukogu funktsioonid ja argumendid
Standardfunktsioonide kasutamine
C keeles on palju standardraamatukogu funktsioone, mis kasutavad argumente erinevate töötluste jaoks. Näiteks printf
funktsioon võtab vastu muutuva arvu argumente ning kuvab andmeid määratud formaadis.
Standardfunktsioonide näide
Allpool on näide printf
funktsiooni kasutamisest.
printf("Name: %s, Age: %dn", "Alice", 30); // Väljund: Name: Alice, Age: 30
Selles näites kasutab printf
argumente, et kuvada stringi ja arvu. Standardraamatukogu funktsioonide kasutamine muudab koodi loetavamaks ja tõstab efektiivsust.
8. Kokkuvõte
Muutuva pikkusega argumendid
C keeles saab funktsioonidele edastada muutuva arvu argumente, kasutades muutuva pikkusega argumente (variadic arguments). Selleks kasutatakse funktsioonide definitsioonis punktiiriga märget (...
). See võimaldab luua funktsioone, mille argumentide arv pole eelnevalt teada. Tuntud näide on printf
funktsioon, mis võtab erineva arvu argumente vastavalt vormindusele.
Muutuva pikkusega argumentide näide
Allpool on näide funktsioonist, mis võtab vastu mitu täisarvu ning arvutab nende summa.
#include <stdarg.h>
#include <stdio.h>
int sum(int count, ...) {
va_list args;
va_start(args, count);
int total = 0;
for (int i = 0; i < count; i++) {
total += va_arg(args, int);
}
va_end(args);
return total;
}
int main() {
printf("Sum: %dn", sum(4, 1, 2, 3, 4)); // Väljund: Sum: 10
}
Selles näites võtab sum
funktsioon vastu mitu täisarvu ning tagastab nende summa. Kasutatakse makrosid nagu va_list
, va_start
, va_arg
ja va_end
, et töödelda muutuva arvu argumente.
Millele tähelepanu pöörata
Muutuva pikkusega argumentide kasutamisel tuleb olla ettevaatlik, et argumentide arv ja tüüp vastaksid ootustele. Kui kutsuval ja defineerival poolel need erinevad, võib programm käituda ettearvamatult või isegi kokku kukkuda.
Praktilised kasutusjuhud ja argumentide tõhus kasutamine
Argumentide tõhus kasutus
Argumentide mõistlik kasutus parandab koodi loetavust ja taaskasutatavust. Kui mitmes funktsioonis kasutatakse samu andmeid, on parem anda need edasi argumentidena, mitte defineerida globaalseid muutujaid. See suurendab funktsioonide sõltumatust ja vähendab teiste koodiosade mõjutamise riski.
Mälukasutus ja jõudlus
Suurte andmete puhul aitab viitamise järgi edastamine vähendada mälukasutust. Kui edastada suur massiiv või struktuur väärtusena, kopeeritakse kogu andmestik. Viidete korral edastatakse ainult aadress, säästes mälu.
Kodeerimise parimad tavad
Funktsioonide loomisel on oluline hoolikalt läbi mõelda argumentide arv ja tüübid. Liigsete argumentide kasutamine muudab funktsioonid keerukamaks ja võib põhjustada vigu. Kõik vajalikud andmed tuleks anda edasi argumentidena, et parandada koodi selgust ja hooldatavust.
9. Argumentidega seotud edasijõudnud tehnikad
Tagasikutse funktsioon (callback)
Tagasikutse funktsioon tähendab, et funktsioon antakse argumendina teisele funktsioonile ning seda kutsutakse seal sees. See võimaldab paindlikke lahendusi ning on sageli kasutusel sündmustepõhistes või asünkroonsetes programmides.
#include <stdio.h>
void executeCallback(void (*callback)(int)) {
callback(10);
}
void printValue(int val) {
printf("Value: %dn", val);
}
int main() {
executeCallback(printValue); // Väljund: Value: 10
}
Selles näites antakse printValue
funktsioon edasi argumendina ja kutsutakse välja executeCallback
funktsioonis.
Funktsioonipointerid
Funktsioonipointerite abil saab funktsioone käsitleda nagu muutujaid. See võimaldab anda funktsioone edasi argumentidena või kutsuda erinevaid funktsioone jooksvalt. Sellest on palju abi dünaamilise ja paindliku koodi kirjutamisel.
#include <stdio.h>
int add(int a, int b) {
return a + b;
}
int main() {
int (*operation)(int, int) = add;
printf("Result: %dn", operation(2, 3)); // Väljund: Result: 5
}
Selles näites antakse add
funktsioon funktsioonipointeri operation
kaudu ja kutsutakse seda välja nagu tavalist muutujat.
10. Funktsioonide argumendid ja mäluhaldus
Dünaamiline mälu ja argumendid
C keeles saab malloc
ja free
abil dünaamiliselt mälu hallata. Kui anda funktsioonile argumendiks dünaamiliselt eraldatud mälu pointer, tuleb mäluhaldusele erilist tähelepanu pöörata.
#include <stdlib.h>
#include <stdio.h>
void allocateMemory(int **ptr, int size) {
*ptr = (int *)malloc(size * sizeof(int));
}
int main() {
int *arr;
allocateMemory(&arr, 5);
for (int i = 0; i < 5; i++) {
arr[i] = i + 1;
}
for (int i = 0; i < 5; i++) {
printf("%d ", arr[i]); // Väljund: 1 2 3 4 5
}
free(arr); // Mälust vabastamine
}
Selles näites eraldab allocateMemory
funktsioon dünaamiliselt mälu ning annab pointeri edasi argumendina. Kui mälu ei hallata õigesti, võib tekkida mäluleke.