Kirjoittaja: L2-K2
Kirjoitettu: 24.01.2008 – 24.01.2008
Tagit: koodi näytille, vinkki
Toisin kuin monissa tulkattavissa kielissä, C-kielessä funktiolle ei voi antaa ihan mitä tahansa parametrinä.
Esimerkiksi merkkijonoa ei voi antaa funktion parametriksi, koska se on oikeasti vain tieto siitä, missä merkkijonon ensimmäinen merkki sijaitsee.
Kuitenkin tietueet muodostavat tähän sääntöön poikkeuksen. Ne on mahdollista asettaa parametreiksi funktiolle. Tämä saattaa tuntua kätevältä ominaisuudelta, mutta sitä käyttäessään tulee olla varovainen.
Silloin kun tietue annetaan suoraan parametriksi funktiolle, kopioidaan se todellisuudessa _joka ikisen_ funktio-kutsun yhteydessä prosessorin puskurin kautta funktiolle. Vaikka tietokoneissa voi olla nykyään useita gigatavuja keskusmuistia, ei prosessorin sisäistä (nopeaa) muistia ole uusimmissakaan mikroprosessoreissa silti kuin joitain megatavua.
Kun tämä muisti täyttyy hidastuu tietokoneen toiminta merkittävästi. Siksi onkin hyvä lähettää (varasinkin isommista tietuista) vain niiden osoite aliohjelmille.
#include <stdio.h> #include <string.h> /* tietue Pallo */ typedef struct { char valmistaja[80]; float sx; float sy; float vx; float vy; } Pallo; /* funktioiden määrittelyt */ void alusta(Pallo *rantapallo); void laske(const float dt, Pallo *rantapallo); void tulosta(const Pallo *rantapallo); /* pääfunktio */ int main() { /* luodaan tietueesta jäsen */ Pallo rantapallo; /* funktion laske aikavakio */ const float dt=0.1f; alusta(&rantapallo); tulosta(&rantapallo); laske(dt, &rantapallo); tulosta(&rantapallo); return 0; } void alusta(Pallo *rantapallo) { /* kopioidaan strcpy:llä pallon valmistaja pallo-tietueeseen */ strcpy(rantapallo->valmistaja, "Oy Loimaan nahkakuula ja peruukkitehdas Ab."); rantapallo->sx = -3.0f; rantapallo->sy = 2.0f; rantapallo->vx = 8.0f; rantapallo->vy = -5.0f; return; } void laske(const float dt, Pallo *rantapallo) { /* lasketaan uudet sijainnit, huomioi, että pallon valmistajaa ei edes tarvittu */ printf("Lasketaan... "); rantapallo->sx += dt * rantapallo->vx; rantapallo->sy += dt * rantapallo->vy; printf("valmista tuli.\n"); return; } void tulosta(const Pallo *rantapallo) { /* tulostetaan pallon tiedot */ printf("Rantapallon, jonka valmistaja on %s ", rantapallo->valmistaja); printf("koordinaatit ovat (%.1f, %.1f).\n", rantapallo->sx, rantapallo->sy); return; }
Varsin asiallinen, koodi on kiitettävän selkeää. Esimerkki on kyllä niin turha sellaisenaan, että asia sopisi paremmin C-oppaan yhteyteen. :) Mutta niinhän ne perusasioiden esittelyt helposti ovat.
Tekstin lopussa ei erikseen tarvita nollamerkkiä, se on paikallaan ihan omatoimisesti (eli "moi\0" => "moi"). Lopputulos strcpy-funktiolla on sama, koska kopiointi loppuu ensimmäiseen nollamerkkiin. Void-tyyppisten funktioiden loppuun ei tarvita return-lausetta.
Hyvän koodaustavan mukaan tulosta-funktion parametrin pitäisi olla tyypiltään const Pallo*
, jotta olisi selvää, ettei se muutu (ja jottei sitä kukaan funktiossa vahingossa muuttaisi).
Aina pitää jostain päästä huomauttamaan. ;)
Metabolix: No muokataan sitten... return-lauseen podän paokallaan koska se on mielestäni selkeyttävä, tiedän sen olevan hyvinkin tarpeeton. Tämä on kuitenkin perustason koodivinkki.
Minusta mukava, että löytyy tälläisiä ihan perustason vinkkejä, jotka selkeästi esittelevät yhden asian tai kielen piirteen. Ei kaikkien tarvitse olla hienoja ja monimutkaisia järjestelmiä.
Tälläisistä on mielestäni se etu, että aloittelijat selkeästi näkevät yhdestä koodivinkistä miten kyseinen asia toteutetaan ja toimii. Harmillisesti koodivinkkihakemisto on vain hieman sekava, joten se haittaa tälläisten kieltä esittelevien perusvinkkien löytämistä.