Helsingin yliopisto Tietojenkäsittelytieteen laitos
 

Tietojenkäsittelytieteen laitos

Tietoa laitoksesta:

 
Helsingin yliopisto / Tietojenkäsittelytieteen laitos / Copyright © 2000 Jan Lindström. Tämän oppimateriaalin käyttö on sallittu vain yksityishenkilöille opiskelutarkoituksissa. Materiaalin käyttö muihin tarkoituksiin, kuten kaupallisilla tai muilla kursseilla, on kielletty.

58127-1 C-ohjelmointi : 3 Syöttö ja tulostus


  • 3 Syöttö ja tulostus

    3 Syöttö ja tulostus

    Syöttö ja tulostus eivät kuulu itse C-kieleen, vaan välineitä siihen on C-standardiin kuuluvassa kirjastossa stdio. Kirjasto määrittelee kolme tyyppiä, useita makroja ja lukuisan joukon funktioita, jotka suorittavat syöttö- ja tulostustoimintoja. Tyypit ovat FILE ja fpos_t.

    C-kielen yhteydessä syötön ja tulostuksen kuvaamiseen käytetään tietovirran käsitettä. Tietovirta kuvaa laitteita kuten päätettä tai magneettinauhaa tai levytiedostoja. Tietovirta on käsitteellinen yleistys, jota käytettäessä ei viitata erilaisten laitteiden erikoisominaisuuksiin. Tietovirtoja on kahdenlaisia: tekstivirtoja ja binäärivirtoja.

    Tekstivirta on jono merkkejä, jotka muodostavat rivejä. Kunkin rivin lopussa on rivinvaihtomerkki. Rivi voi olla tyhjä, mutta silloinkin sen lopussa on rivinvaihtomerkki. Koska eri tietokoneissa on erilaisia tapoja esittää tekstiä, syöttöä tai tulostusta suorittavat funktiot saattavat muuttaa tekstivirtojen merkkejä taikka lisätä tai poistaa niitä. Tyypillinen esimerkki on rivinvaihtomerkki, jota saattaa vastata yksi erikoismerkki mutta myös erikoismerkkipari. Toteutuksesta riippumatta C-kielessä rivinvaihtomerkin tulee olla '\n', t.s. rivinvaihdon kohdalla esim getchar-funktion tulee palauttaa arvonaan kyseinen merkki.

    Tekstivirrasta luettavan tekstin ei välttämättä tarvitse täsmälleen vastata sitä, mitä sinne on aiemmin kirjoitettu, paitsi silloin, kun teksti koostuu kokonaisista riveistä, jotka sisältävät vain kirjoittuvia merkkejä sekä seuraavia ohjausmerkkejä: tabulaattoreita, rivinvaihtoja, pystysuoria tabulointeja ja sivunvaihtoja.

    Binäärivirta on jono tavuja, jotka sisältävät tietoa tietokoneen sisäisestä esitysasusta. Binäärivirrasta luettu tieto vastaa täsmälleen sinne aiemmin kirjoitettua. Tulostuksen yhteydessä järjestelmä kuitenkin saattaa lisätä binäärivirtaan nollatavuja (NULL-merkkejä).


    3.1 Tiedostot

    Tietovirta liitetään ulkoiseen tiedostoon avaamalla tiedosto, mikä voi tarkoittaa myös uuden tiedoston perustamista. Vanhan tiedoston uudelleen perustaminen tuhoaa sen vanhan sisällön.

    Tiedostoon liittyy tiedosto-osoitin (FILE *), joka osoittaa kohtaa, johon seuraava tiedosto-operaatio kohdistuu. Kun tiedosto on liitetty tietovirtaan, tämä osoitin osoittaa tiedoston alkuun, siis ensimmäiseen merkkiin. Luettaessa tiedostosta ja kirjoitettaessa tiedostoon osoittimen arvo päivittyy automaattisesti.

    Kun tietovirta on puskuroimaton, ohjelma lukee tai kirjoittaa merkit välittömästi. Kun tietovirta on puskuroitu, järjestelmä kokoaa merkit ns. puskuriin ja lukee tai kirjoittaa jaksoissa, kun puskuri on täyttynyt.

    Tiedoston ja tietovirran välinen yhteys poistetaan sulkemalla tiedosto. Käynnistyessään ohjelma aina avaa automaattisesti kolme ennaltamääriteltyä tekstivirtaa:

    • standardisyöttövirta (standard input stream) stdin

    • standarditulostusvirta (standard output stream) stdout

    • standardivirhevirta (standard error stream) stderr

    Usein standardivirrat liitetään päätteeseen.


    3.2 Formatoitu tulostus (printf)

    Funktiolla printf kirjoitetaan formatoidusti standarditulostusvirtaan stdout. Funktion kutsu on muotoa
    printf(formaatti, arg1, ..., argn)
    
    ,missä formaatti on merkkijono, joka määrää tulostuksen ulkoasun, ja arg1, ..., argn ovat lausekkeita, joita voi olla mielivaltainen määrä (myös nolla). Standardin mukaan funktio palauttaa tulostamiensa merkkien määrän tai virheen sattuessa negatiivisen arvon.

    Formaatti on merkkijono, joka koostuu sellaisinaan tulostuvista merkeistä ja kentänmäärittelyistä. Argumenttien määrän ja tyyppien tulee vastata kenttämäärittelyitä. Muussa tapauksessa tulos on määrittelemätön (kääntäjä ei välttämättä ilmoita mitään). Kenttämäärittelyt alkavat %-merkillä. Kenttämäärittelyt ja argumentit vastaavat toisiaan annetussa järjestyksessä, so. formaatin k:s kentänmäärittely määrää argumentin argk tulostusmuodon. Kentänmäärittelyt määräävät, mitä muutoksia funktio kohdistaa argumenttiensa arvoihin niitä tulostaessaan.

    Koska formaatin muu teksti kuin kentänmäärittelyt tulostuu sellaisenaan, sitä käytetään suorasanaisen tekstin, lukujen välisen tyhjän tilan yms. tulostamiseen. Kentänmäärittely koostuu %-merkistä ja seuraavista osista tässä järjestyksessä:

    • Lippuja (flags), jotka modifioivat kentänmäärittelyn merkitystä.

    • Minimikentänleveys, joka ilmaistaan kokonaislukuvakiolla. Jos tulosteessa on kentänleveyttä vähemmän merkkejä, tulee kenttään täytemerkkejä vasemmalle (tai oikealle, jos formaatissa on vasemmalletasauslippu). Täytemerkit ovat välilyötejä tai nollia. Jos tulosteessa on kentänleveyttä enemmän merkkejä, kenttä levenee tarpeeksi. Jos kentänleveyttä ilmaiseva kokonaislukuvakio alkaa nollalla, täytemerkkinä on nolla, muuten välilyönti.

    • Tarkkuus, joka koostuu pisteestä ja sitä seuraavasta kokonaisluvusta. Jos pistettä ei seuraa kokonaisluku, rakenne toimii kuten .0. Tarkkuus ilmoittaa:

      • tulostuvien numeroiden vähimmäismäärän kentänmäärittelykirjaimien d, i ,o, u, x ja X yhteydessä.

      • desimaalipisteen jälkeisten numeroiden määrän kentänmäärittelykirjaimien e, E ja f yhteydessä.

      • merkitsevien numeroiden enimmäismäärän kentänmäärittelykirjaimien g ja G yhteydessä.

      • merkkijonosta tulostuvien merkkien enimmäismäärän kentänmäärittelykirjaimen s yhteydessä.

    • Kokomäärite, joka on kirjain h, l tai L. Kokomäärite h ilmoittaa, että sitä seuraaviin kentänmäärittelykirjaimiin d, i, o, u, x ja X liittyvät argumentit ovat tyyppiä short tai unsigned short. Kokomäärite l ilmoittaa, että sitä seuraaviin kentänmäärittelykirjaimiin d, i, o, u, x ja X liittyvät argumentit ovat tyyppiä long tai unsigned long. Kokomäärite L ilmoittaa, että sitä seuraaviin kentänmäärittelykirjaimiin e, E, f, g ja G liittyvät argumentit ovat tyyppiä long double. Jos kokomäärite esiintyy jonkin muun kentänmäärittelykirjaimen yhteydessä, se jää vaikutuksetta.

    • Kentänmäärittelykirjain, joka on jokin kirjaimista c, d, e, E, f, g, G, n, o, p, s, u, x X tai %.

    Liput, minimikentänleveys, tarkkuus ja kokomäärite ovat valinnaisia. Sen sijaan kentänmäärittelykirjain on pakollinen. Esimerkiksi kentänmäärittelyssä %+7.4lf on lippu +, minimikentänleveys 7, tarkkuus .4, kokomäärite l ja kentänmäärittelykirjain f.

    Liput ja niiden merkitys ovat seuraavat:

    • -: Vasemmalletasauslippu: tuloste tulee kentän vasempaan reunaan, ja täytemerkit siis tulevat oikealle kentän loppuun.

    • +: Tuloste alkaa aina etumerkillä (+ tai -).

    • tyhjä :Tulosteen alkuu tulee välilyönti, jos tulos on etumerkillinen ja positiivinen. Jos sekä + että tyhjä esiintyvät, tyhjä-lippu jää huomiotta.

    • #: Aiheuttaa vaihtoehtoisen tulostusmuodon, joka riippuu kentänmäärittelykirjaimesta seuraavasti:

      • c, d, i, s, u : ei vaikutusta.

      • o, x, X : ellei tuloste ole nolla sen alkuu tulee vastaavasti 0, ox tai 0X.

      • e, E, f, g, G: tulosteeseen tulee aina desimaalipiste, vaikka sitä ei seuraisi yhtään numeroa; normaalisti desimaalipiste esiintyy vain, kun sitä seuraa numero.

      • g, G: kentän loppuun voi tulla ylimääräisiä nollia.

    • 0: Täytemerkkinä käytetään välilyönnin sijasta nollaa. Lippua voidaan käyttää kentänmäärittelykirjaimien d, i, o, u, x, X, e, E, f, g, ja G yhteydessä, muille sen toiminta on määrittelemätön. Jos kuitenkin kentänmäärittelykirjaimien d, i, o, u, x ja X yhteydessä käytetään tarkkuutta, 0-lippu jätetään huomiotta.

    Kentänmäärittelykirjaimet ja niiden merkitys ovat seuraavat:

    • d, i : Vastaava kokonaislukuargumentti tulostuu etumerkillisenä kymmenjärjestelmän kokonaislukuna. Tarkkuusmääritteen oletusarvon on 1.

    • u : Vastaava kokonaislukuargumentti tulostuu etumerkittömänä kymmenjärjestelmän kokonaislukuna.

    • o : Vastaava kokonaislukuargumentti tulostuu etumerkittömänä oktaalisena kokonaislukuna.

    • x, X : Vastaava kokonaislukuargumentti tulostuu etumerkittömänä heksadesimaalisena kokonaislukuna. Tulosteen mahdolliset kirjaimet (a-f) ovat pieniä tai isoja sen mukaan, onko kentänmäärittelykirjaimena x vai X.

    • f : Vastaava reaalilukuargumentti tulostuu desimaalimuodossa
      [-]ddd.ddd
      
      Desimaalipisteen oikealla puolella olevien numeroiden lukumäärä on se, jonka kenttämäärittelyn sisältämä tarkkuus ilmoittaa, tai sen puuttuessa kuusi (kääntäjäkohtainen). Jos tarkkuus on ilmoitettu nollaksi, desimaalipiste ei tulostu. Jos desimaalipiste esiintyy tulostuksessa, vähintään yksi numero edeltää sitä. Tulostuksessa tapahtuu pyöristys tulostusasun määräämään tarkkuuteen.

    • e, E: Vastaava realilukuargumentti tulostuu eksponenttimuodossa
      [-]d.ddde±dd
      
      missä on yksi nollasta eroava numero ennen desimaalipistettä ja sen jälkeen tarkkuuden ilmoittama määrä numeroita. Jos tarkkuus on nolla, desimaalipiste ei tulostu. Tulostuksessa tapahtuu pyöristys tulostusasun määräämään tarkkuuteen. Eksponentti sisältää aina vähintään kaksi numeroa. Esityksessä on pieni tai suuri E-kirjain kentänmäärittelykirjaimen mukaan.

    • g, G: Vastaava reaalilukuargumentti tulostuu f- tai e-muodossa. Tarkkuus ilmoittaa merkitsevien numeroiden lukumäärän. Tulostus riippuu argumentin arvosta ja on mahdollisimman tiivis. Tuloste on eksponenttiesityksen mukainen vain, jos eksponentti on pienempi kuin -4 tai suurempi tai yhtäsuuri kuin tarkkuus. Ylimääräisiä loppunollia ei tulostu. Desimaalipiste tulostuu vain, jos sitä seuraa ainakin yksi numero.

    • c: Vastaava argumentti tulostuu yhtenä merkkinä.

    • s: Vastaava argumentti tulostuu merkkijonona. Argumentin tulee olla osoitin merkkijonoon, jonka lopussa on NULL-merkki. Merkkijonon merkit tulostuvat NULL-merkkiin saakka. Jos tarkkuus esiintyy, se määrää tulostuvien merkkien enimmäismäärän.

    • p: Argumentin tulee olla tyyppiä void *. Sen arvo muuntuu kirjoittuviksi merkeiksi ao. C-järjestelmässä määritellyllä tavalla.

    • n: Vastaava argumentin tulee olla osoitin kokonaislukumuuttujaan, joka saa arvokseen niiden merkkien lukumäärän, jotka printf-funktio siihen mennessä tämän kutsun aikana on kirjoittanut tulostusvirtaan. Mitään tulostusta ei siis tapahdu.

    • %: Tulostuu %-merkki.

    Tulostetaan kokonaisluku 123 eri formaateilla:

    %d     :123:
    %2d    :123:
    %3d    :123:
    %6d    :   123:
    % 6d   :   123:
    %06d   :000123:
    %-6d   :123   :
    %o     :173:
    %x     :7b:
    %X     :7B:
    %#o    :0173:
    %#X    :0X7B:
    
    Tulostetaan reaaliluku 123.456 eri formaateilla:
    %f        :123.456001:
    %.2f      :123.46:
    %2.f      :123:
    %10.4f    :  123.4560:
    %10.5f    : 123.45600:
    %-10.5f   :123.45600 :
    %010.5f   :0123.45600:
    %-+10.5f  :+123.45600:
    %+-10.4f  :+123.4560 :
    %10.0f    :       123:
    

    3.3 Formatoitu lukeminen (scanf)

    Funktiolla scanf luetaan formatoidusti standardisyöttövirrasta stdin. Funktion kutsu on muotoa:
    scanf(formaatti,arg1,...,argn);
    
    missä formaatti on merkkijono, joka määrää konversion, jonka funktio suorittaa argumentteja arg1,...,argn vastaavalle syötetiedolle. Argumentteja voi olla mielivaltainen määrä. Näiden argumenttien tulee olla osoittimia, sillä ne määräävät, mihin muistipaikkoihin scanf tallentaa lukemansa arvot.

    Jos scanf-kutsussa on vähemmän argumentteja, kuin formaatti edellyttää, funktion toiminta on määrittelemätön. Jos taas formaatti loppuu kesken, ylimääräiset argumentit jäävät huomiotta.

    Funktio scanf palauttaa arvon EOF, jos on sattunut virhe ennen yhtäkään konversiota. Muuten funktio palauttaa muistiin tallentamiensa tietoalkioiden lukumäärän. Tämä voi olla odotettua pienempi, jopa nolla, jos syötteet eivät vastaa formaattia. Formaatti voi sisältää kolmenlaisia osia:

    • Tyhjiä merkkejä (whitespace characters). Tyhjä merkki formaatissa aiheuttaa sen, että scanf lukee syöteissä mahdollisesti seuraavina olevia tyhjiä merkkejä, kunnes löytyy ei-tyhjä merkki. Jos formaatissa on peräkkäin useita tyhjiä merkkejä, niin vaikutus on sama kuin yhdellä.

    • Kentänmäärittelyjä, jotka alkavat %-merkillä ja aiheuttavat syöttötietojen lukemisen ja muuntamisen. Periaatteessa scanf lukee merkkejä kunnes a) tiedosto loppuu, b) löytyy tyhjä merkki tai muu kyseiseen kenttään sopimaton merkki tai c) luettujen merkkien määrä saavuttaa määritellyn maksimikentänleveyden.

    • Muita merkkejä. Kukin merkki aiheuttaa yhden merkin lukemisen syöttövirrasta. Jos se ei ole sama kuin formaatin sisältämä merkki, funktion toiminta loppuu ja tämä merkki palaa syöttövirtaan luettavaksi seuraavalla lukuoperaatiolla.

    Kentänmäärittelyiden ja osoitinargumenttien määrän ja tyyppien tulee vastata toisiaan. Muuten toiminta on ennalta määrittelemätön. Kentänmäärittely alkaa %-merkillä. Sitä seuraa tässä järjestyksessä:

    • Sijoituksenestomerkki *: scanf lukee syöttövirrrasta normaalisti kentänmäärittelyn mukaisen kentän mutta ei sijoita konversion tulosta muistiin ao. argumentin osoittamaan paikkaan, siis tämä kenttä ohittuu.

    • Maksimikentänleveys, joka on nollasta eroava etumerkitön kokonaisluku.

    • Kokomäärite, joka on jokin merkeistä h, l tai L. Kentänmäärittelykirjaimia d, i, n, u, o tai x voi edeltää kirjain h tarkoittaen sitä, että vastaava argumentti on osoitin muistipaikkaan, joka on tyyppiä short int tai unsigned short int, taikka kirjain l tarkoittaen tyyppiä long int tai unsigned long int. Kentänmäärittelykirjaimia e, f tai g voi edeltää kirjain l tarkoittaen sitä, että vastaava argumentti on osoitin muistipaikkaan, joka on tyyppiä double eikä float, tai kirjain L tarkoittaen tyyppiä long double.

    • Kentänmäärittelykirjain, joka on c, d, e, E, f, g, F, i, n, o, p, s, u, x, X, % tai [. Kentänmäärittelykirjain [ ei esiinny yksin, vaan sitä seuraa merkkejä, joista viimeinen on ].

    Sijoituksenestomerkki, maksimikentänleveys ja kokomäärite ovat valinnaisia. Sen sijaan kentänmäärittelykirjain on pakollinen. Funktion scanf kentänmäärittelyt ovat hyvin samanlaiset kuin edellä esitellyn printf-funktion. Erot ovat seuraavat:

    • scanf ei tunne kentänmäärittelyissä esiintyvää tarkkuutta eikä lippumerkkejä.

    • printf ei tunne vasenta hakasulkua [.

    • printf-funktiossa kentän leveys on minimi, scanf-funktiossa maksimi

    • tähdellä * on eri merkitykset.
    Kentänmääritelykirjaimet ja niiden merkitykset ovat seuraavat (tässä on esitetty vain perusteet, lue lisää kurssikirjasta):

    • d: Vastaavan argumentin tulee olla osoitin kokonaislukuun. Syötteen tulee olla kymmenjärjestelmän kokonaisluku. Lukiessaan syötettä scanf toimii seuraavasti. Ensin ohitetaan alussa olevat tyhjät merkit laskematta niitä mukaan maksimikentänleveyteen. Luvun edessä voi olla etumerkki (+ tai -), jota seuraa numero. Sen jälkeen luetaan merkkejä, kunnes tiedosto loppuu tai vastaan tulee merkki, joka ei ole numero tai on luettu maksimikentänleveyden verran merkkejä. Jos luettu merkkijono on tyhjä, seuraa paluu koko funktion kyseisestä kutsusta. Luetut merkit tulkitaan kymmenjärjestelmän kokonaisluvuiksi. Merkkijono muunnetaan etumerkilliseksi kokonaisluvuksi ja sijoitetaan argumentin osoittamaan paikkaan (ei tarkisteta onko tilaa varattu). scanf toimii analogisella tavalla lukiessaan syötteitä, jotka vastaavat kentänmäärittelykirjaimia i, u, o, x ja X.

    • i: Vastaavan argumentin tulee olla osoitin kokonaislukuun. Syötteen tulee olla kymmenjärjestelmän kokonaisluku, oktaalinen kokonaisluku tai heksadesimaalinen kokonaisluku.

    • u: Vastaavan argumentin tulee olla osoitin etumerkittömään kokonaislukuun. Syötteen tulee olla etumerkitön kymmenjärjestelmän kokonaisluku.

    • o: Vastaavan argumentin tulee olla osoitin kokonaislukuun. Syötteen tulee olla oktaalinen kokonaisluku.

    • x, X: Vastaavan argumentin tulee olla osoitin kokonaislukuun. Syötteen tulee olla heksadesimaalinen kokonaisluku. kentänmäärittelykirjaimet x ja X ovat täysin identtisiä ja kummatkin hyväksyvät numeroiden lisäksi kirjaimet abcdefABCDEF.

    • e, f, g: Vastaavan argumentin tulee olla osoitin realilukuun. Syötteen tulee olla desimaalimuodossa tai eksponenttimuodossa oleva realiluku.

    • s: Vastaavan argumentin tulee olla merkkijono-osoitin (char *). Ensin scanf ohittaa alussa olevat tyhjä merkit laskematta niitä kentänleveyteen. Sitten luetaan merkkejä, kunnes

      • tiedosto loppuu tai
      • vastaan tulee tyhjä merkki tai
      • formaatin mukainen maksimikentänleveys tulee täyteen
      Huomaa, että myös mm. rivinvaihto on tyhjä merkki.

    • c: Vastaavan argumentin tulee olla osoitin merkkiin (char *). Syöte on yksi tai useampi merkki. Huomaa, että nyt ei ohiteta tyhjiä merkkejä. Jos kentän leveyttä ei ole määritelty, luetaan täsmälleen yksi merkki.

    • n: Vastaavan argumentin tulee olla osoitin kokonaislukuun ja arvoksi tulee virrasta luettujen merkkien lukumäärä.

    • %: Syöttövirrasta odotetaan löytyvän %-merkin. Mitään sijoitusta ei tapahdu.

    Esimerkkejä:
    #include<stdio.h>
    
    int main(void)
    {
        int n,i;
        float x;
        char nimi[10];
    
        n = scanf("%d%f%s",&i,&x,nimi);
    }
    
    Jos annemme syötteenä rivin
    78 15.23e-1 Tero
    
    tällöin funktio palauttaa arvon 3, muuttuja i saa arvon 78, muuttuja x saa arvon 1.523 ja nimi arvon "Tero".

    #include<stdio.h>
    
    int main(void)
    {
      int n,i;
      float x;
      char sana[20];
    
      n = scanf("%2d%f%*d %[akKu]",&i,&x,sana);
    }
    

    Jos annamme syötteenä rivin

    123456 0987 Marja
    
    niin funktio palauttaa arvon 3, muuttuja i saa arvon 12, muuttuja x saa arvon 3456.0 ja sana saa arvon "Marja".

    3.4 Merkeittäin lukeminen (getchar)

    Funktion getchar määrittely on muotoa
    int getchar(void);
    
    Funktion getchar kutsu vastaa sellaista funktion getc (Muotoa int getc(FILE *tietovirta) ) kutsua, jossa argumentin tietovirta arvo on stdin. Funktio lukee tietovirrasta seuraavan merkin etumerkittömänä merkkinä, muuntaa sen kokonaisluvuksi (int) ja kasvattaa asianmukaisesti tiedosto-osoitinta. Funktio palauttaa tämän merkin. Jos tietovirta on lopussa, tiedostonloppuindikaattori asettuu ja palautetaan arvo EOF. Samoin käy, jos lukemisessa tapahtuu virhe. Esimerkiksi:

    #include<stdio.h>
    
    int main(void)
    {
        int c;
    
        while(( c = getchar() ) != EOF )
            putchar(c);
    
        return 0;
    }
    

    3.5 Riveittäin lukeminen (gets) ja tulostaminen (puts)

    Funktion gets määrittely on muotoa
    char *gets(char *s);
    
    Funktio lukee merkkejä standardisyöttövirrasta (stdin) taulukkoon, jota osoittaa s, kunnes tulee vastaan tiedoston loppu tai rivinvaihto. Funktio lisää tallentamansa merkkijonon perään NULL-merkin mutta ei rivinvaihtomerkkiä. Funktio palauttaa osoittimen s, jos kaikki menee hyvin. Jos heti tulee vastaan tiedoston loppu, taulukon sisältö pysyy muuttumattomana ja funktio palauttaa nollaosoitteen.

    Funktion puts määrittely on muotoa

    int puts(char *s);
    
    Funktio kirjoittaa s:n osoittaman merkkijonon standariditulostusvirtaan (stdout) ja lisää perään rivinvaihdon. Jos sattuu kirjoitusvirhe, funktio palauttaa arvon EOF, muuten funktio palauttaa positiivisen arvon. Esimerkki:
    #include<stdio.h>
    
    #define LINESIZE 80
    
    int main(void)
    {
       char line[LINESIZE + 1];
       int linenumber = 1;
    
       while( gets(line) != NULL )
       {
           printf("%6d\t",linenumber++);
           puts(line);
       }
       return 0;
    }
    


    Jan Lindström (Jan.Lindstrom@cs.Helsinki.FI)