Licencja Creative Commons

Autorem tego opracowania jest dr Piotr A. Dybczyński z Instytutu Obserwatorium Astronomiczne UAM w Poznaniu.


Definicja struktury

Struktura jest obiektem stanowiącym nazwaną grupę zmiennych o różnych typach. Struktury wprowadza się zwykle dla zwiększenia przejrzystości programu lub dla ułatwienia przekazywania większych ilości powiązanych ze sobą danych. Poniżej mamy przykład definicji struktury, zawierającej komplet elementów orbity a niżej deklarację dwóch zmiennych strukturalnych. W tym szczególnym przypadku wszystkie elementy są typu double.

struct orbita{
                 double q,               /*  perihelion distance           */
                        e,               /*  eccentricity                  */
                        peri,            /*  argument of perihelion        */
                        node,            /*  longitude of ascending node   */
                        i,               /*  inclination of the orbit      */
                        T;               /*  moment of perihelion passage  */
             };

struct orbita o1,o2;

// powyższe można zapisać krócej:

struct orbita{
                 double q,               /*  perihelion distance           */
                        e,               /*  eccentricity                  */
                        peri,            /*  argument of perihelion        */
                        node,            /*  longitude of ascending node   */
                        i,               /*  inclination of the orbit      */
                        T;               /*  moment of perihelion passage  */
             } o1,o2;

// można też skorzystać z możliwości definiowania własnego typu:

typedef struct{
                 double q,               /*  perihelion distance           */
                        e,               /*  eccentricity                  */
                        peri,            /*  argument of perihelion        */
                        node,            /*  longitude of ascending node   */
                        i,               /*  inclination of the orbit      */
                        T;               /*  moment of perihelion passage  */
              }orbita;

orbita o1,o2;
 

Do elementów struktury odwołujemy się w programie jak do zmiennych korzystając z notacji o1.peri, o2.e itp. W takim zapisie przed kropką (operatorem selekcji) występuje nazwa struktury (jednoznacznie identyfikująca miejsce jej przechowywania w pamięci komputera) a po kropce nazwa elementu (komponentu, składnika) struktury. Kolejność elementów w strukturze wpływa jedynie na kolejność ich umieszczenia w pamięci.

Wskaźniki do struktur i ich elementów

W wielu przypadkach potrzebne są wskaźniki (pointery) do struktur. Definiujemy je podobnie jak wskaźniki do zmiennych:

struct orbita{
                 double q,               /*  perihelion distance           */
                        e,               /*  eccentricity                  */
                        peri,            /*  argument of perihelion        */
                        node,            /*  longitude of ascending node   */
                        i,               /*  inclination of the orbit      */
                        T;               /*  moment of perihelion passage  */
             };

struct orbita *p1;

double *ww;

struct orbita o1,o2;

/* Po tych deklaracjach w programie może pojawić się np. podstawienie:  */

p1=&o2;

/* Jeśli potrzebujemy wskaźnika do poszczególnego elementu struktury to wykorzystuje się specjalną notację: */

ww = p1->node;

/* Przykłady z kodu wyliczającego elementy orbity ... */

elem->e = f/mi;
elem->p = c*c/mi;
elem->a = elem->p/(1.-elem->e*elem->e);
elem->q = elem->a*(1-elem->e);
elem->n = sqrt(mi/(elem->a*elem->a*elem->a));
 

Przykład zastosowania struktur - czytanie plików binarnych

Efemerydy planetarne JPL są w tej chwili podstawowym narzędziem do wyliczania położeń i prędkości planet, Księżyca i Słońca w układzie równikowym. Są to duże pliki binarne opublikowane wraz dokumentacją i oprogramowaniem w FORTRAN-ie do ich wykorzystania. Z konieczności wykonałem więc kiedyś pełne tłumaczenie tego oprogramowania na język C, dostępne jako public domain na naszym obserwatoryjnym serwerze ftp.

Zajmijmy się przykładowo dostępem do efemerydy DE221. Plik efemerydy to plik binarny z rekordami wielkości 8144 bajtów (każdy rekord to 1018 współczynników Czebyszewa po osiem bajtów - typ double).

