Kirjautuminen

Haku

Tehtävät

Oppaat: C-ohjelmointi: Osa 3 - Ehdot, silmukat ja funktiot

  1. Osa 1 - Ensimmäinen ohjelma
  2. Osa 2 - Muuttujat, taulukot ja tietueet
  3. Osa 3 - Ehdot, silmukat ja funktiot
  4. Osa 4 - Standardikirjasto

Kirjoittaja: Antti Laaksonen. Vuosi: 2004.

Tämän oppaan alussa tutustutaan tosiin ja epätosiin lausekkeisiin, jotka liittyvät tärkeällä tavalla seuraavaan aiheeseen: ohjelman kulkuun vaikuttaviin ehtolauseisiin ja saman asian monta kertaa toistaviin silmukoihin. Toinen tärkeä uusi asia on omien funktioiden luominen. Funktioiden avulla koodi lyhenee ja selkeytyy, ja virheiden korjaaminen on myös helpompaa. Luodaanpa oppaassa myös silmäys osoitinmuuttujiin, jotka osoittavat toiseen tietokoneen muistissa olevaan muuttujaan.

Tosi ja epätosi

C-kielessä lauseke, jonka arvo on 0, on epätosi. Kaikki muut arvot ovat tosia. Erillistä tietotyyppiä totuusarvolle ei ole.

Lausekkeita voidaan vertailla operaattoreilla == (yhtä suuri), != (erisuuri), < (pienempi), > (suurempi), <= (pienempi tai yhtä suuri) ja >= (suurempi tai yhtä suuri). Lisäksi käytössä on loogiset operaattorit ! (tosi, jos lauseke on epätosi), && (tosi, jos kummatkin lausekkeet ovat tosia) ja || (tosi, jos ainakin jompikumpi lauseke on tosi). Sulkujen käyttö operaattoreiden yhteydessä on mahdollista.

Seuraavassa listassa on esimerkkejä tosista ja epätosista lausekkeista:

lauseketotuusarvo
0epätosi
5tosi
7 > 2tosi
6 == 3epätosi
2 <= 2tosi
7 != 7epätosi
!(3 > 5)tosi
5 > 2 && 6 == 6tosi
6 == 3 || 5 < 5epätosi

Huomaa merkintöjen = ja == ero. Edellistä käytetään arvon sijoittamiseen muuttujaan ja jälkimmäistä kahden lausekkeen vertailuun. Jos muuttujan arvoksi tulee muu kuin 0, on sijoituslauseke aina tosi.

Ehtolause if

if-ehtolauseen jäljessä oleva koodi suoritetaan, jos ehto on tosi. Seuraavassa esimerkissä tulostetaan tekstiä näytölle, jos a-muuttujan arvo on suurempi kuin viisi.

if (a > 5)
    printf("a on suurempi kuin viisi.");

Jos suoritettavia lauseita on useampia, ne täytyy kirjoittaa aaltosulkujen sisään. Seuraavassa esimerkissä a:n arvoksi muutetaan nolla, jos sen arvo on yli viisi. Sen jälkeen tulostetaan vielä tekstiä näytölle.

if (a > 5) {
    a = 0;
    printf("a:n arvo muuttui nollaksi, koska se oli yli viisi.");
}

Jos ehtolauseessa on else-osa, sen perässä oleva koodi suoritetaan silloin, kun ehto ei ole tosi. Seuraavassa esimerkissä tarkistetaan ensin, onko a-muuttujan arvo viisi. Jos ei ole, tarkistetaan onko a:n arvo suurempi kuin viisi. Jos ei ole näinkään, siirrytään viimeiseen else-lauseeseen ja a:n täytyy olla pienempi kuin viisi. Kussakin tapauksessa tulostetaan erilainen teksti näytölle.

if (a == 5)
    printf("a on viisi.");
else if (a > 5)
    printf("a on suurempi kuin viisi.");
else
    printf("a on pienempi kuin viisi.");

Seuraavassa on hieman monimutkaisempi ehtorakenne, joka ilmoittaa, onko vuosi karkausvuosi vai ei. Jos vuosiluku on neljällä jaollinen, se on karkausvuosi. Kuitenkin sadalla jaollinen vuosi on karkausvuosi ainoastaan silloin, kun se on myös 400:lla jaollinen. Aaltosulut eivät olisi oikeastaan pakollisia, koska joka ehdon perässä on vain yksi ohjelmalause, mutta ne ovat tässä mukana selkeyden vuoksi.

