|
struct datum
{ int tag;
int monat;
int jahr;
char mon_name[4];
};
| Legt nur die Form der Struktur datum fest |
struct datum {
int tag;
int monat;
int jahr;
char mon_name[4];
} geb_dat, heute;
| Erzeugt zusätzlich die Strukturvariablen geb_dat
und heute |
struct point
{ double spx, spy;
int farbe;
char label;
} spot1;
| point ist der Strukturname, spx, spy, etc.
sind Elementnamen und spot1 ist die deklarierte Variable |
struct point punkt1, punkt2;
| ebenfalls so deklarierte Variablen |
Durch die Angabe einer (oder mehrerer) Strukturvariablen
wird diese Struktur erzeugt (d. h. Speicherplatz dafür bereitgestellt).
Strukturvereinbarungen ohne Angabe einer Strukturvariablen legen
nur die Form (den Prototyp) der Struktur fest.
Die geschlossene Initialisierung erfolgt (analog zu den Arrays) bei
der Deklaration. Zum Beispiel:
struct datum heute = {26,9,1987,"jun"};
struct point spot2 = {2.8, -33.7, 15, 'A'};
Für den Elementzugriff gibt es zwei eigene Operatoren. Der
direkte Zugriff wird dabei mit dem Punktoperator . nach
folgendem Schema durchgeführt (Der Operator -> wird
bei den Pointern besprochen):
Strukturvariable . Komponente
Beispiel:
punkt1.farbe = 11;
punkt2.spy = spot2.spy;
heute.tag = 22;
heute.monat = 1;
heute.jahr = 2000;
Strukturvariable können an Funktionen übergeben werden,
und Funktionen können Strukturen als Rückgabetyp haben. Beispiel (mit
obiger Definition):
/* createpoint : bepackt Struktur 'point' */
struct point createpoint(double x, double y, int farbe, char label)
{
struct point dummy;
dummy.spx = x;
dummy.spy = y;
dummy.farbe = farbe; /* gleiche Bezeichnungen */
dummy.label = label; /* interferieren NICHT */
return dummy;
}
Strukturen können als Elemente ebenfalls wieder Strukturen
enthalten (allerdings nicht sich selbst) und Strukturen können
zu Vektoren zusammengefaßt werden:
struct kunde
{
char name[NAMLAE];
char adresse[ADRLAE];
int kund_nr;
struct datum liefer_dat;
struct datum rech_dat;
struct datum bez_dat;
};
struct kunde kunde1, kunde2, ... ;
struct kunde kunden[KUNANZ];
Programmbeispiel: Komplexe Arithmetik
#include <stdio.h>
struct complex
{
double r;
double i;
};
typedef struct complex cpx;
cpx makecpx(double, double);
cpx sum(cpx, cpx);
cpx product(cpx, cpx);
cpx power(cpx, int);
void compprint(cpx);
int main(void)
/* Berechnet Potenzen komplexer Zahlen */
{
int k;
cpx basis, result;
basis = makecpx(1,1);
for (k=0; k < 10; ++k)
{
result = power(basis, k);
printf("%2d ", k);
compprint(result);
}
return(0);
}
cpx makecpx(double r, double i)
/* Komplexe Zahl erzeugen */
{
cpx tmp;
tmp.r = r; tmp.i = i;
return (tmp);
}
cpx sum(cpx a, cpx b)
/* Summe zweier komplexer Zahlen */
{
a.r += b.r;
a.i += b.i;
return (a);
}
cpx product(cpx x, cpx y)
/* Produkt zweier komplexer Zahlen */
{
cpx u;
u.r = x.r * y.r - x.i * y.i;
u.i = x.r * y.i + x.i * y.r;
return (u);
}
cpx power( cpx basis, int expo)
/* Potenz einer komplexen Zahl */
{
cpx u = {1, 0};
while (expo > 0)
{
if (expo % 2)
{
expo--;
u = product(basis, u);
}
else
{
expo = expo/2;
basis = product(basis, basis);
}
}
return(u);
}
void compprint(cpx z)
/* Druckt eine komplexe Zahl */
{
if ((z.r != 0) && (z.i != 0))
printf("%5.2f + %5.2f * i\n", z.r, z.i);
else if ((z.r == 0) && (z.i != 0))
printf("%13.2f * i\n", z.i);
else if ((z.r != 0) && (z.i == 0))
printf("%5.2f\n", z.r);
else printf("0\n");
}
Varianter Record: union
Während eine Struktur mehrere Variablen (verschiedenen Typs)
enthält, ist eine Variante eine Variable, die (aber natürlich
nicht gleichzeitig) Objekte verschiedenen Typs speichern kann.
Verschiedene Arten von Datenobjekten können so in einem einzigen
Speicherbereich maschinenunabhängig manipuliert werden.
Syntaktisch sind union und struct analog (bis auf Initialisierung).
Der wesentliche Unterschied ist, daß eine Variable vom Typ union
zu einer Zeit immer nur eines deren angegebener Elemente
enthalten kann. Beispiel:
union utype
{ int n;
double d; } irgendwas;
irgendwas.n = 3;
irgendwas.d = 11.7;
zahl = irgendwas.n; /* in diesem Fall: Fehler! */
Allerdings ist Buchführung notwendig, um zu wissen, welcher Datentyp
in welcher union-Variablen zuletzt abgespeichert wurde (deshalb
der obige Fehler). Beispiel:
if (utype == INT)
printf("%d\n",uval.ival);
else if (utype == FLOAT)
printf("%f\n",uval.fval);
else if (utype == STRING)
printf("%s\n",uval.pval);
else
printf("bad type %d in utype\n",utype);
Ein wichtiges Beispiel für Struktur- und Variantenvereinbarung
ist die Definition der Strukturen WORDREGS und BYTEREGS sowie
der Varianten REGS für MS-DOS Funktionsaufrufe:
struct WORDREGS {
unsigned int ax;
unsigned int bx;
unsigned int cx;
unsigned int dx;
unsigned int si;
unsigned int di;
unsigned int cflag;
};
struct BYTEREGS {
unsigned char al,ah;
unsigned char bl,bh;
unsigned char cl,ch;
unsigned char dl,dh;
};
union REGS {
struct WORDREGS x;
struct BYTEREGS h;
};
union REGS inregs,outregs;
inregs.x.bx = 0x12; /* BX Register auf Hex 12 stellen */
inregs.h.ah = 0x10 /* AH Register auf Hex 10 stellen */
c = outregs.x.cx /* CX Register nach c kopieren */
typedef
Mit typedef kann man neue Datentypnamen definieren
(Nicht aber neue Datentypen!). typedef ist #define ähnlich,
aber weitergehender, da erst vom Compiler verarbeitet und nicht
nur einfacher Textersatz. Die Anwendungen von typedef liegen darin,
ein Programm gegen Protabilitätsprobleme abzuschirmen und
für eine bessere interne Dokumentation zu sorgen. Durch typedef
wird aber auch der Aufbau von Structures verschleiert, so daß
viele Programmierer keinen Gebrauch davon machen (z. B. beim Betriebssystemkern
von Linux).
Zur Syntax: Der neue Typname steht an genau der Stelle, an der ohne
typedef der Variablenname stünde. Beispiele:
typedef unsigned long int bigint;
typedef struct{
int i;
float f;
double df;} collect;
collect ist hier also keine Strukturvariable, sondern der so neu
definierte Typname!
|
|
|