Pierwsze dwa rekordy nie zawierają jednak tych współczynników tylko różne stałe tekstowe i numeryczne używane w efemerydzie.

Początek pierwszego rekordu w binarnym pliku efemerydy wygląda tak (dodałem przejście do nowego wiersza po każdych 84 bajtach dla zwiększenia czytelności):

 JPL Planetary Ephemeris DE421/LE421
 Start Epoch: JED=  2414864.5 1899-JUL-29-00:00:00
 Final Epoch: JED=  2471184.5 2053-OCT-09-00:00:00
 DENUM LENUM TDATEFTDATEBCENTERCLIGHTAU    EMRAT GM1   GM2   GMB   GM4   GM5   GM6
 GM7   GM8   GM9   GMS   RAD1  RAD2  RAD4  JDEPOCX1    Y1    Z1    XD1   YD1   ZD1
 X2    Y2    Z2    XD2   YD2   ZD2   XB    YB    ZB    XDB   YDB   ZDB   X4    Y4
 Z4    XD4   YD4   ZD4   X5    Y5    Z5    XD5   YD5   ZD5   X6    Y6    Z6    XD6
 YD6   ZD6   X7    Y7    Z7    XD7   YD7   ZD7   X8    Y8    Z8    XD8   YD8   ZD8
 X9    Y9    Z9    XD9   YD9   ZD9   XM    YM    ZM    XDM   YDM   ZDM   XC    YC
 ZC    XDC   YDC   ZDC   BETA  GAMMA J2SUN GDOT  MA0001MA0002MA0004MAD1  MAD2  MAD3
 RE    ASUN  PHI   THT   PSI   OMEGAXOMEGAYOMEGAZS31M  TAUE1 TAUE2 ROTEX ROTEY DROTEX
 COBLATEDOT  IFAC  KVC   PHIC  THTC  PSIC  OMGCX OMGCY OMGCZ AM    J2M   J3M   J4M
 C22M  C31M  C32M  C33M  S32M  S33M  C41M  S41M  C42M  S42M  C43M  S43M  C44M  S44M
 LBET  LGAM  K2M   TAUM  AE    J2E   J3E   J4E   K2E0  K2E1  K2E2  TAUE0 DROTEYGMAST1
 GMAST2GMAST3PSIDOTMGMIS MA0007MA0324MA0003MA0006MA0009MA0010MA0019MA0020MA0024MA0031
 MA0041MA0052MA0139MA0354MA0511MA0532MA0654MA0005MA0008MA0013MA0014MA0015MA0016MA0018
 MA0022MA0023MA0027MA0029MA0045MA0051MA0065MA0078MA0097MA0105MA0111MA0344MA0372MA0405
 MA0409MA0451MA0704MA0747MA0011MA0021MA0025MA0028MA0030MA0042MA0060MA0063MA0069MA0094
 MA0098MA0135MA0145MA0187MA0192MA0194MA0216MA0230MA0337MA0419MA0488MA0554XS    YS
 ZS    XDS   YDS   ZDS   ............................................................
 ....................................................................................

Na podstawie dokumentacji do przeczytania tych dwóch pierwszych rekordów przygotowałem następujący kod:


#define RECSIZE 8144

FILE *F1;

struct rec1{
         char ttl[3][84];   /* trzy wiersze opisu efemerydy */
         char cnam[400][6]; /* nazwy stałych (400 sztuk po 6 znaków) */
         double ss[3];
         long int ncon;   /* liczba wykorzystywanych stałych */
         double au;
         double emrat;
         long int ipt[12][3];
         long int numde;
         long int lpt[3];
       };
 struct{
         struct rec1 r1;
         char spare[RECSIZE-sizeof(struct rec1)];
       } R1;

 struct rec2{
         double cval[400];
       };
 struct{
         struct rec2 r2;
         char spare[RECSIZE-sizeof(struct rec2)];
       } R2;

/* Dzięki powyższym deklaracjom przeczytanie i zinterpretowanie zawartości
   pierwszych dwóch rekordów efemerydy załatwia instrukcja:   */


  fread(&R1,sizeof(R1),1,F1);
  fread(&R2,sizeof(R2),1,F1);

 


Licencja Creative Commons