if (vuosi % 4 == 0) {
    if (vuosi % 100 == 0) {
        if (vuosi % 400 == 0) {
            printf("On karkausvuosi.");
        } else {
            printf("Ei ole karkausvuosi.");
        }
    } else {
        printf("On karkausvuosi.");
    }
} else {
    printf("Ei ole karkausvuosi.");
}

Silmukat while ja do

while-silmukan sisällä olevaa koodia toistetaan niin kauan, kuin silmukan alussa oleva ehto on tosi. Seuraava silmukka tulostaa näytölle luvut yhdestä kymmeneen. Aluksi a-muuttujan arvo on 1, ja sitä kasvatetaan joka tulostuksen jälkeen. Silmukkaa toistetaan niin kauan, kuin a:n arvo on 10 tai pienempi.

a = 1;
while (a <= 10) {
    printf("%i ", a);
    a++;
}
/* tulostus: "1 2 3 4 5 6 7 8 9 10" */

do-silmukka on muuten täysin samanlainen kuin while-silmukka, paitsi että ehdon tarkistus on silmukan lopussa. Siksi do-silmukan välissä oleva koodi suoritetaan varmasti ainakin kerran. Seuraavassa on lukujen 1 – 10 tulostus toteutettuna do-silmukalla.

a = 1;
do {
    printf("%i ", a);
    a++;
} while (a <= 10);
/* tulostus: "1 2 3 4 5 6 7 8 9 10" */

Pidä huolta siitä, että silmukan ehto muuttuu aikanaan epätodeksi. Muuten silmukka jatkuu loputtomiin ja ohjelma jumiutuu.

for-silmukka

for-silmukan määrittelyssä on kolme osaa: muuttujan alustus, silmukan jatkamisehto ja muuttujan kasvatus tai vähennys. Jokaisella kierroksella muuttujan arvo kasvaa tai vähenee, ja silmukan toistaminen jatkuu niin kauan, kuin ehto pysyy totena. Tässä on – kolmannen kerran – esimerkki, joka tulostaa näytölle luvut yhdestä kymmeneen.

for (i = 1; i <= 10; i++) {
    printf("%i ", i);
}
/* tulostus: "1 2 3 4 5 6 7 8 9 10" */

Muuttujan arvo voi kasvaa yhtä suuremmissa tai pienemmissä erissä. Seuraavassa tulostetaan parilliset luvut 2, 4, 6, 8 ja 10. Joka kierroksella muuttujan arvo kasvaa kahdella.

for (i = 2; i <= 10; i += 2) {
    printf("%i ", i);
}
/* tulostus: "2 4 6 8 10" */

Samaten muuttujan arvo voi vähentyä kasvamisen sijaan. Seuraavassa on lukujen 10 – 1 tulostus, jossa muuttujan arvo on aluksi 10, vähenee yhdellä joka kierroksella, ja silmukka jatkuu niin kauan, kuin muuttujan arvo on 1 tai suurempi.

for (i = 10; i >= 1; i--) {
    printf("%i ", i);
}
/* tulostus: "10 9 8 7 6 5 4 3 2 1" */

Silmukan keskeyttäminen

Silmukka voidaan keskeyttää break-lauseella, vaikka ehto ei olisi vielä muuttunut epätodeksi. Lisäksi continue-lause siirtyy suoraan silmukan alkuun seuraavalle kierrokselle. Seuraavassa esimerkissä silmukka jatkuisi ehtonsa puolesta loputtomiin (jos luku ei ole 0, se on aina tosi), mutta break-lause keskeyttää silmukan, kun a:n arvo on yli kymmenen. Taas kerran siis luvut 1 – 10 tulevat näytölle.

a = 1;
while (1) {
    printf("%i ", a);
    a++;
    if (a > 10)
        break;
}
/* tulostus: "1 2 3 4 5 6 7 8 9 10" */

Funktio

Funktio koostuu kahdesta osasta: koodin alussa olevasta esittelystä ja itse funktiosta. Seuraavassa on funktio nimeltä moikka, joka tulostaa näytölle tervehdyksen aina, kun sitä kutsutaan. Ohjelmassa funktiota kutsutaan kolmesti, minkä vuoksi näytölle tulostuu kolmesti teksti "Moikka!" ja rivinvaihto. Funktion esittely on samanlainen kuin itse funktion ensimmäinen rivi, mutta se päättyy puolipisteeseen.

