Adok's Way to C
Teil 3

Seid  gegrt, meine Freunde! Mit neuem Eifer  strzen wir uns in eine weitere
Schlacht,   in  einen  neuen  Teil   unseres  C-Kurses!  Diesmal  geht's,  wie
angekndigt,  wieder  um  Variablen.  Dieses  Thema  ist  einfach  riesig! Wir
beschftigen  uns  mit der Eingabe und  Ausgabe von Zahlenvariablen und lernen
dabei  einige  neue Varianten von printf  kennen. Und als Draufgabe werden wir
den  if-Befehl  & Co. kennenlernen, mit  dem wir Verzweigungen realisieren und
etwas  ntzlichere  Programme erstellen knnen!  Also, worauf wartet ihr noch?
Lat uns beginnen!

+++ Los geht's! +++

Jau,  wie  man Zeichen und Strings ausgibt, wit ihr ja schon. Na, wie? Genau,
mit putchar und puts! Jetzt geht's darum, auch Zahlen ausgeben zu knnen. Dazu
bedienen wir uns einer altbekannten Funktion  aus  stdio.h,  printf.  Wie  wir
wissen, kann der Parameter Text nicht nur aus druckbaren Zeichen, sondern auch
aus  Steuerzeichen  bestehen!  Diese  werden  durch  einen  Backslash (also \)
gekennzeichnet.

Jedoch   sind  nicht  nur  Steuerzeichen  nicht  druckbar,  sondern  auch  die
sogenannten   PLATZHALTER.  Wie  immer  gilt's  auch  hier:  Nomen  est  Omen!
Platzhalter  halten  den Platz fr eine  Variable  frei. An dieser Stelle wird
dann  eine  Variable  auf  dem  Bildschirm  ausgegeben.  Ein jeder Platzhalter
beginnt  mit  einem  Prozentzeichen. Danach  folgt  eine  Formatangabe. Einige
Beispiele fr Formatangaben:

       Datentyp(en):
 %d    short int und char
 %ld   long int
 %u    unsigned short und unsigned char
 %lu   unsigned long
 %f    float
 %lf   double

%f  und  %lf  haben brigens eine Besonderheit:  Man  kann auch die Anzahl der
Nachkommastellen,  die ausgegeben werden sollen,  bestimmen! Dazu mu man nach
dem  Prozentzeichen  einen  Punkt und  danach  die Anzahl der Nachkommastellen
hinschreiben.  Beispielsweise mu man %.2f schreiben,  um einen float mit zwei
Nachkommastellen  anzuzeigen.  Auerdem gibt es  noch einige Formatangaben fr
Zeichen und Strings. Mit ihnen lassen sich Zeichen und Strings genauso wie mit
putchar  und  puts ausgeben, nur wird  im Gegensatz zu puts kein automatischer
Zeilenvorschub ausgegeben.

 %c    gibt eine char-Variable als Zeichen aus
 %s    gibt einen char-Array als String aus
 %%    gibt das Prozentzeichen aus

So,  aber  mit diesen Formatangaben allein  lt sich absolut nichts anfangen!
Jau,  ihr  habt  recht:  Wir mssen  natrlich  noch  angeben, welche Variable
ausgegeben  werden  soll!  Und  das  geschieht  z.B.  so:

 printf("Eine Zahl: %d\n",intvar);

oder, mit mehreren Variablen:

 printf("%d %s %lf",intvar,chararray,doublevar);

+++ Beispielprogramm: printf +++

// C-Kurs 3: Die erweiterten Funktionen von printf

#include <stdio.h>

void main(void)
{
  int summand[2],
      summe;

  summand[0]=-20;
  summand[1]=40;
  summe=summand[0]+summand[1];

  printf("Erster Summand: %d\n"
         "Zweiter Summand: %d\n"
         "Summe: %d\n",
          summand[0],summand[1],summe);

  /* Ein String lt sich in C auch ber mehrere Zeilen verteilen, wenn man
     wie oben vorgeht. */
}

+++ Die vier Grundrechnungsarten +++

