Muutujate deklareerimine
C-keeles deklareerime alati muutuja määrates andmetüüp ja muutuja nimi, kasutades süntaksit data_type variable_name; .
1 2 3 4 5 6 7 8 9 10 11 12 13 |
#include <stdio.h> int main(void) { // Declares an integer variable int number; printf("Enter an integer: "); scanf("%d", &number); printf("You entered %d as integer.\n", number); return 0; } |
Kui sama andmetüübiga muutujaid on rohkem, eraldatakse need komaga data_type variable_name_1, variable_name_2;. Sellisel viisil saab deklareerida suvalise arvu muutujaid, aga mida rohkem on muutujaid, seda raskemini loetavaks kood muutub!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
#include <stdio.h> int main(void) { // Declares two real numbers of the same data type float firstRealNumber, secondRealNumber; printf("Enter a real number: "); scanf("%f", &firstRealNumber); printf("Enter another real number: "); scanf("%f", &secondRealNumber); printf("You entered %f and %f as real numbers.\n", firstRealNumber, secondRealNumber); return 0; } |
Muutujate algväärtustamine
Iga muutuja võib deklareerimise käigus algväärtustada, omistades sellele väärtuse vastavalt süntaksile data_type variable_name = initial_value; . Vastavalt koodimisstiilile tuleb iga muutuja, millele omistatakse algväärtus, deklareerida eraldi real. See on oluline eelkõige koodi loetavuse seisukohalt.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#include <stdio.h> int main(void) { // Declares and initializes an integer int number = 129; // Declares and initializes a double double realNumber = 25.91; printf("The numbers are: %d and %.2lf\n", number, realNumber); return 0; } |
Andmetüübid
C keel jätab muutuja andmetüüpide deklareerimisel mõned asjad lahtiseks. Nimelt määrab C standard ainult muutuja minimaalse suuruse baitides ja andmetüüpide suuruste vahelise seose. Seda on oluline meeles pidada, kui andmetüübi suurus esitatakse fikseeritud numbrina – see ei ole alati korrektne!
Järgnevas tabelis on toodud põhilisemad andmetüübid ja formaadid. Põhjalikuma ülevaate saamiseks vaadake https://en.wikipedia.org/wiki/C_data_types või https://www.tutorialspoint.com/cprogramming/c_data_types.htm
Andmetüüp | Miinimum suurus (baitides) | Kasutusjuht | Formaat | Kommentaarid |
char | 1 | tähemärk | %c | ASCII kodeerimine |
char [] | ? | sõne | %s | Null-terminaatoriga ASCII-märkidest massiiv |
int | 2 | väiksemad täisarvud
|
%d %i | Suurus sõltub platvormist |
long | 4 | Pikemad täisarvud | %ld %li | Suurus sõltub platvormist. Soovitatav on selle asemel kasutada bit-width täisarve |
float | 4 | reaalarvud, ujukomaarvud | %f | Madal täpsus, vältida nt rahaliste väärtuste puhul jne |
double | 8 | reaalarvud, kahekordse täpsusega ujukoma arv | %lf | Parem täpsus, kuid siiski ebasobiv, kui nõutakse suurt täpsust |
Märkus: minimaalne suurus ja seos on väga märgatav, kui programmeeritakse mikrokontrollereid. Nt tavalisel lauaarvutil, sülearvutil ja serveril on int 4 baiti, aga enamikel Arduino arendusplaatidel on int 2 baiti. Ühtlasi peab long andmetüüp olema 2x suurem kui int , seega lauaarvutil on see tõenäoliselt 8 baiti, kuid Arduinol 4 baiti. See on omakorda sõltuv sellest, millist mikroprotsessorit Arduino mikrokontroller kasutab.
Bit-width täisarvu andmetüüpide kasutamiseks tutvu teegiga inttypes.h . Seda käsitleme ka Programmeerimine 1 kursusel.
Massiivide deklareerimine
Massiive deklareeritakse sama süntaksi alusel nagu muutujaid, lisades deklaratsiooni soovitud massiivi pikkuse data_type array_name[array_size]; . Pikkuse määramine on kohustuslik staatiliste massiivide puhul.
Maagiliste numbrite vältimiseks kasutatakse sageli makrot ( #define ) või const piiranguga muutujat
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
#include <stdio.h> #define NUM_CNT 3 int main(void) { int nums[NUM_CNT]; for (int i = 0; i < NUM_CNT; i++) { printf("Enter number %d: ", i + 1); scanf("%d", &nums[i]); } printf("Entered nums were: "); for (int i = 0; i < NUM_CNT; i++) { printf("%d ", nums[i]); } printf("\n"); return 0; } |
Massiivide algväärtustamine
Massiive saab algväärtustada deklaratsiooni käigus, määrates loogeliste sulgude { } vahel kas kõik väärtused või alamhulga väärtustest, nt data_type array_name[array_size] = {val_1, val_2, ..., val_n-1}; .
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
#include <stdio.h> #define NUM_CNT 3 int main(void) { int nums[NUM_CNT] = {9, 2, 5}; printf("Array contains: "); for (int i = 0; i < NUM_CNT; i++) { printf("%d ", nums[i]); } printf("\n"); return 0; } |
Massiivi algväärtustamisel võib massiivi suuruse array_size määramata jätta. Sellisel juhul leiab kompilaator massiivi pikkuse vastavalt algväärtustatud liikmete arvule.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
#include <stdio.h> int main(void) { // Array size omitted, length must be calculated afterwards int nums[] = {9, 2, 5}; int arrayLen = sizeof(nums) / sizeof(int); printf("Array contains: "); for (int i = 0; i < arrayLen; i++) { printf("%d ", nums[i]); } printf("\n"); return 0; } |
Massiivi algväärtustamine nullideks
Massiivid võivad olla null-väärtustatud kasutades süntaksit data_type array_name[array_size] = {0};. Sellisel juhul arvesta, et kui massiivi pikkus ei ole määratud, siis saab massiivi pikkuseks 1.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
#include <stdio.h> #define NUM_CNT 3 int main(void) { // Zero-initialized array int nums[NUM_CNT] = {0}; printf("Array contains: "); for (int i = 0; i < NUM_CNT; i++) { printf("%d ", nums[i]); } printf("\n"); return 0; } |
Mitme-dimensiooniliste massiivide deklareerimine ja initsialiseerimine
Kõik massiivi dimensioonid tuleb deklaratsiooni käigus spetsifitseerida. 2-dimensioonilise massiivi deklareerimiseks kasutame tavaliselt süntaksit data_type array_name[row_cnt][col_cnt];. Ridade ja veergude kasutamine on illustreeriv (mõtle nt Exceli tabelile), kuid ka väga levinud praktika.
2-D massiivi initsialiseerimisel kasutame pesastatud sulge ridade eristamiseks. Väärtuste joondamine ei ole kohustuslik, kuid on abiks hooldatavuse seisukohalt.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
int main(void) { int nums[ROW_CNT][COL_CNT] = {{ 5 3, 14, 3, 6}, {14, 3, -9, 2, 7}, { 9, 1, 9, 2, 51}, {91, 0, 0, 1, 16}, {15, 43, 656, 1, 1}}; printf("Array contains:\n"); for (int i = 0; i < ROW_CNT; i++) { for (int j = 0; j < COL_CNT; j++) { printf("%3d ", nums[i][j]); } printf("\n"); } return 0; } |
Pane tähele, et mitmemõõtmelises massiivis võib esimese mõõtme (st ridade arvu) ära jätta, kuid selle peab hiljem välja arvutama, et massiivi itereerida.
Sõnede deklareerimine
C-keeles käsitletakse sõne null-lõpuga massiividena. Iga massiivi element on ASCII-koodis esindatud märk, mille suurus on 1 bait. Sõnel peab alati olema varuks üks lisamärk null-lõpu jaoks.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#include <stdio.h> #define STR_LEN 8 int main(void) { char word[STR_LEN]; printf("Enter a word (up to %d characters): ", STR_LEN - 1); scanf("%7s", word); printf("You entered: %s\n", word); return 0; } |
Märkus: Sellist sõne lugemise viisi ei soovitata C-keeles kasutada, aga see on jäetud illustratsiooniks, et hoida see lihtsa ja lühikesena. Õigeid sõne lugemise viise tutvustatakse vastavas loengus.
Sõnede initsialiseerimine
Sõned initsialiseeritakse tihti sõne literaalidena, jättes massiivi pikkuse määramata – nii saab kompilaator tuvastada massiivi pikkuse. Sõned on alati ümbritsetud jutumärkidega, kuid üksikud tähemärgid on ümbritsetud ülakomadega.
Järgmises näites koosneb sõne 13 märgist, samas massiiv on deklareeritud 14 baidi pikkuseks, et oleks ruumi lõpu märgile NUL. Väljend null-lõpp (zero-terminated) tuleb sellest, et ASCII sümbol NUL omab täisarvulist väärtust 0 (null)
1 2 3 4 5 6 7 8 |
#include <stdio.h> int main(void) { char hello[] = "Hello, World!"; printf("%s\n", hello); return 0; } |
Enamik ajast kasutatakse tühjade kantsulgude asemel muutuja nime ees tärni. Sellel on täpselt sama mõju.
1 2 3 4 5 6 7 8 |
#include <stdio.h> int main(void) { char *hello = "Hello, World!"; printf("%s\n", hello); return 0; } |
Tühja sõne initsialiseerimine
Tühja sõne initsialiseerimisel peame olema kindlad, et sõne oleks piisava pikkusega vastavalt planeeritavale kasutusjuhule.
1 2 3 4 5 6 7 8 9 10 |
#include <stdio.h> #define STR_LEN 256 int main(void) { char word[STR_LEN] = ""; return 0; } |
ÄRA KASUTA char *string = ""; ega char string[] = "";. Kompilaator arvutab massiivi pikkuse initsialiseerimise baasil- need on tühjad sõned, mis sisaldavad ainult sõne lõputähist, mille tulemuseks on 1-baidine pikkus ja seetõttu ei mahu sinna ühtegi muud märki.
Sõnedest koosneva massiivi deklareerimine
Sõnede massiive käsitletakse sarnaselt kahemõõtmeliste massiividega, kuid sõltuvalt deklareerimise viisist võib esineda mõningaid erandeid.
Deklaratsioon char strings[num_of_strings][string_length]; võimaldab luua kindla arvu sõnesid, mille määrab esimene pikkus (st num_of_string ), kus iga sõne saab olla kuni string_length - 1 märgi pikkune. Kõik sõned kasutavad sama palju mälu olenemata tegelikust pikkusest.
Sellist tüüpi deklaratsioon on ebatavaline ja suuresti ebapraktiline. Rohkem levinud näide on toodud järgmises peatükis.
Sõnedest koosneva massiivi initsialiseerimine
Sõnede massiiv deklareeritakse tavaliselt massiivina, mille elemendid on viidad sõnedele. Selleks kasutatakse järgmist süntaksit:
char *strings[] = {"string1", "string2", ..., "string_n-1"};Selle eeliseks on see, et kompilaator määrab automaatselt nii massiivi kui ka iga initsialiseeritud sõne suuruse. See on ka käsureaargumentide struktuur.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
#include <stdio.h> int main(void) { char *names[] = {"Tiina", "Mari", "Toomas", "Karl"}; int n = sizeof(names) / sizeof(char *); for (int i = 0; i < n; i++) { printf("%s\n", names[i]); } return 0; } |