#include <stdio.h>

/* funktion esittely */
void moikka(void);

int main(void) {
    /* funktiokutsu */
    moikka();
    moikka();
    moikka();
    return 0;
}

/* itse funktio */
void moikka(void) {
    printf("Moikka!\n");
}

Parametrit ovat muuttujia, jotka välittyvät funktiolle sitä kutsuneesta koodista. Funktion parametrit kirjoitetaan sulkuihin funktion nimen jälkeen. Jos parametreja ei ole, niiden paikalle tulee merkintä void. Jos parametreja on useampia, ne erotetaan pilkuilla. Seuraava funktio (muista kirjoittaa esittely koodin alkuun!) tulostaa parametrina olevan markkamäärän sekä vastaavan rahamäärän euroina.

void euroiksi(float markat) {
    printf("%.2f markkaa on %.2f euroa.", markat, markat / EUROKERROIN);
}

Koodin alussa on määritelty vakioksi euron ja markan välinen muuntokerroin (1 euro = 5,94573 markkaa). Jos sama muuttumaton arvo saattaa toistua useassa ohjelman kohdassa, kannattaa käyttää vakioita, koska vakion arvon muuttaminen vaikuttaa samalla kertaa koko ohjelmaan ja vakion nimen muistaminen on helppoa. Ennen varsinaista ohjelman käännöstä vakiot korvautuvat niitä vastaavilla arvoilla.

#define EUROKERROIN 5.94573

Tätä funktiota voisi sitten kutsua ohjelmassa näin:

euroiksi(10);
/* tulostus: "10.00 markkaa on 1.68 euroa." */

Funktiota voisi kuitenkin vielä parantaa. Euromäärälle saattaa tulla ohjelmassa muutakin käyttöä, joten on parempi, jos funktio suoraan tulostamisen sijasta palauttaa arvonaan euromäärän funktiota kutsuneeseen koodiin. Palautusarvon tyyppi merkitään funktion alkuun, ja jos funktio ei palauta mitään, niin tyypin tilalla on void. Palautusarvon asettava return-lause poistuu saman tien funktiosta. Uusi monikäyttöisempi funktio näyttää tältä:

float euroiksi(float markat) {
    return markat / EUROKERROIN;
}

Nyt funktiota voisi käyttää ohjelmassa vaikkapa näin:

printf("Kirja maksaa %.2f euroa.", euroiksi(60));
/* tulostus: "Kirja maksaa 10.09 euroa." */

Funktion palautusarvoa voidaan siis käyttää aivan samalla tavalla kuin muuttujan arvoa.

Osoittimet

Jokaisella muuttujalla on tietokoneen muistissa oma paikkansa, johon sen arvo on tallennettu. Muuttujan muistiosoite selviää kirjoittamalla sen nimen eteen &-merkki. Osoitinmuuttuja, jonka nimen eteen määrittelyssä kirjoitetaan *-merkki, osoittaa toiseen ohjelmassa olevaan muuttujaan. Varsinainen muuttuja ja siihen liittyvä osoitinmuuttuja viittaavat yhteen ja samaan arvoon tietokoneen muistissa. Seuraavassa esimerkissä muuttujan arvoa muutetaan osoitinmuuttujan kautta.

/* muuttuja on tavallinen muuttuja, osoitin on osoitinmuuttuja */
int muuttuja, *osoitin;
/* laitetaan osoitin osoittamaan muuttujaan */
osoitin = &muuttuja;
/* asetetaan muuttujan arvoksi 123 */
*osoitin = 123;
/* nyt muuttujan arvo on 123! */
printf("%i", muuttuja);

Osoitinmuuttujan nimi sellaisenaan tarkoittaa siis muuttujan osoitetta. Jos nimen edessä on *-merkki, osoitin viittaa muuttujan sisältöön. Ennen kuin osoitinmuuttujaa voi käyttää, jonkun toisen muuttujan osoite täytyy tallentaa siihen. Osoitinmuuttujaan on tallennettu pelkästään muuttujan osoite tietokoneen muistissa, joka vaihtelee jokaisella ohjelman suorituskerralla.

Osoittimet ja funktiot