Back to kindergarten! Also, liebe Kinder, da gibt es das Plus, damit knnt ihr
zwei  pfel  und  vier pfel zu  sechs  pfeln  machen... Scherz beiseite, ich
hoffe, jeder wei, wie die vier Grundrechnungsarten funktionieren. In C werden
sie durch folgende Symbole dargestellt:

 +    Plus
 -    Minus
 *    Ma(h)l(zeit)
 /    Dividiert

Besonderheiten gibt's nur bei der Division. Denn was glaubt ihr, kommt bei der
folgenden Zuweisung raus:

 float floatvar;
 floatvar=5/2;

"Zwei komma fnf!!!"

Falsch,  ihr  Schlaumeier,  zu frh gefreut!  Es  kommt 2 heraus! Wenn nmlich
sowohl  der  Dividend  als  auch der  Divisor  ganze  Zahlen  sind, also keine
Nachkommastellen  enthalten, wird immer eine Integerdivision durchgefhrt. Die
Nachkommastellen  werden  also  abgeschnitten. Um  das  zu verhindern, mu man
einfach  eine der beiden Zahlen  als Fliekommazahlen schreiben. Also schreibt
man z.B.:

 floaty=5/2.0;

Oder man schreibt das:

 floaty=5/(float)2;

WAS SOLL DENN DAS SEIN? DA STEHT JA EIN DATENTYP IN DER KLAMMER!

Richtig, das gibt es in C auch! Und zwar nennt sich diese Eigenschaft

+++ Typecasting +++

Mit  Typecasting  wird  schlicht und einfach  eine  Zahl oder eine Variable in
einen  anderen  Datentyp umgewandelt. Aber  nur temporr (fr die Berechnung)!
Mit  Typecasting  lt  sich  nicht  eine  Integervariable  dauerhaft  in eine
Fliekommazahl  verwandeln!  Der Datentyp, in  den verwandelt werden soll, mu
dabei in zwei runde Klammern eingeschlossen werden.

+++ Division durch Null +++

Und dann gibt es noch einige Besonderheiten. Zum einen darf man nie durch Null
dividieren,  wenn man nicht absichtlich den  Interrupt 0 auslsen will (der im
Normalfall  das  Programm  abbricht,  wenn er  nicht  auf  eine eigene Routine
verbogen ist).

+++ berlauf und Unterlauf +++

Weiters  mu  man  das Phnomen des  berlaufs  beachten. Addiert man zu einem
unsigned  char,  der  gleich 255 (der Maximalwert)  ist,  1,  so wird er auf 0
zurckgesetzt.  Wenn  ihr euch das Bitmuster  der Zahl anseht, wird euch alles
klar: 255d = 11111111b. Addieren wir dazu 1, so mte 100000000b entstehen. Da
ein  Byte  jedoch  nur 8 Bit hat,  wird  Bit 8 abgeschnitten, und brig bleibt
Null.  Daher mu man eine int-Variable als Schleifenzhler verwenden, wenn man
eine Schleife (s.u.) von 0 bis 255 machen will. Bei einer char-Variablen wrde
die Schleife endlos laufen! Genauso gibt's natrlich auch Unterlufe (Zahl ist
0, und wir ziehen immer noch was ab).

Solche berlaufphnoneme treten natrlich auch bei den anderen Datentypen auf,
aber dort erst ab 65535 (unsigned short), 2^32-1 (unsigned long) usw. Aber nun
zu etwas anderem!

+++ scanf +++

Der  Name sagt's: scanf aus stdio.h ist der Eingabebefehl fr Zahlenvariablen.
ABER: scanf ist sehr fehleranfllig! Deshalb wrde ich an eurer Stelle nur mit
groer Sorgfalt mit ihm umgehen.

Die Syntax lautet:

 scanf(formatstring,adresse_der_variablen);

