Kirjoittaja: Antti Laaksonen (2004).
C-kielessä ei ole valmista keinoa tekstin tulostamiseen näytölle, tiedostojen käsittelyyn, neliöjuuren laskemiseen eikä moneen muuhunkaan tuiki tarpeelliseen asiaan. Tästä syystä jokaisen C-kääntäjän mukana on joukko ohjelmaan liitettäviä kirjastoja, joissa on juuri näitä usein käytettyjä funktioita. Yksi kirjastoista, stdio.h
, on kaiketi ennestään tuttu. Näistä kirjastoista käytetään yhdessä nimitystä standardikirjasto, ja kirjastot ja niiden funktiot ovat samat kääntäjästä riippumatta. Tässä oppaassa tutustutaan moniin standardikirjaston funktioihin.
Erillistä tietotyyppiä merkkijonoille ei ole, vaan merkkijono tallennetaan char-tyyppiseen taulukkoon. Jokainen merkkijonon merkki vie yhden alkion taulukossa, minkä lisäksi taulukon viimeisessä alkiossa on nollamerkki. Tästä syystä merkkijonon "esimerkki" tallentamiseen tarvitaan taulukko, jossa on kymmenen alkiota:
char mjono[10] = "esimerkki";
0 1 2 3 4 5 6 7 8 9 e s i m e r k k i \0
Merkkijonon merkkejä voi käsitellä aivan samalla tavalla kuin taulukon arvoja. Esimerkiksi edellisessä merkkijonossa mjono[0]
on merkki 'e' ja mjono[5]
on 'r'. Nollamerkin ansiosta tiedetään, milloin merkkijono päättyy. Seuraava koodinpätkä laskee merkkijonon pituuden:
char mjono[10] = "esimerkki"; int p = 0; /* kasvatetaan laskuria niin kauan, kuin merkki ei ole nollamerkki */ while (mjono[p] != '\0') { p++; } printf("Merkkijonon pituus on %d merkkiä.\n", p);
On tärkeää huomata, että koska merkkijonot ovat taulukoita, niitä ei voi vertailla ja yhdistellä tavallisten muuttujien tapaan. Jokaisessa merkkijonoihin liittyvässä toimenpiteessä täytyy ottaa huomioon, että merkkijono on taulukko.
Standardikirjastossa string.h
on joukko tavallisimpia merkkijonoihin liittyviä funktioita. Muun muassa seuraavat funktiot ovat käytössä silloin, kun string.h
on liitetty ohjelman alkuun #include
-komennolla:
strlen(mjono) Funktio palauttaa merkkijonon merkkien määrän. strcpy(kohde, lähde) Merkkijonon kopiointi toiseen merkkijonoon. strcmp(mjono1, mjono2) Kahden merkkijonon vertailu aakkosjärjestyksessä, palautusarvo: 1 (mjono1 suurempi), -1 (mjono2 suurempi) tai 0 (merkkijonot samat). strcat(mjono, jatke) Kahden merkkijonon yhdistäminen.
Tässä on edellisiin funktioihin liittyvä esimerkki:
#include <stdio.h> #include <string.h> /* merkkijonofunktiot */ int main(void) { char eka[4] = "esi", toka[7] = "merkki"; char tulos[12]; printf("%s %d\n", eka, strlen(eka)); /* näytetään eka ja sen pituus */ printf("%s %d\n", toka, strlen(toka)); /* näytetään toka ja sen pituus */ strcpy(tulos, eka); /* kopioidaan tulokseen eka */ strcat(tulos, toka); /* liitetään tulokseen toka */ printf("%s %d\n", tulos, strlen(tulos)); /* näytetään tulos ja sen pituus */ return 0; }
Merkkijonotaulukoiden, joiden lopussa on nollamerkki osoittamassa taulukon päättymisestä, käytössä piilee eräs vaara. Jos nollamerkin päälle epähuomiossa kirjoittaa jotain, merkkijonon loppua ei enää tiedetä, ja tietokoneen muistiin saattaa tallentua tietoa taulukon tilanvarauksen jälkeen. Näin voi käydä silloin, kun merkkijono kopioidaan tai yhdistetään liian pieneen taulukkoon. Funktiot strncpy
, strncmp
ja strncat
toimivat muuten samalla tavalla kuin esikuvansa, paitsi että niissä on kolmas parametri, joka ilmoittaa kopioitavien tai vertailtavien merkkien suurimman sallitun määrän.
Muuttujien liittäminen merkkijonon keskelle tapahtuu sprintf
-funktiolla, joka toimii lähes samalla tavalla kuin aiemmin tutuksi tullut printf
-funktio. Erona on se, että näytölle tulostamisen sijasta tiedot tallennetaan funktion ensimmäisenä parametrina olevaan merkkijonoon. Funktiossa on kuitenkin vaaransa, nimittäin merkkijonolle pitää olla tarpeeksi tilaa, tai tapahtuu kummia:
char edellinen[16] = "edellinen", mjono[16], seuraava[16] = "seuraava"; sprintf(mjono, "Lukujen %d, %d ja %d summa on %d.", 1, 2, 3, 1 + 2 + 3); printf("mjono = %s\n", mjono); /* "Lukujen 1, 2 ja 3 summa on 6." */ printf("edellinen = %s\n", edellinen); /* "edellinen" */ printf("seuraava = %s\n", seuraava); /* "3 summa on 6." <= Huomaa virhe! */
Edellä tapahtuvaa virhettä kutsutaan ylivuodoksi (engl. overflow). Siinä taulukon rajojen yli menevä tieto tallentuu taulukon jälkeiseen muistiin. Seurauksena voi olla esimerkiksi ohjelman kaatuminen tai tietojen muuttuminen.
Koodin saa turvalliseksi funktiolla snprintf
, joka toimii samalla tavalla kuin sprintf
mutta ottaa toisena parametrina maksimipituuden. Jos merkkijono on liian pitkä, se katkaistaan maksimipituuteen. Tavallisen taulukon koon saa selville kätevästi sizeof
-operaatiolla.
char edellinen[16] = "edellinen", mjono[16], seuraava[16] = "seuraava"; /* Täytetään enintään taulukon koon verran (sizeof(mjono)). */ snprintf(mjono, sizeof(mjono), "Lukujen %d, %d ja %d summa on %d.", 1, 2, 3, 1 + 2 + 3); printf("mjono = %s\n", mjono); /* "Lukujen 1, 2 ja" <= Teksti katkeaa. */ printf("edellinen = %s\n", edellinen); /* "edellinen" */ printf("seuraava = %s\n", seuraava); /* "seuraava" */
Samoin kuin sprintf
muuttaa tietoa merkkijonoksi, sscanf
-funktio lukee merkkijonosta mallin mukaan tietoa muuttujiin. Tämän lisäksi merkkijonossa olevan luvun muuttaminen lukumuuttujaksi tapahtuu funktioilla atoi
(int), atol
(long) ja atof
(double) palautettavan muuttujatyypin mukaan.
Tulostukseen käytettävä funktio printf
ja syötettä lukeva scanf
ovat jo vanhoja tuttuja oppaan edellisistä osista. Aikaisemmin näiden funktioiden toimintaan on viitattu helppotajuisilla ilmauksilla "kirjoittaminen näytölle" ja "lukeminen näppäimistöltä". Näin usein onkin, mutta ei kuitenkaan aina. Esimerkiksi jos ohjelma käynnistetään komentorivillä seuraavalla tavalla, syöte luetaan tiedostosta luku.txt ja tulostus tapahtuu tiedostoon kirjoitus.txt.
ohjelma < luku.txt > kirjoitus.txt
Standardikirjastossa stdio.h
on muutama muu tulostamiseen ja syötteen lukemiseen liittyvä funktio: putchar
ja getchar
yhden merkin tulostamiseen tai lukemiseen, sekä puts
ja gets
yhden rivin tulostamiseen tai lukemiseen. Kun käytetään funktiota gets
, merkkijono luetaan kokonaan rivin loppuun asti, vaikka siinä olisi välilyöntejä.
char nimi[30]; /* tämän taulukon täytyy olla riittävän iso luettavalle merkkijonolle */ printf("Kirjoita nimesi: "); gets(nimi); printf("Terve, %s!\n", nimi);
Tiedostojen käsittelyyn liittyvät funktiot sisältyvät nekin stdio.h
-kirjastoon. Aluksi ohjelmaan täytyy kirjoittaa tiedosto-osoittimen määrittely:
FILE *tiedosto;
Tämän jälkeen tiedoston avaaminen lukemista tai kirjoittamista varten tapahtuu fopen-funktiolla. Ensimmäisenä parametrina on tiedoston nimi, ja toisena parametrina on avaustapa. Kun käsitellään tekstitiedostoja, avaustapa on "r" (luku), "w" (kirjoitus) tai "a" (kirjoitus loppuun). Jos kirjoitettavaa tiedostoa ei ole olemassa, se luodaan.
tiedosto = fopen("testi.txt", "w");
Nyt tiedosto sisältää avatun tiedoston osoittimen, jota käytetään jatkossa muissa tiedostofunktioissa. Jos tiedoston avaaminen epäonnistuu, osoittimeksi tulee NULL
, joka on mm. stdio.h
-kirjastossa määritelty vakio. Huom! Jos tiedostonimessä on mukana koko hakemistopolku (esim. "c:\omat\testi.txt"), täytyy kenoviivoja olla niiden erityismerkityksen vuoksi kaksi ("c:\\omat\\testi.txt").
Tekstitiedostoihin liittyvät funktiot ovat samantapaisia kuin tulostus- ja syöttöfunktiot; niiden edessä vain on f-kirjain ja yhtenä parametrina on tiedoston osoitin. Kirjoitusfunktioita ovat fprintf
, fputs
(yksi rivi, ei lisää rivinvaihtoa kuten puts!) ja fputc
(yksi merkki), ja lukufunktioita ovat fscanf
, fgets
ja fgetc
. Tässä kirjoitetaan avattuun tiedostoon kolme lukua samalle riville.
fprintf(tiedosto, "%d %d %d\n", 12, 34, 56);
Äsken kirjoitetut luvut voisi lukea tiedostosta näin (avaustapa tietenkin "r"):
fscanf(tiedosto, "%d %d %d", &luku1, &luku2, &luku3);
Kun tiedostosta on luettu tai siihen on kirjoitettu tarvittavat tiedot, tiedosto täytyy lopuksi sulkea. Tämä tapahtuu fclose-funktiolla.
fclose(tiedosto);
Välillä ei ole ennalta tiedossa, kuinka paljon tietoa tiedostossa on. Tällöin voidaan käyttää funktiota feof
, jonka palautusarvo on tosi, kun tiedosto on luettu loppuun asti. Tässä on kokonainen ohjelma, joka lukee tiedoston kaikki rivit ja tulostaa ne näytölle. Ohjelmassa on mukana myös virheenkäsittely siltä varalta, että tiedostoa ei olekaan olemassa.
#include <stdio.h> int main(void) { FILE *tiedosto; /* tähän taulukkoon rivi luetaan ennen sen tulostamista */ char rivi[127]; /* avataan tekstitiedosto lukemista varten */ tiedosto = fopen("testi.txt", "r"); /* onnistuiko tiedoston avaaminen? */ if (tiedosto != NULL) { /* jatketaan tiedoston loppuun asti */ while (!feof(tiedosto)) { /* luetaan seuraava rivi (kuitenkin korkeintaan 127 merkkiä) */ fgets(rivi, 127, tiedosto); /* tulostetaan näytölle äsken luettu rivi */ printf("%s", rivi); } fclose(tiedosto); } else { printf("Myttyyn meni!\n"); } return 0; }
Jos tiedosto avataan binäärimuodossa, avaustapa on "rb", "wb" tai "ab", ja kirjoitukseen ja lukuun käytetään funktioita fwrite
ja fread
.
Matemaattiset funktiot ovat kirjastossa math.h
. Seuraavassa taulukossa on muutama usein tarvittava kirjastossa oleva funktio:
pow(luku, eksp) potenssilasku sqrt(luku) neliöjuuri ceil(luku) pyöristys ylöspäin (kok.luvuksi) floor(luku) pyöristys alaspäin (kok.luvuksi) sin(luku) sinifunktio cos(luku) kosinifunktio tan(luku) tangenttifunktio
Seuraava ohjelma laskee suorakulmaisen kolmion hypotenuusan pituuden, kun kaksi kateettia on tiedossa. Suorakulmaisessa kolmiossa on voimassa Pythagoraan lause a2 + b2 = c2, jossa a ja b kuvaavat kateetteja ja c on hypotenuusa. Sen vuoksi hypotenuusan pituus lasketaan kaavalla c = √(a2 + b2).
#include <stdio.h> #include <math.h> /* matematiikkafunktiot */ int main(void) { float k1, k2, h; printf("Kirjoita kolmion kateettien pituudet: "); /* kysytään pituudet käyttäjältä välilyönnillä erotettuina */ scanf("%f %f", &k1, &k2); /* lasketaan hypotenuusan pituus kateettien perusteella */ h = sqrt(pow(k1, 2) + pow(k2, 2)); /* tulostetaan hypotenuusan pituus kahden desimaalin tarkkuudella */ printf("Hypotenuusan pituus on %.2f\n", h); }
Kirjastossa time.h
on päivämääriin ja aikoihin liittyviä funktiota. Päivämäärien tallennusmuoto on kuluneiden sekuntien määrä hetkestä 1.1.1970. Tämänhetkisen päivämäärän ja ajan saa selville funktiolla time
, ja sekuntiluvun muuttaminen järkevämpään muotoon tapahtuu esimerkiksi funktiolla localtime
. Seuraava esimerkki tulostaa näkyviin päivämäärän, kellonajan sekä pari muuta tietoa.
#include <stdio.h> #include <time.h> /* päivämääräfunktiot */ int main(void) { time_t nyt; /* sekuntiluku */ struct tm *aika; /* päivämäärätietue */ time(&nyt); /* haetaan tämänhetkinen päivämäärä */ aika = localtime(&nyt); /* muutetaan päivämäärä järkevään muotoon */ printf("Nyt on %d.%d.%d %d:%d:%d\n", aika->tm_mday, aika->tm_mon + 1, 1900 + aika->tm_year, aika->tm_hour, aika->tm_min, aika->tm_sec); printf("Viikonpäivä %d, vuodenpäivä %d\n", aika->tm_wday, aika->tm_yday); printf("%d\n", nyt); }
Tietueen osoittimen yhteydessä käytetään merkintää ->
. Päivämäärän esitykseen liittyy muutamia huomionarvoisia asioita: Jostain syystä kuukausien laskeminen aloitetaan nollasta, eli tammikuu on 0 ja joulukuu on 11. Vuoteen täytyy lisätä 1900, eli vuosi 2004 on ilmoitettu muodossa 104. C-kielen (ja amerikkalaisten) mukaan viikko alkaa sunnuntaista, eli 0 on sunnuntai ja 6 on lauantai.
Satunnaislukuihin liittyvät funktiot ovat kirjastossa stdlib.h
. Satunnaislukugeneraattorin alustaminen tapahtuu srand
-funktiolla, ja tavallisesti siemenlukuna käytetään senhetkistä aikaa. Samalla siemenluvulla on satunnaislukusarja aina sama. Sen jälkeen rand
-funktio palauttaa luvun ainakin väliltä 0 – 32767. Näppärä keino laskea tästä luvusta satunnaisluku omavalintaisella asteikolla on käyttää jakojäännöstä apuna. Seuraava ohjelma arpoo kymmenen satunnaislukua väliltä 0 – 9.
#include <stdio.h> #include <time.h> #include <stdlib.h> /* satunnaisluvut */ int main(void) { int i; time_t siemen; time(&siemen); /* alustetaan satunnaislukugeneraattori */ srand(siemen); /* tulostetaan kymmenen satunnaislukua väliltä 0 - 9 */ for (i = 0; i < 10; i++) { printf("%d\n", rand() % 10); } }
Tässä oppaassa ei ole ollut mahdollista esitellä kuin murto-osa standardikirjaston funktioista. Lisää tietoa kirjastoista ja funktioista on esimerkiksi seuraavilla Internet-sivustoilla:
Standardikirjaston lisäksi on olemassa lukematon määrä muita kirjastoja mitä erilaisimpiin tarkoituksiin. Omia kirjastoja voi tietysti tehdä myös itse.
Kuinka merkkijonot tallennetaan C-kielessä?
Seuraavan koodinpätkän kirjoittaja on tehnyt montakin virhettä merkkijonojen käsittelyssä. Tee korjaukset.
char nimi[10]; nimi = "esi"; nimi = nimi + "merkki"; if (nimi == "esimerkki") { printf("Ohjelma toimii!\n"); }
Mitä yhteisiä piirteitä löydät näytölle tulostamisesta ja näppäimistön lukemisesta, merkkijonojen käsittelystä ja tiedostojen käsittelystä?
Kirjoita ohjelma, joka tulostaa tiedostoon alkuluvut väliltä 2 – 100. Alkuluku on luku, joka on jaollinen pelkästään yhdellä sekä itsellään. Ensimmäiset alkuluvut ovat 2, 3, 5, 7, 11 ja 13. Hyödynnä jakojäännöstä!
Kirjoita ohjelma, joka laskee ja tulostaa näytölle tiedostossa olevien aakkosmerkkien määrän (isojen ja pienten kirjainten välille ei eroa). Esimerkkitiedosto:
Tässä kaikki!
Ja vastaava tulostus:
A 1 I 2 K 3 S 2 T 1 Ä 2
Kirjoita ohjelma, joka ratkaisee toisen asteen yhtälön. Jos yhtälö on ax2 + bx + c, niin ratkaisukaava on x = (-b ± √(b2 - 4ac)) / 2a
.
Kirjoita ohjelma, joka tarkistaa henkilötunnuksen oikeellisuuden. Tietoa henkilötunnuksen muodostumisesta on esim. täällä.
Ovatko rand
-funktion tuottamat satunnaisluvut oikeasti satunnaisia?
(Vaikea:) Tee itse localtime
n tapainen funktio, joka laskee sekuntiluvun perusteella päivän, kuukauden, vuoden, tunnit, minuutit ja sekunnit.
Kaikkien tehtävien ratkaisut tulevat opassarjan seuraavaan osaan, joka on samalla viimeinen!
Antti Laaksonen, 8.4.2004
Hienoa jatkoa opassarjalle. Näistä asioista kaipasinkin lisää tietoa.
voisko joku lähettää mul gtk.h tiedoston, ku se herjaa tälläst: Fatal error:unable to open input file 'gtk/gtk.h'
---error level:1
Oikein mukava opas!
http://www.tp.spt.fi/~jnie/ckurssi/
Tuossa on lisää C-harjoituksia, kun niitä monet on kysellyt.
Koskas on tulossa seuraavaa opasta vai tuleeko?
miksi strlen lopettaa laskemiseen tyhjään merkkiin
esim .
nimi = "pekka pasanen"; strlen(nimi);
palauttaa arvoksi 6
Miten voi tehdä omia kirjastoja?
Milloin tulee seuraava C-opas?
Eipä tunnu näkyvän... (^)
miksi strlen lopettaa laskemiseen tyhjään merkkiin
esim .
nimi = "pekka pasanen";
strlen(nimi);
palauttaa arvoksi 6
Mullekkin käy näin.
Olis kiva jos toi opassarja jatkuis ja siellä selitettäis jotain hyödyllistä niinkun vaikka et miten saadaan ikkuna ruudulle jossa on jotain tekstiä..
Kun kerran mainitaan strncpy ja kumppanit, mieluummin opetettaisi käyttämään näitä. Normaaleilla funktioilla niin helposti ei tarkisteta pituuksia ja mennään metsään.
C:llä (jota tämä opassarja käsittelee) ei sitä ikkunaa saa ruudulle. Tämä täytyy hoitaa käyttisriippuvaisella tavalla käyttäen jotain kirjastoa (joko suoraan vaikkapa WinAPI:a tai monelle alustalle kääntyvää kirjastoa esim. SDL:ää, joka sekin Windowssissa käyttää WinAPI:a).
Omia kirjastoja on helppo tehdä: teet vain .h-tiedostoon funktioiden esittelyt ja .c-tiedostoon toteutukset. Sitten voit käyttää kirjastoasi kun annat projektissa esikääntäjälle määrityksen #include "munkirjasto.h". Toki tämä .c-tiedosto on käännettävä mukana tai linkitettävä muulla tavalla.
Mun käsityksen mukaan merkkijonon viimeinen merkki nolla, joten esim merkkijono[10] mahtuu 10 merkkiä:
0 1 2 3 4 5 6 7 8 9 10 E S I M E R K K I ! \0
speedy69: Se on valitettavasti väärä käsitys. Merkkijono[10] sisältää kymmenen alkiota eli alkiot 0-9. Tällöin siihen mahtuu kymmenen merkkiä, joista viimeinen on se nollamerkki. "Käytettäviä" merkkejä on siis vain yhdeksän.
yritin tehdä tota tehtavää 4 ja se sanoo, että expected primary-expression before "else". Eli osaako joku kokeneenpi sanoo, missä vika, itellä kun on tää koodaus vielä aika alussa.
tässä ongelmaosa koodista
while(1){ if (b!=a){ if (b!=0) { if (a%b==0){ printf("%i",a); break;} }}} else if (100<=b){ <--kone valittaa tästä break} else if (b<=100){ <--ja tästä b++;} }
Tossa näyttäis tuo while lause loppuvan ennen kun tulee tuo else if eli koita esim poistaa break;}<- eli tuo hakasulku.
flip92 kirjoitti:
nimi = "pekka pasanen";
strlen(nimi);
Yllä kirjoitettiin, että tämä palauttaa virheellisesti arvon 6. Itse asiassa täsmälleen ylläolevan kaltainen koodi ei palauta mitään arvoa, vaan strlen-funktion arvo heitetään hukkaan sen jälkeen, kun se lasketaan. Tämä siis, jos koodi oli täsmälleen esittämänne tapaista.
Jos teillä on vielä tämä ongelma, näyttäkää kokonainen ohjelma missä tulee väärä arvo. Esimerkiksi:
printf("%d", strlen (...));
tai
return strlen (...);
käyttävät tätä saatua arvoa johonkin. Vain silloin selviää mikä se on. Kannattaa aina esittää tarpeeksi koodia, että ongelma voidaan selvittää.
Laittaa sis jotain tällaista näkyviin, jos haluatte selvittää ongelman parhaiten.
#include <stdio.h> #include <string.h> int main (void) { printf ("%d", strlen("Pekka Pasanen")); return 0; }
Tämä tulostaa arvon 13 minulla. 6 olisi ilman muuta virhe kirjaston toteutuksessa.
:-)
string.h
sisältää myös string
-tietotyypin määrittelyn.
ZcMander kirjoitti:
Miten voi tehdä omia kirjastoja?
Omia kirjastoja saa tekemällä .h-päätteisiä tiedostoja ja liittämällä ne muihin lähdekooditiedostoihin. Esimerkiksi:
esimerkki.h
#ifndef ESIMERKKI_H #define ESIMERKKI_H void funktio(); #endif /* ESIMERKKI_H
funktio.c
.. void funktio() { .. }
main.c
#include "esimerkki.h" .. int main(void) { .. }
Käännä
$gcc -c main.c funktio.c $gcc main.o funktio.o -o esimerkki
Ohjelman jakaminen useampiin tiedostoihin on monelta kantilta kätevää.
- Suurempi ryhmä voi työskennellä paremmin saman ohjelman teossa. Jokainen työstää omaa tiedostoansa.
- Voidaan käyttää joitain olio-ohjelmoinnin ominaisuuksia.
- Yksi tiedosto voi sisältää kaikki yhden sortin operaatioita hoitavat funktiot.
- Monessa tapauksessa on ohjelman osien siirtäminen toiseen ohjelmaan helppoa, kopioidaan vain tiedosto toisen ohjelman lähdekoodien joukkoon.
Jos jaetaan ohjelma useaan tiedostoon, kannattaa pitää pääfunktio omassa tiedostossansa, useimmiten tiedostossa main.c. Siihen sitten liitetään tarvittavat headerit ja kääntämisen yhteydessä linkataan muita tiedostoja.
LTY:n uudella Käytännön Ohjelmointi-kurssilla on käytössä ohjelmointiopas, joka sisältää esimerkkejä ja juttua C-ohjelmoinnin perusteista.
http://www.it.lut.fi/kurssit/07-08/CT20A0210/oppaat/C-ohjelmointiopas_LTY.pdf
Opas on pitkälti suunnattu Pythonilla alkeet opetelleille, mutta kaipa nuo esimerkit auttaa muitakin uusia ohjelmoijia.
Antti Laaksonen oppaassaan kirjoitti:
Kaikkien tehtävien ratkaisut tulevat opassarjan seuraavaan osaan, joka on samalla viimeinen!
Mahtaa olla melkoinen opus tulossa, kun kohta neljä vuotta kestänyt sen väsääminen.
"The Massive C Programming Tutorial - From Newbie To Career Programmer by Antti Laaksonen" :D
time.h kirjastoon ja stdlib.h kirjastoon lisää selostusta en vieläkään ole oppinut
TsaTsaTsaa kirjoitti:
Antti Laaksonen oppaassaan kirjoitti:
Kaikkien tehtävien ratkaisut tulevat opassarjan seuraavaan osaan, joka on samalla viimeinen!
Mahtaa olla melkoinen opus tulossa, kun kohta neljä vuotta kestänyt sen väsääminen.
Yhdeksän vuotta jo laskurissa... Veikkaan sanamääräksi n. 100000000 :)
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.