Osoittimia tarvitaan muun muassa silloin, kun kokonaisen taulukon tiedot täytyy välittää funktiolle. Koko taulukon sisältö ei voi olla nimittäin funktion parametrina. Funktiolle välitetään pelkästään taulukon ensimmäisen alkion osoite muistissa. Taulukon alkiot tallennetaan aina perätysten muistiin. Seuraavassa ohjelmassa funktiolle välitetään taulukon osoite, ja taulukon kaikki kolme alkiota tulostetaan näytölle.

#include <stdio.h>

void naytatiedot(int tiedot[3]);

int main(void) {
   int taulukko[3] = {1, 2, 3};
   naytatiedot(taulukko);
}

void naytatiedot(int tiedot[3]) {
    printf("%i %i %i", tiedot[0], tiedot[1], tiedot[2]);
    /* tulostus: "1 2 3" */
}

Mutta miksi ohjelmassa ei ole osoittimiin liittyviä merkintöjä? Tämä johtuu siitä, että funktion parametrina taulukko tarkoittaa oikeasti samaa kuin &taulukko[0] ja tiedot[indeksi] tarkoittaa samaa kuin *(tiedot + indeksi). Tällaisten lyhenteiden käyttäminen on vain paljon mukavampaa kuin osoitinmerkintöjen. Samaan tapaan mahdollista on välittää funktiolle tavallisen muuttujan tai tietuemuuttujan osoite. Tietueen yksittäiseen muuttujaan osoitetaan merkinnällä tietue->muuttuja, joka tarkoittaa samaa kuin (*tietue).muuttuja.

Osoittimille on käyttöä myös silloin, kun funktion täytyy palauttaa useampi kuin vain yksi arvo. Osoittimien avulla funktio pystyy muuttamaan sen parametrien arvoa pysyvästi. Esimerkissä on kolme muuttujaa, joiden arvoiksi funktio asettaa 12, 34 ja 56. Muuttujiin viitataan niiden osoitteiden avulla, jotka ovat funktion parametreina. Lopuksi muuttujien uudet arvot tulostetaan näytölle.

#include <stdio.h>

void arvot(int *a, int *b, int *c);

int main(void) {
    int eka, toka, kolmas;
    arvot(&eka, &toka, &kolmas);
    printf("%i %i %i", eka, toka, kolmas);
    /* tulostus: "12 34 56" */
}

void arvot(int *a, int *b, int *c) {
    *a = 12;
    *b = 34;
    *c = 56;
}

Tehtäviä

  1. Määritä a:n ja b:n arvot niin, että lauseke 2 * a + b == 11 && 3 * a - b == 4 on tosi.

  2. Mitä vikaa on seuraavassa koodissa?

    if (nopeus = 100) {
        printf("Nopeus on 100 km/h.");
    }
  3. Mitä tarkoittaa *-merkki muuttujan nimen edessä? Entä &-merkki?

  4. Muuta karkausvuoden tarkistus funktioksi, jonka parametrina on tarkistettava vuosi ja joka palauttaa arvon 1, jos vuosi on karkausvuosi, tai muuten arvon 0.

  5. Kirjoita ohjelma, joka kysyy käyttäjältä syötettävien lukujen määrän, kysyy sitten nämä luvut yksi kerrallaan, ja lopuksi laskee ja tulostaa näytölle lukujen keskiarvon.

  6. Kirjoita ohjelma, joka tulostaa näytölle kertotaulun 1 – 10. Muuta sitten ohjelmaa niin, että kertotaulun koon voi kirjoittaa koodin alussa vakion arvoksi.

  7. C-kielessä switch-lausetta käytetään tähän tapaan:

    switch (a) {
        case 1:
            printf("a on yksi.");
            break;
        case 2:
            printf("a on kaksi.");
            break;
        case 3:
            printf("a on kolme.");
            break;
        default:
            printf("a on jotain muuta.");
            break;
    }

    Mitä parannuksia tekisit tämän ehtorakenteen muodostukseen, jos olisit C-kielen suunnittelija?

Antti Laaksonen, 19.2.2004


Kommentit

Eero Harmaala [28.02.2004 10:09:51]

Lainaa #

