Tietokoneen käytön ja ohjelmoinnin alkeet

Kurssin kotisivulle


9 C - osa 3, sekalaisia täydennyksiä

Komentoriviargumentit

Komentorivillä voidaan antaa numeerisia arvoja. Ne ovat merkkijonoja, jotka on muunnettava lukuarvoiksi ennen sijoittamista muuttujiin. Muunnoksia varten on olemassa funktiot atoi (ascii-to-int, muunnos kokonaisluvuksi), atol (kaksoistarkkuuden kokonaisluku), atof (kaksoistarkkuuden reaaliluku).

  main(int argc, char **argv)
 {
   int n ;
   float x ;
   ...
   n = atoi(argv[1]) ;
   x = atof(argv[2]) ;
   ..

}

Ohjelma voitaisiin suorittaa esimerkiksi komennolla

   ohjelma 1 2.5

Tyyppimuunnokset

Aritmeettisissa lausekkeissa muuttujien tyypit muunnetaan automaattisesti.

  int i ;
  float x ;
  i = 5/2 ;
  x = 5/2 ;

Jakolaskun 5/2 operandit ovat kokonaislukuja, joten tulos on myös kokonaisluku, jakolaskun kokonaisosa (2). Asiaan ei vaikuta, vaikka sijoituslauseen vasemmalla puolella olisi reaaliluku. Ohjelman jälkeen muuttujan i arvo on 2 ja muuttujan x 2.0.

Muuttujan tai vakion tyyppi voidaan muuttaa eksplisiittisesti:

  int i, j ;
  float x ;
  x = (float)i / j ;

Nyt i muunnetaan reaaliluvuksi, joten jakolasku tapahtuu reaalilukujen jakolaskuna.

Vastaavasti (int) muuntaa luvun kokonaisluvuksi. Muunnos reaaliluvusta kokonaisluvusta on katkaiseva; desimaaliosa heitetään pois ja luku pyöristetään nollaa kohti: 1.9 -> 1, -2.2 -> -2.

Seuraavassa esimerkkiohjelmassa esiintyy joitakin tyyppimuunnoksia. Kirjain L vakion perässä tarkoittaa, että kyseessä on kaksoistarkkuuden luku (long).


/*------------------------------------------------*/
/* convert between Gregorian calendar dates and   */
/* Julian day numbers                             */
/*------------------------------------------------*/
#include 
#include 
#include 
#include 
#include 

/* function prototypes ---------------------------*/
double julian0(int y, int m, int d) ;
long int day_number(int y, int m, int d) ;
void   gregor(long int dn, int *yy, int *mm, int *dd, int *wd) ;

main(int argc, char **argv)
{
  double jd ;
  long int dn ;
  int y, m, d, yy, mm, dd, wd ;

  if (argc==2)
  {
    jd = atol(argv[1]) ;
    dn = (long)(jd - julian0 (1900, 1,1)) ;
    gregor (dn, &y, &m, &d, &wd) ;
  }
  else if (argc==4)
  {
    y = atoi(argv[1]) ;
    m = atoi(argv[2]) ;
    d = atoi(argv[3]) ;
    jd = julian0 (y, m, d) ;
    dn = day_number(y, m, d) ;
    gregor (dn, &y, &m, &d, &wd) ;
  }
  else
  {
    fprintf(stderr,"usage: jd y m d   OR  jd julian_date\n") ;
    exit(1) ;
  }

  printf("%d.%d.%d  wd=%d  jd=%10.1lf\n", y,m,d,wd,jd) ;

}

/*------------------------------------------------*/
/* standard julian date                           */
/*------------------------------------------------*/
double julian0(int y, int m, int d)
{
  if (m <= 2)
  {  y-- ; m+=12 ; }
  return(floor(365.25*y) + floor(30.6001*(m+1)) + d +
         1720994.5 + 2.0 - y / 100 + y / 400) ;
}
/*------------------------------------------------*/
/* day number                                     */
/* dn = 0 <=> 1.1.1900                            */
/*------------------------------------------------*/
long int day_number(int y, int m, int d)
{
  return(367L*(y-1900)-7*(y+(m+9)/12)/4-3*((y+(m-9)/7)/100+1)/4+
         275L*m/9+d+3309L) ;
}
/*------------------------------------------------*/
/* convert day number to an ordinary date         */
/* wd: 1=mo, 2=tu, ..., 6=sa, 0=su                */
/*------------------------------------------------*/
void gregor(long int dn, int *yy, int *mm, int *dd, int *wd)
{
  long int j, y, m, d ;
  *wd = (int)(dn % 7) ;
  j = dn+693901L ;
  y = (4*j-1)/146097L ;
  j = (4*j-1)%146097L ;
  d = j/4 ;
  j = (4*d+3)/1461L ;
  d = ((4*d+3)%1461)/4 + 1 ;
  m = (5*d-3)/153 ;
  d = ((5*d-3)%153)/5 + 1 ;
  y = y*100+j ;
  if (m < 10)
      m+=3 ;
  else
     { m-=9 ; y++ ; }

  *yy = (int)y ;
  *mm = (int)m ;
  *dd = (int)d ;
}


Makrot

Aikaisemmin esiintyi muunnos asteista radiaaneiksi. Muunnoskerroin oli tavallinen muuttuja, jolle annettiin alkuarvo.

   float rad = 57.2958 ;
   ...
   x /= rad ;

Tämä ei ole turvallinen tapa, koska muuttujan rad arvoa voidaan muuttaa.

Määritellään vakion arvo direktiivillä:

  # define rad 57.2958

Tämä on oikeastaan makron määrittely. Kun kääntäjä näkee symbolin rad, se korvataan luvulla 57.2958.

Makroja voidaan myös käyttää taulukoiden koon määrittelyyn:

  # define N 100
  ...
  float taulu[N] ;
  ...
  for (i=0; i < N; i++) taulu[i]=0 ;

Kun taulukon todellinen koko ei sellaisenaan esiinny missään kohtaa ohjelmaa, kokoa voidaan helposti muuttaa vain makromäärittelyä muuttamalla.

Makroilla voi olla myös parametreja. Muunnokset radiaaneiksi ja asteiksi voitaisiin määritellä makroina

  # define rad(x)  x / 57.2958
  # define deg(x)  x * 57.2958

Nyt näitä voidaan käyttää kulmamuunnoksissa:

   a = sin(rad(x)) ;
   z = deg(acos(a)) ;

Makron kutsu vaikuttaa samanlaiselta kuin funktiokutsu. Makro ei ole funktio, vaan pelkkä lyhennysmerkintä. Kääntäjä vain korvaa makrokutsun sille define-direktiivillä määritellyllä tekstillä. Jos nyt kirjoitetaan

   a = rad(x + y) ;

tästä generoituu ohjelma

   a = x + y / 57.2958 ;

ja tulos ei luultavasti ole toivottu. Ongelma vältetään lisäämällä määrittelyyn sulut:

  # define rad(x)  (x) / 57.2958
  # define deg(x)  (x) * 57.2958

jolloin kutsu toimii kuten pitääkin:

   a = (x + y) / 57.2958 ;