Im   Grunde  genommen  geht's  also  wie   printf!  Auch  die  Platzhalter  im
Formatstring  sind  die gleichen (bis auf  die Anzahl der Nachkommastellen bei
floats  und doubles, die gibt's hier  nicht). Nur beim Variablennamen mt ihr
aufpassen:  Vor dem Namen mu IMMER ein &-Zeichen stehen. Der &-Operator dient
dazu,  die  Speicheradresse  der  Variablen  herauszufinden.  In  Wirklichkeit
arbeitet scanf nmlich mit Zeigern (siehe Teil 4).

+++ Beispielprogramm: scanf +++

// C-Kurs 3: scanf

#include <stdio.h>

void main(void)
{
  float zahl[2];

  printf("Zahl 1 eingeben: ");
  scanf("%f",&zahl[0]);
  printf("Zahl 2 eingeben: ");
  scanf("%f",&zahl[1]);

  printf("\n%.2f + %.2f = %.2f\n",zahl[0],zahl[1],zahl[0]+zahl[1]);
  printf("%.2f - %.2f = %.2f\n",zahl[0],zahl[1],zahl[0]-zahl[1]);
  printf("%.2f * %.2f = %.2f\n",zahl[0],zahl[1],zahl[0]*zahl[1]);
  printf("%.2f / %.2f = %.2f\n",zahl[0],zahl[1],zahl[0]/zahl[1]);
}

+++ Weitere Operatoren +++

Richtig,  das waren noch nicht alle Operatoren,  die es in C gibt! Zunchst zu
den  kombinierten  Operatoren. Sie vereinfachen Zuweisungen wie:

 a=a+3;

Man kann stattdessen nmlich die Operatoren + und = kombinieren und schreiben:

 a+=3;

Analoges gilt fr -, * und /.

Daneben gibt es noch Inkrement und Dekrement:

 a++;

steht fr

 a=a+1;

und

 a--;

steht fr

 a=a-1;

Es  ist  auch mglich, ++a; bzw. --a;  zu schreiben. Steht der Inkrement- bzw.
Dekrementoperator  isoliert,  also  als  eigene  Anweisung,  macht  das keinen
Unterschied. Sehr wohl aber, wenn man den Inkrement- oder Dekrementoperator in
komplexeren Anweisungen einbaut. So wird

 a=b++;

mit

 a=b;
 b=b+1;

bersetzt. Die Anweisung

 a=++b;

dagegen steht fr

 b=b+1;
 a=b;

Auf  den  Wert  von  b haben beide  Anweisungen  also  denselben Effekt, fr a
liefern sie dagegen verschiedene Ergebnisse. Ein Beispielprogramm demonstriert
dies.

+++ Beispielprogramm: Zwei verschiedene Arten des Inkrement-Operators +++

// C-Kurs 3: Der Unterschied zwischen a++ und ++a

#include <stdio.h>

void main(void)
{
  char a=5,
       b=0;

  // Erste Mglichkeit
  b=a--;
  printf("b=a-- ergibt:\na=%d\nb=%d\n\n",a,b);

  // Variablen zurcksetzen
  a=5;
  b=0;

  // Zweite Mglichkeit
  b=--a;
  printf("b=--a ergibt:\na=%d\nb=%d\n",a,b);
}

+++ Binre Operatoren +++

Eine weitere Art von Operatoren in C sind die binren Operatoren:

 ~      bitweises NOT                             NOT 0101b = 1010b
 &      bitweises AND                       0101b AND 0011b = 0001b
 ^      bitweises XOR                       0101b XOR 0011b = 0110b
 |      bitweises OR                        0101b  OR 0011b = 0111b

Eine  genaue  Erkluterung dieser Operatoren findet  ihr in Artikeln zum Thema
Boolesche Algebra.

+++ Bitschiebeoperatoren +++

Die  Bitschiebeoperatoren  entsprechen  einer  Multiplikation  mit  oder einer
Division durch eine Zweierpotenz.

 a<<x   entspricht:   a mal (2 hoch x)
 a>>x   entspricht: a durch (2 hoch x)

+++ Verzweigungen +++

Oft  mssen in Programmen Entscheidungen nach dem Muster "Wenn diese Bedingung
erfllt  ist, dann tu' dies, andernfalls tu' das" getroffen werden. Dazu dient
der if-else-Block:

 if(boolescher_ausdruck) {
   ...
 }
 else {
   ...
 }

Der else-Zweig kann weggelassen werden.

Die im booleschen Ausdruck zulssigen Vergleichsoperatoren sind:

 ==   Test auf Gleichheit
 !=   Test auf Ungleichheit
 <    Test, ob der linke Wert kleiner ist als der rechte
 >    Test, ob der linke Wert grer ist als der rechte
 <=   Test, ob der linke Wert nicht grer ist als der rechte
 >=   Test, ob der linke Wert nicht kleiner ist als der rechte

Auerdem kann man folgende logische Verknpfungen verwenden:

 !    Boolesches NOT: negiert den Wahrheitswert des Ausdrucks
 &&   Boolesches  AND:  liefert nur dann  TRUE,  wenn beide Teilausdrcke wahr
      sind, ansonsten FALSE
 ||   Boolesches  OR: liefert nur dann  FALSE, wenn beide Teilausdrcke falsch
      sind, ansonsten TRUE

FALSE ist gleich 0; jeder andere Wert ist TRUE. Die Vergleichsoperatoren geben
fr TRUE in der Regel -1 zurck (da dies aber nicht definiert ist, kann es bei
einzelnen  Compilern  abweichen,  weshalb  man  sich  nicht  darauf  verlassen
sollte). Aus diesem Grund mu der Ausdruck nicht unbedingt aus einem Vergleich
bestehen.  Schreiben  wir z.B. if(var) und die  Variable  var ist gleich 0, so
ergibt  der Test automatisch FALSE. Die  Anweisungen innerhalb if werden nicht
ausgefhrt.  Falls vorhanden, wird zum  else-Zweig gesprungen. Ist var dagegen
ungleich 0, so ist die Bedingung erfllt.

+++ Beispielprogramm: if +++

// C-Kurs 3: Verzweigungen mit if

#include <stdio.h>

void main(void)
{
  long int zahl[2];

  printf("Gib die erste Zahl ein!  ");
  scanf("%ld",&zahl[0]);
  printf("Gib die zweite Zahl ein! ");
  scanf("%ld",&zahl[1]);

  printf("\nDie beiden Zahlen erfllen folgende Bedingungen:\n");
  if(zahl[0]==zahl[1]) printf("Zahl 1 ist gleich Zahl 2.\n");
  if(zahl[0]<=zahl[1]) printf("Zahl 1 ist kleiner oder gleich Zahl 2.\n");
  if(zahl[0]>=zahl[1]) printf("Zahl 1 ist grer oder gleich Zahl 2.\n");
  if(zahl[0]<zahl[1])  printf("Zahl 1 ist kleiner als Zahl 2.\n");
  if(zahl[0]>zahl[1])  printf("Zahl 1 ist grer als Zahl 2.\n");
  if(zahl[0]!=zahl[1]) printf("Zahl 1 ist ungleich Zahl 2.\n");
}

+++ String-Vergleiche +++

Wenn  wir  testen  wollen,  ob  der  String  str1  dem String str2 entspricht,
schreiben wir:

if(!strcmp(str1,str2)) { ... }

Die   Verneinung   (!)  ist  deshalb   wichtig,   weil  strcmp  aus  internen,
algorithmischen Grnden den Wert 0 zurckliefert, wenn beide Strings identisch
sind, obwohl 0 FALSE bedeutet.

+++ Beispielprogramm: strcmp, strlen +++

// C-Kurs 3: strcmp und strlen

#include <stdio.h>
#include <string.h>

void main(void)
{
  char vor[21],
       nach[21],
       name[42];

  printf("Hallo, Typ!\nWie lautet dein Vorname? ");
  scanf("%s",vor);
  fflush(stdin);
  printf("Und dein Nachname? ");
  scanf("%s",nach);
  fflush(stdin);

  if(!strcmp(vor,nach))
  {
    printf("\nHe, du Schlingel! Dein Vorname ist ja genauso wie dein ");
    printf("Nachname!\nAber wie dem auch sei...\n");
  }

  strcpy(name,vor);
  strcat(name," ");
  strcat(name,nach);

  printf("\nDu heit also %s!\n"
         "Wutest du eigentlich, da dein Name "
         "genau %d Zeichen lang ist?",name,strlen(name));
}

Die  Funktion fflush, aufgerufen mit dem Parameter stdin (Standard-Input, also
Tastatur), dient hierbei zum Leeren des Tastaturpuffers.

+++ switch +++

Ein unbersichtliches Konstrukt wie

if(ausdruck=1)
{
   ....
}
else
{
  if(ausdruck=2)
  {
     ....
  }
  else
  {
     ....
  }
}

lt sich mit switch vereinfachen:

switch(ausdruck)
{
  case 1:    //Jetzt kommen die Befehle
             break;
  case 2:    //Wieder Befehle
             break;
  default:   //usw.
}

Wichtig  ist es, break nicht zu vergessen. Ansonsten werden alle nachfolgenden
Anweisungen  im  switch-Block abgearbeitet. Wenn  ausdruck  also gleich 1 sein
sollte,  werden in diesem Fall auch die Anweisungen fr den Fall ausdruck == 2
und ausdruck == ein anderer Wert abgearbeitet!

Ein   Beispiel,   zuerst   richtig,   danach   schlampig.   Links   steht  die
switch-Anweisung, rechts immer das quivalent als if-Block.

Richtig:

switch(var>1)                          if(!(var>1))
{                                        printf("Wert <= 1\n");
  case 0:    printf("Wert <= 1\n");    else
             break;                      printf("Wert > 1\n");
  default:   printf("Wert > 1\n");
}

(Ihr  seht:  Da  TRUE und FALSE  Zahlenwerte  sind, kann auch ein switch-Block
Entscheidungen treffen, obgleich if hierfr wesentlich besser geeignet ist.)

Schlampig:

switch(vary>1)                         if(!(vary>1))
{                                      {
  case 0:    printf("Wert <= 1\n");      printf("Wert <= 1\n");
  default:   printf("Wert > 1\n");       printf("Wert > 1\n");
}                                      }
                                       else
                                         printf("Wert > 1\n");

Ihr  seht  also,  was da entstehen kann. Am besten, ihr probiert das Ganze mal
live aus, um euch mit dieser  Eigenheit  vertraut  zu  machen.  In  bestimmten
Fllen kann sie auch ganz ntzlich sein, um Speicherplatz zu sparen.

+++ for +++

Die  for-Schleife existiert in vielen  Programmiersprachen, doch in keiner ist
sie  so  flexibel wie in C. Wir  mchten zuerst auf die "klassische" Benutzung
der  for-Schleife  eingehen; dann werden  wir uns die besonderen Mglichkeiten
ansehen, die C bietet.

Normalerweise  stellt  die for-Schleife eine  Zhlschleife  dar. Eine Variable
wird  zuerst auf einen bestimmten Anfangswert gesetzt. Nun werden, solange sie
einen   bestimmten  Endwert  noch  nicht  berschritten  hat,  ein  bestimmter
Anweisungsblock  abgearbeitet und die Variable um einen bestimmten Wert erhht
oder verringert.

Diese "klassische" for-Schleife sieht in C z.B. so aus:

for(zaehler=startwert;zaehler<=endwert;zaehler++)
{
  ...
}

Tatschlich  verlangt  die  for-Schleife  von  C  drei  Parameter,  die  durch
Semikolons  getrennt werden. Der erste ist die Anweisung, mit der die Schleife
initialisiert  wird.  Normalerweise ist das  die Zuweisung des Anfangswerts an
die Schleifenzhlvariable.

Der   zweite  Parameter  ist  eine  Bedingung;  jedesmal,  wenn  der  Computer
unmittelbar  vor  der  Ausfhrung  des  Inneren  der  for-Schleife steht, wird
geprft,  ob  sie  erfllt  (TRUE) ist.  Falls  ja,  wird  das Schleifeninnere
ausgefhrt;  falls  nein,  wird die Ausfhrung  der  Schleife beendet, und die
nchste Anweisung auerhalb der for-Schleife wird ausgefhrt.

Der  dritte  Parameter schlielich ist eine  Operation,  die jedesmal nach dem
Abarbeiten  des  Schleifeninneren  ausgefhrt  wird -  in  der  Regel also das
Erhhen oder Verringern des Schleifenzhlers.

+++ Beispielprogramm: "klassisches" for +++

// C-Kurs 3: Fakulttsberechnung mit for

#include <stdio.h>

void main(void)
{
  unsigned char zahl,
                i;
  unsigned long ergebnis=1;

  printf("Bitte 'ne Zahl zwischen 2 und 30 eingeben: ");
  scanf("%ud",&zahl);

  switch( (zahl>=2) && (zahl<=30) )
  {
    case 0:    printf("\nZwischen 2 und 30 habe ich gesagt. rks.\n");
               break;
    default:   for(i=2; i<=zahl; i++) ergebnis*=(unsigned long)i;
               printf("\nFakultt ist: %lu\n",ergebnis);
  }
}

+++ Das Besondere von for in C +++

Das  Besondere  der  for-Schleife  in C  ist,  da  sie eine Verallgemeinerung
darstellt.  Oben  habe  ich  bereits  die  Funktionen  der einzelnen Parameter
erklrt: Initialisation, Bedingung, bei deren Nichterfllung abgebrochen wird,
und  eine  am Ende jeder for-Schleife  ausgefhrte  Operation. Mu es sich nun
etwa  bei  der  Bedingung um einen  Test,  ob  die Schleifenzhlvariable einen
bestimmten  Wert noch nicht berschritten hat, handeln? Nein - wir knnen eine
beliebige  Bedingung verwenden, je nachdem,  was wir bentigen. Eine Schleife,
die im Quick-Sort-Algorithmus verwendet wird, knnte man bspw. so ausdrcken:

 for(; dataspace[counter_min]<central; counter_min++);

Im  Prinzip  handelt es sich dabei  aber  um syntaktische Spielereien. C kennt
noch  weitere,  hnliche Schleifen, mit  denen sich solche Aufgaben treffender
ausdrcken lassen.

+++ while +++

Eine davon ist while. Syntax:

while(ausdruck)
{
  ...
}

Zuerst  wird berprft, ob der angegebene Ausdruck  wahr ist; nur wenn er wahr
ist,  werden die Anweisungen im  Schleifeninneren ausgefhrt, andernfalls wird
direkt  zur  nchsten Anweisung auerhalb  der while-Schleife gesprungen. Nach
einmaliger   Ausfhrung  der  Anweisungen   im  Schleifeninneren  wird  erneut
berprft, ob der Ausdruck wahr ist, usw.

Man  htte  obige  for-Schleife aus  dem  Quick-Sort-Algorithmus also auch als
while-Schleife formulieren knnen:

 while(dataspace[counter_min]<central) counter_min++;

Das ist vielleicht sogar besser lesbar.

Auch  die  klassische for-Schleife liee  sich  mit Hilfe einer while-Schleife
realisieren:

 zaehler=startwert;
 while(zaehler<=endwert)
 {
   ...
   zaehler++;
 }

+++ do ... while +++

Eng  verwandt  mit  while ist do ...  while.  Hier erfolgt die berprfung des
Ausdrucks allerdings erst nach einmaliger Ausfhrung des Schleifenrumpfs.

Syntax:

do
{
  ...
} while(ausdruck)

+++ Ternrer Operator +++

Darf's  noch ein Operator mehr sein? Das if-Konstrukt lt sich abkrzen, wenn
es  darum  geht,  je  nach Erfllung  einer  Bedingung  einer  Variablen einen
bestimmten  Wert  zuzuweisen. In C gibt  es  einen eigenen Operator dafr, den
"ternren  Operator". Ein Beispiel soll  seine Funktionsweise erklren. Nehmen
wir folgendes, eher umgangssprachliche Konstrukt:

if(marius_sagt_richtiges)
  marius_ist_klug = -1;
else
  marius_ist_klug = 0;

Statt diesem schreibt man krzer:

marius_ist_klug = marius_sagt_richtiges ? -1 : 0

+++ Vergleiche als Operatoren +++

Das letzte Beispiel liee sich noch krzer formulieren:

marius_ist_klug = ( marius_sagt_richtiges != 0 );

Auch ein Vergleich ist ein Operator. Mit obiger Anweisung wird zuerst geprft,
ob  die Variable marius_sagt_richtiges ungleich FALSE ist. Das Ergebnis dieses
Vergleichs  wird  der  Variablen  marius_ist_klug  zugewiesen.  Wer  sich  die
Zahlenwerte  von  TRUE  und FALSE nicht merken  kann,  dem  kann mit Hilfe des
Prprozessors Abhilfe geschaffen werden.

+++ Der Prprozessor +++

Bisher  tauchte  der  PP  nur  im  Zusammenhang mit dem Einbinden von externen
Headerdateien auf. Der PP kann jedoch noch viel mehr!  Da stellt sich zunchst
die  Frage:  Was ist der PP berhaupt? Er ist eine Art "Textbersetzer". Bevor
ein Quellcode compiliert werden kann,  mu  es  zuerst  in  den  PP  geschickt
werden.  Dieser  sucht  nun nach "seinen" Befehlen wie #include, #define etc.,
welche natrlich immer mit einem amerikanischen Numerus beginnen.  Die Befehle
veranlassen  den  PP,  den  Quellcode  des  Programms  zu ndern. Stt er auf
#include, so wird die danach angegebene Headerdatei geffnet und  komplett  in
das  Proggy  eingebunden.  Ebenso  veranlassen  die  anderen  Befehle wie etwa
#define den PP, etwas im Programm zu ndern.

Da  sind  wir  beim springenden Punkt:  Was  macht  #define? #define dient zum
Erstellen von Konstanten und Makros. Die Anweisung

 #define TRUE -1

veranlat  den  PP, berall dort, wo im  Quellcode das Wrtchen TRUE steht, es
durch -1 zu ersetzen. Ebenso kann man mit der kurzen Anweisung

 #define HW printf("Hello World!\n");

den angegeben langen Funktionsaufruf abkrzen.

Es lassen sich auch Makros mit Parametern definieren. Ein Beispiel lautet:

 #define CUBE(x) x*x

Nun kann man etwa schreiben:

 y = CUBE(10);

und y wird 100.

Hier liegt jedoch der Hund begraben! Denn was passiert, wenn man

 y = CUBE(5+5);

schreibt? Der PP ersetzt dies durch

 y = 5+5*5+5;

was  35 ergbe. Wir tten also besser  daran, das Makro CUBE(x) mit (x)*(x) zu
definieren:

 #define CUBE(x) (x)*(x)

und

 y = CUBE (5+5);

wird durch

 y = (5+5)*(5+5);

ersetzt - wir erhalten das richtige Ergebnis.

Eine weitere Fehlerquelle liegt darin, da sich eine Makrodefinition jederzeit
berschreiben oder mit dem Befehl #undef rckgngig machen lt. Ebenso knnte
man Variablen mit Makros/Konstanten verwechseln. Aus diesem Grund hat man sich
angewhnt,  MAKROS  GROSS  zu schreiben,  whrend  variablen klein geschrieben
werden.

Nachdem nach dem PP-Lauf der Quellcode in eine fr den Compiler  lesbare  Form
umgewandelt worden ist, wird der Compiler aufgerufen, und weiter geht's.

Weitere  ntzliche  PP-Befehle sind #if, #endif,  #else  und #elif. Damit lt
sich eine bedingte bersetzung realisieren! Schreiben wir nmlich:

#if defined(WIN95)
  printf("Windows-95-Version des Programms wird geladen...\n");
#elif defined(LINUX)
  printf("Linux-Version loading...\n");
#else
  printf("Starte DOS-Version...\n");
#endif

...so wird Anweisung Nummer 1 nur dann compiliert, wenn das Makro WIN95 vorher
definiert  wurde.  Ist  dagegen  LINUX  definiert,  wird  die zweite Anweisung
compiliert.  Und  wenn weder WIN95 noch  LINUX  definiert sind, wird Anweisung
Nummer  3  compiliert. So liee sich  der Quellcode von mehreren verschiedenen
Versionen  des  Programms fr verschiedene  Betriebssysteme  in einem einzigen
Quellcode  unterbringen. Dieser mu nur  minimal verndert werden (nmlich die
Makrodefinitionen),  danach wird er neu compiliert,  schon hat man sein Proggy
fr  sein  System! Soviel zu der  Portabilitt  von C-Programmen, wenn man sie
richtig anwendet.

Statt  #if  defined(...) geht es auch  krzer,  indem man #ifdef ... schreibt.
Analog  gibt  es  auf  #ifndef.  Wenn  man  jedoch  #if  verwendet,  sind auch
komplexere Varianten mglich, etwa:

 #if KONSTANTE == 1

Naja,  das  war  viel  auf einmal, stimmt's?  Aber  wenn  wir  in diesem Tempo
weitermachen,  sind wir in Teil 5  mit den Grundkenntnissen der Programmierung
in C fertig.