Opas on kyllä ihan hyvä, mutta pari asiaa pistivät hiukan silmääni kolmannessa osassa. Ensinnäkin, #define:n sijaan olisi suositeltavaa käyttää const-muuttujia. Ei siinä mitään, etteikö #define toimisi, mutta sen toiminta perustuu vain siihen, että #define-"muuttujan" nimen teksti korvataan muuttujan sisällön tekstillä [Jos nyt tietoni pitävät paikkansa]. #define on kyllä ihan kätevä esimerkiksi makroissa, mutta olisi kyllä ihan järkevää tuoda esille const-tyyppiset vakiomuuttujatkin.

Toiseksi, kolmannen oppaan viimeisessä esimerkissa (siinä, missä osoittimia käytettiin useamman arvon palauttamiseen funktiosta) olisi ollut parempi käyttää viittauksia, jotta funktion kutsuminen ja kirjoittaminen olisi ollut helpompaa. Funktion prototyypissä ja määrittelyssä olisi täytynyt käyttää viittauksia (int &a, int &b, int &c), mutta muualla ei tarvitsisi käyttää yhtään osoitin- ja osoite-operaattoreita [eli & ja *, niistä nimistä en ole kyllä erityisen varma =) ]. Tosin, luulen että aiotkin käydä funktion toteuttamisen viittauksilla myöhemmin seuraavissa oppaan osissa, kun vaan pääset viittauksiin asti.

Opas on kyllä sisällöltään erinomainen, joten toivottavasti sinulla riittää voimia jatkaa sitä vielä monella osalla =D

Gwaur [28.02.2004 12:39:37]

Lainaa #

lainaus:

Ensinnäkin, #define:n sijaan olisi suositeltavaa käyttää const-muuttujia.

Eikös const ole vakio eli sellainen, minkä arvo ei voi muuttua? Const on lyhenne sanasta constant, joka on suomeksi vakio. Muuttujan nimi tuleekin juuri siitä, että sen arvo voi muuttua.

Antti Laaksonen [28.02.2004 14:29:43]

Lainaa #

Eero: Vakiot (#define) tosiaan korvaantuvat ohjelmassa niiden arvoilla ennen varsinaista kääntämistä. Tämä on mielestäni vakioiden tarkoitus, mutta kerro toki, mitä etuja const-muuttujien käytössä tarkalleen ottaen olisi. Viittauksia ei ole siksi, että niitä voi käyttää vain C++:ssa. Todennäköisesti C-oppaita tulee vielä ainakin kaksi. :)

Eero Harmaala [28.02.2004 16:54:17]

Lainaa #

Olen lueskellut aiheeseen liittyviä kirjoja ja ainakin useimmissa niistä on kehotettu välttämään #define:n käyttöä [#define taitaa hiukan lisätä alttiutta virheiden syntymiselle (tästä en ole täysin varma, mutta jotain tämän tapaista olen kuullut)], joten ajattelin vain mainita asiasta. Ei siis ollut tarkoitus väittää, että const olisi parempi, vaan vain tuoda esille se tosiasia, että const:in käyttö on myös mahdollinen tapa suorittaa vakion määrittely. Myönnän, että huomautukseni taisi olla vähän perusteeton, koska define toimii yhtä hyvin kuin const:kin. Ja kuten jo mainitsin, #define on hyvin kätevä makroissa ja sen sellaisissa, joissa sitä itsekin käytän.

Käytän nykyään enimmäkseen C++:aa, joten pääsi vähän unohtumaan se, ettei viittauksia voi käyttää C:ssä. Muuten... aiotko jossain vaiheessa kirjoittaa C++ -oppaan tai kenties käsitellä sitä C-oppaan myöhemmissä osissa?

Jaska [28.02.2004 20:13:29]

Lainaa #

Ainakin yksi constin etu vakioitä määriteltäessä tulee mieleen: constia käyttämällä kääntäjä tietää minkä tyyppistä arvoa vakio sisältää. Näin kääntäjä osaa valvoa ja varoittaa vakion vääränlaisesta käytöstä todennäköisemmin kuin esikäsittelijää käyttäessä.

Gwaur [29.02.2004 00:14:02]

Lainaa #

Vastaan tehtävään 7:
Tekisin niin, että lauseet jotka on case-rivien välissä voisi kirjottaa { } merkkien sisään, ettei tarvis break; komentoa ollenkaan. Ja defaultin muuttaisin elseksi kuten iffeissä on.

tomaattigeeni [29.02.2004 23:09:11]

Lainaa #

toi definehän toimii siten, että esikääntäjä muuttaa ne määritellyt vakiot arvoiksi, joten esikääntäjä näkee ohjelman tällaisena:
#define BLAA 10
...
if(BLAA == 10) { }
...

ja itse kääntäjä tällaisena:
if(10 == 10) { }

Gwaur [02.03.2004 16:43:05]

Lainaa #

Ja tietokone jotakuinkin tällaisena:
10111010010100110011010

=D heheh

hunajavohveli [21.03.2004 20:08:12]

Lainaa #

Hyvä opassarja. Olisi kiva saada vielä tietoa grafiikasta, äänestä, tiedostonkäsittelystä, Windows-ohjelmista ja muista edistyneemmistä asioista.

Gaxx [01.05.2004 23:13:20]

Lainaa #

lainaus:

Tekisin niin, että lauseet jotka on case-rivien välissä voisi kirjottaa { } merkkien sisään, ettei tarvis break; komentoa ollenkaan. Ja defaultin muuttaisin elseksi kuten iffeissä on.

Jos ne kirjotettas {}merkkien sisään, niin sittenhän siitä katois ominaisuus suorittaa monta case:a perätysten!!! Toi defaultin vaihto elseksi olisi tietysti ihan hyvä.

Metabolix [17.07.2004 19:20:24]

Lainaa #

lainaus:

Erillistä tietotyyppiä totuusarvolle ei ole.

Kyllä "bool" olisi syytä mainita jossakin. "true" ja "false" ovat ihan varattuja sanoja.

Antti Laaksonen [17.07.2004 19:25:18]

Lainaa #

Tämä opas käsittelee C-kieltä, jossa ei ole bool-tietotyyppiä ja joka ei tunne varattuja sanoja true ja false.

ZcMander [26.01.2005 14:20:10]

Lainaa #

const on parempi, koska kääntäjä ilmoittaa virheestä jos esim. merkkijonoa yritetään laittaa kokonaislukuun(int). definestä ei. Constille voi/pitää myös laittaa tyyppe(int, long, char).

phadej [18.02.2005 23:49:22]

Lainaa #

if (vuosi % 4 == 0 && ((vuosi % 100 == 0 && vuosi % 400 == 0) || (vuosi % 100 != 0 && vuosi % 400 != 0)) ) {
  printf("%d on karkausvuosi\n",vuosi);
} else {
  printf("%d ei ole karkausvuosi\n",vuosi);
}

;)

Sweiz [11.08.2005 23:38:47]

Lainaa #

Mä en ole vieläkään muuten tajunnut, mikä on jakojäännös.. Hehe

TeeVee [05.11.2005 17:48:36]

Lainaa #

Esim, viisi jaettuna kahdella, tulee kaksi ja jää jakojäännökseksi yksi.

feenix [22.12.2005 11:09:44]

Lainaa #

Sellainen vinkki kannattaisi vielä sisällyttää, että jos vertailussa on kiinteä numero tai muu, se kannattaa aina kirjoittaa ensin. Esimerkiksi:

if (5 == a)
jotain;

ennemmin kuin:

if (a == 5)
jotain;

Varsinkin aloittelija helposti unohtaa toisen yhtäsuuruusmerkin ja kirjoittaa (a = 5) ja sitten mietitään miksei mikään toimi.

Sale [06.07.2006 05:38:29]

Lainaa #

Vuosia välttelin ohjelmointia... Nyt tuli yksi simulointitehtävä eteen töissä, josta ei päässyt yli eikä ympäri. Kuukaudessa opin tämän oppaan ja parin esimerkkikoodin avulla ohjelmoimaan C:tä tyydyttävästi. Rohkea rokan syö.

Pekka Karjalainen [06.09.2006 16:56:02]

Lainaa #

Opas kirjoitti:

Koko taulukon sisältö ei voi olla nimittäin funktion parametrina.

Totta, mutta parametrinä voi olla struct, jonka sisällä on taulukko(ja). Typerä esimerkki seuraa. Tälle ominaisuudelle voi keksiä parempaakin käyttöä.

#include <stdio.h>

typedef struct {
  int taulu[10];
} Kuori;

void funktio (Kuori tavarat) {
  int i;
  printf ("Sain tavaraa, jonka arvot ovat:\n");
  for (i=0; i<10; ++i)
    printf ("%3d ", tavarat.taulu[i]);
}

int main (void) {
  Kuori vermeet = {{13,12,16,14,15,18,12,13,11,13}};
  funktio (vermeet);
  return 0;
}

Juhko [08.10.2006 18:18:33]

Lainaa #

Coolcoolcoolcoolcool!!!!!!!!!!!!!!!!!!!

Codeprofile [10.12.2006 10:14:01]

Lainaa #

Perfect! Tällä opas-sarjalla pääsee hyvin alkuun! Paitsi että mun hello world ohjelma tulostaa tekstin ja sulkeutuu samantien. Miten se Pause-juttu oikeen toimii (syntax error before "break")??

fronty [31.07.2007 15:01:01]

Lainaa #

Ihan hyvä opas sarjahan tämä kyllä on.
Olisin kyllä halunnut tässä oppaassa vakioiden yhteydessä mainittavan const-tyyppiset vakiot, tai mahdollisesti kakkososassa mainittavan vakiot mukaanlukien constin. Vaikka kyllähän constinkin arvon saa pointtereilla muutettua.
Ja totuusarvoista, voihan aina tehdä oman tietotyyppinsä niille jos sitä tarvitsee. :/

Torgo [02.04.2009 12:19:09]

Lainaa #

Const-vakio vs. define-vakio.

Ok. Constien käsittely ja optimointi on hieman kääntäjäkohtaistakin. Jotkut kääntäjät voivat optimoida niiden käytön hyvinkin, mutta pääperiaatteessa erot menevät näin:
Const on tyypitetty ja sen käsittely jää kääntäjälle. Define on tyypittämätön ja käsitellään jo esikääntäjän toimesta. Constille luodaan myös symboli ja varataan muistia normaalin muuttujan tapaan. Näin ollen constia on turvallisempi käyttää, koska sille tehdään tyyppitarkistukset ja sitä voidaan debugata symbolisen nimensä avulla.
Define puolestaan vain korvaa koodissa esiintyvät nimet suoraan literaaliarvollaan. Arvoa ei siis talleteta minnekään muistiin, jolloin säästetään (joskus arvokastakin) muistia. Teoriassa se on myös tehokkaampaa koska muistiosoituksia ei pitäisi tulla samaan tapaan. Todellinen tehokkuus selviää kuitenkin vain mittaamalla.
Sulautettuja järjestelmiä työkseni koodavana suosin mieluummin defineä, ellei constin käyttö ole erityisen perusteltua. Myös enumien käyttö vakioiden määrittelyyn on usein paikallaan. Constia voi käyttää esim. jos vakio ei olekaan mikään ennalta määrätty literaali vaan riippuu jollain tapaa ulkoisista tekijöistä.

Edit. ja täytyy myös muistaa että C ja C++ käsittelevät consteja eri tavalla. Yleensä se missä näkee suosituksia constin käyttöön on juuri C++ -oppaat, koska C++ hanskaa globaalit constit paremmin. C++:ssa ne linkitetään staattisesti, eikä dynaamisesti kuten C:ssä. Tällöin mainitsemani constien haittapuoli poistuu, mutta muuttaa niiden käyttöäkin hieman.

Mayson [05.02.2014 20:50:57]

Lainaa #

ja mä en jostain kumman syystä osaa muodostaa noista käännettävää ohjelmaa tai sit mä olen tippunut jostain kumman syystä kelkasta. eli siis ohjeistus ei ole mennyt perille tai selittäjä on jättänyt jotain ilmaisematta...

Metabolix [13.02.2014 21:13:14]

Lainaa #

Mayson, sinun olisi viisainta kysyä ongelmistasi keskustelualueella. Moni muu on jo osannut lukea tätä opasta, joten luultavasti et vain ole keskittynyt riittävästi. Suosittelen, että palaat ensimmäiseen ja toiseen osaan ja tahkoat niitä, kunnes ymmärrät ohjelmien perusrakenteen ja osaat sitten koota näistäkin koodeista kokonaisia ohjelmia.

Kirjoita kommentti

Huomio! Kommentoi tässä ainoastaan tämän oppaan hyviä ja huonoja puolia. Älä kirjoita muita kysymyksiä tähän. Jos koodisi ei toimi tai tarvitset muuten vain apua ohjelmoinnissa, lähetä viesti keskusteluun.

Muista lukea keskustelun ohjeet.
Tietoa sivustosta