3. Beispielprogramme zur Einführung

Beispielprogramm P3-1.C

main()
{
printf ("Viel Spass mit C !\n");
}

Erläuterungen zu diesem Programm:

- C-Programme bestehen aus Funktionen, diese sind an den dem Funktionsnamen folgenden runden Klammern zu erkennen

- Funktion main() muß immer vorhanden sein

- sie wird meist am Anfang des Quellencodes plaziert

- die geschweiften Klammern umschließen den Funktionskörper wie z.B. BEGIN und END in PASCAL

- das Ende des Quellencodes muß nicht explizit angegeben werden

- in C gibt es nur Funktionen, keine CALLs

- printf ist eine Funktion zur formatierten Ausgabe auf den Bildschirm

- sie hat hier die Stringkonstante "Viel Spass mit C !\n" als Parameter

- die Zeichenkombination \n steht für das Zeilenendezeichen

- C kennt keine Zeilenstruktur (Ausnahme: innerhalb von Zeichenketten oder #define-Anweisungen)

- Anweisungen sind mit ; zu beenden

Beispielprogramm P3-2.C

main()
{
printf ("Viel");
printf (" Spass");
printf (" mit");
printf (" C !");
printf ("\n");
}

Erläuterungen zu diesem Programm:

gleiche Wirkung wie Programm P3-1.C aber anderes Programm

kein explizites Zeilenendezeichen, daher Verkettung der Ausgabe

das Zeichen \ wirkt als Fluchtsymbol, es dient zur Darstellung von Sonderzeichen:

  \t    =  Tabulatorzeichen
  \b    =  Backspacezeichen
  \"    =  das Zeichen "
  \\    =  das Zeichen \

Beispielprogramm P3-3.C

/* Beispiel 3 */
/* Umwandlung von Fahrenheit in Celsius
   fuer f = 0, 20, ..., 300 */
main()
{
int lower,upper,step;
float fahr,celsius;
lower = 0;  /* untere Grenze der Temperaturtabelle */
upper = 300; /*obere Grenze */
step = 20;   /*Schrittweite */
fahr = lower;
while (fahr <= upper) {
    celsius = (5.0/9.0) * (fahr-32.0);
    printf ("%4.0f %6.1f\n",fahr,celsius);
    fahr = fahr + step;
    }
}

Erläuterungen zu diesem Programm:

- alle Angaben zwischen /* und */ werden als Kommentar behandelt

- Kommentar kann überall im Quellencode stehen wo auch ein Leerzeichen, Tabulatorzeichen oder Zeilentrennzeichen stehen darf, sinnvollerweise schreibt man ihn aber an das Ende einer Zeile und/oder verwendet Kommentarzeilen

- in C müssen alle Variablen vor ihrer Verwendung vereinbart werden

- Vereinbarungen müssen am Anfang eines Blocks vor der ersten Anweisung stehen

- man unterscheidet Deklarationen und Definitionen

- C kennt folgende elementaren Datentypen

char := einzelnes Zeichen (Character)

int := Integerzahlen

float := Gleitkommazahlen

double := Gleitkommazahl mit doppelter Genauigkeit

- zur Qualifizierung dienen dann noch die Zusätze:

short := kleine Integerzahl

long := große Integerzahl

unsigned := ohne Vorzeichen

signed := mit Vorzeichen (Weglasswert)

- die Zeilen :

lower = 0;

upper = 300;

fahr = lower;

stellen Zuweisungen dar, dabei wird im 3.Fall eine Typwandlung von int nach float durchgeführt

- while (fahr <= lower) {

...

}

ist eine von mehreren in C realisierten Kontrollstrukturen, die Anweisungen in den geschweiften Klammern werden nur ausgeführt, wenn der Ausdruck in der Klammer nach while wahr ist

- hängt nur eine einzige Anweisung von der while Bedingung ab, so kann man die geschweiften Klammern auch weglassen:

while (i < j)

i = 2 * j;

- in C gilt generell die Konvention:

gleich 0 := FALSE (FALSCH)

ungleich 0 := TRUE (WAHR)

- die Formulierung 5.0/9.0 gegenüber 5/9 ist notwendig, da wegen der sonst verwendeten Ganzzahlarithmetik 5/9=0 gilt

- dagegen kann man die Zahl 32 als 32 oder 32.0 schreiben, weil C die Verwendung gemischter Typen in Ausdrücken erlaubt; zum Zwecke der besseren internen Dokumentation sollte man in unserem Falle aber 32.0 verwenden (Gleitkommazahlen)

- printf kann mehr als einen Parameter haben und gleichzeitig die Ausgabe formatieren:

printf("%4.0f %6.1f\n",fahr,celsius);

bedeutet:

gibt die Variable fahr im Gleitkommaformat mit insgesamt 4 Stellen ohne Nachkommastellen aus, füge ein Leerzeichen (Blank) ein, gib dann die Variable celsius im Gleitkommaformat mit insgesamt 6 Stellen und einer Nachkommastelle aus und schließe die Ausgabe mit einem Zeilenendezeichen ab

- printf kennt noch andere Umwandlungsformate:

%c := ein einzelnes Zeichen

%d = Integerzahl

%f := Gleitkommazahl

%o := Oktaldarstellung

%s := Zeichenkette

%x := Hexadezimaldarstellung

%% := das %-Zeichen selbst ausgeben

Beispielprogramm P3-4.C

/* Beispiel 4 */
/* wie Beispiel 3 aber mit for-Schleife */
main()
{
int fahr;
for (fahr=0; fahr <= 300; fahr=fahr+20)
    printf ("%4.0d %6.1f\n",fahr,(5.0/9.0)*(fahr-32));
}

Erläuterungen zu diesem Programm:

- dieses Programm liefert das gleiche Ergebnis, wie das vorige Beispiel, aber es sieht ganz anders aus

- fahr ist jetzt eine Integerzahl, dies dient nur der Demonstration der %d Umwandlung

- printf akzeptiert auch Ausdrücke für die auszugebenden Parameter

- die for Schleife ist eine weitere in C mögliche Kontrollstruktur, sie hat die Form:

for (Initialisierung; Bedingung; Reinitialisierung)

Beispielprogramm P3-5.C

/* Beispiel 5 */
/* wie Beispiel 4 aber mit #define-Konstanten */
#define LOWER 0    /* untere Grenze der Tabelle */
#define UPPER 300  /* obere Grenze der Tabelle */
#define STEP 20    /* Schrittweite */
main()
{
int fahr;
for (fahr=LOWER; fahr <=UPPER; fahr=fahr+STEP)
    printf ("%4.0d %6.1f\n",fahr,(5.0/9.0)*(fahr-32));
}

Erläuterungen zu diesem Programm:

- die Verwendung von symbolischen Konstanten garantiert eine einfache Änderungsmöglichkeit

- symbolische Konstanten werden üblicherweise zur einfacheren Identifizierung in Großbuchstaben geschrieben

- C unterscheidet zwischen Groß- und Kleinschreibung

- nach #define Zeilen steht kein Semikolon, da #define einen Textersatz (also auch mit evtl. Semikolon) bewirkt

- das # muß in der 1. Spalte stehen

- der C-Präprozessor verarbeitet diejenigen Anweisungen, bei denen ein # in der ersten Spalte steht (in unserem Falle hier ist diese Verarbeitung ein Textersatz)

Beispielprogramm P3-6.C

/* Beispiel 6 */
/* ein Kopierprogramm */
#include <stdio.h>       /* enthaelt wichtige                             Konstantendefinitionen */
main()
{
int c;
c = getchar();
while (c != EOF) {
    putchar(c);
    c=getchar();
    }
}

Erläuterungen zu diesem Programm:

- #include bewirkt das Einfügen von Quellencode aus einer anderen Datei

- die Hauptanwendung liegt im Einfügen von sogenannten Header-Dateien, die üblicherweise zu jedem C-Bibliothekssystem dazugehören

- eine solche Headerdatei hat die Dateinamenergänzung .h und enthält Symbole und Vereinbarungen, die bei bestimmten Anwendungen (z.B. Ein-/Ausgabe, Dateiverarbeitung) immer wieder gebraucht werden

- die spitzen Klammern um den Dateinamen bewirken, daß zunächst das "INCLUDE"-Verzeichnis (bei UNIX Systemen meist /usr/lib/include) und erst dann das Arbeitsverzeichnis nach der angegebenen Datei durchsucht wird

- auf verschiedenen Rechnern kann EOF 0 oder -1 sein, daher die Definition von EOF in einer Headerdatei

- c ist als int deklariert, um den Wert EOF abfragen zu können

- getchar ist eine Funktion aus der Funktionsbibliothek, die 1 Zeichen von der Konsole (stdin) einliest

- putchar gibt 1 Zeichen auf die Konsole (stdout) aus

- != bedeutet ungleich

- nach der while Bedingung sind 2 Anweisungen mittels geschweifter Klammern zu einem Block zusammengefaßt

- man hätte das Programm auch noch kompakter so formulieren können

  while ((c=getchar()) != EOF)
      putchar(c);

die Klammerung ist sehr wichtig sonst wird c der Wert des Vergleiches von getchar() mit EOF und nicht das gelesene Zeichen zugewiesen

Beispielprogramm P3-7.C

/* Beispiel 7 */
/* Programm zum Zaehlen von Eingabezeichen */
#include <stdio.h>
main()
{
long nc;
nc = 0;
while (getchar() != EOF)
    ++nc;
printf ("%ld\n",nc);
}

Erläuterungen zu diesem Programm:

- ++nc ist eine Inkrementoperation für die Variable nc, analog ist --nc eine Dekrementoperation

- ++nc und nc++ sind beide möglich, unterscheiden sich aber

- ++nc heißt erst inkrementieren, dann Wert von nc verwenden

- nc++ heißt erst Wert von nc verwenden, dann inkrementieren

- die Formatangabe %ld ist notwendig, da nc ein Long-Integerwert ist

Beispielprogramm P3-8.C

/* Beispiel 8 */
/* wie Beispiel 7, aber mit for-Schleife
   und anderer Datentyp fuer den Zaehler */
#include <stdio.h>
main()
{
double nc;
for (nc=0;getchar() != EOF; ++nc)
    ;
printf ("%.0f\n",nc);
}

Erläuterungen zu diesem Programm:

- die for-Schleife in diesem Fall hat keine abhängige Anweisung, daher das einzelne Semikolon in einer neuen Zeile (wichtig zur Dokumentation)

- die Formatangabe %.0f bewirkt die Ausgabe eine doppelt genauen Gleitpunktzahl ohne Nachkommastellen

Beispielprogramm P3-9.C

/* Beispiel 9 */
/* Programm zum Zaehlen der Eingabezeilen */
#include <stdio.h>
main()
{
int c,nl;
nl = 0;
while ((c=getchar()) != EOF)  /* Klammern sind wichtig */
    if (c == '\n')
        ++nl;
printf("%d\n",nl);
}

Erläuterungen zu diesem Programm:

- hier sehen wir eine if Kontrollstruktur, wobei die Bedingung wie bei while in Klammern gesetzt wird

- die if Kontrollstruktur sieht so aus:

if (Bedingung)

Anweisung(en)

else

Anweisung(en)

der else Zweig ist optional

- == bedeutet identisch

- '\n' ist eine Zeichenkonstante, deswegen in Hochkommas eingeschlossen

Beispielprogramm P3-10.C

/* Beispiel 10 */
/* Eingabezeilen, -worte und -zeichen zaehlen */
#include <stdio.h>
#define YES 1
#define NO 0
main()
{
int c, nl, nw, nc, inword;
inword = NO;
nl = nw = nc = 0;
while ((c=getchar()) != EOF) {
    ++nc;
    if (c == '\n')
        ++nl;
    if (c==' ' || c=='\n' || c=='\t')
        inword = NO;
    else if (inword == NO) {
        inword = YES;
        ++nw;
    }
}
printf("%d %d %d\n",nl,nw,nc);
}

Erläuterungen zu diesem Programm:

- verbundene Anweisungen wie nl=nw=nc=0; werden von rechts nach links abgearbeitet, sie sollten nach Möglichkeit vermieden werden

- || ist der (logische) ODER-Operator

- && ist der (logische) UND-Operator

- Ausdrücke mit logischen Operatoren werden von links nach rechts bewertet und dann abgebrochen, wenn das Ergebnis feststeht (also der erste Teilausdruck ungleich 0 (bei ODER) oder gleich 0 (bei UND) ist

Beispielprogramm P3-11.C

/* Beispiel 11 */
/* Ziffern, Zwischenraeume und andere Zeichen zaehlen */
#include <stdio.h>
main()
{
int c,i,nwhite,nother;
int ndigit[10];
nwhite=nother=0;
for (i=0; i<10; ++i)
    ndigit[i]=0;
while ((c=getchar()) != EOF)
    if (c>='0' && c<='9')
        ++ndigit[c-'0'];
    else if (c==' ' || c=='\n' || c=='\t')
        ++nwhite;
    else
        ++nother;
printf("Zahlen =");
for (i=0; i<10; ++i)
    printf(" %d",ndigit[i]);
printf("\n\"White Space\" = %d, andere = %d\n",
    nwhite,nother);
}

Erläuterungen zu diesem Programm:

- Vektoren (Felder) werden durch Anhängen von eckigen Klammern an den Variablennamen definiert

- die Feldindizes laufen von 0 bis N-1, sie werden nicht abgeprüft

- das Beispielprogramm gilt nur für Zeichencodes mit lückenlosem Aufeinanderfolgen von Ziffern (sowohl in EBCDIC als auch in ASCII erfüllt)

- char wird intern in int gewandelt, deshalb ist der Ausdruck

  c-'0'

so einfach möglich

- Verkettungen von if und else sollte man so schreiben:

  if              oder           if
  else                           else if
      if
      else                       else

Beispielprogramm P3-12.C

/* Beispiel 12 */
/* die Funktion X hoch N */
main()
{
int i;
for (i=0; i<10; ++i)
    printf("%d %d %d\n",i,power(2,i),power(-3,i));
}
power(x,n)    /* x hoch n, n>0 */
int x,n;
{
int i,p;
p=1;
for (i=1; i<=n; ++i)
    p = p * x;
return(p);
}

Erläuterungen zu diesem Programm:

- hier haben wir zum ersten Mal eine "richtige" Funktion

- eine Funktion hat immer die Form:

Name(Parameterliste,optional)

Parameterdeklarationen,optional

{

Vereinbarungen

Anweisungen

return Funktionswert,optional

}

- die Parameternamen sind nur lokal bekannt

- die Parameterwerte sind durch die Funktion nur lokal nicht aber mit Wirkung für die aufrufende Funktion veränderbar

- die return Anweisung bewirkt einen Rücksprung mit der Übergabe des Funktionswertes, die Klammern um den Funktionswert sind syntaktisch nicht notwendig, aber üblich

- fehlt return, dann erfolgt der Rücksprung nach der letzten schließenden geschweiften Klammer, der Funktionswert ist dann unbestimmt

Beispielprogramm P3-13.C

/* Beispiel 13 */
/* Wie Beispiel 3, aber mit Einlesen der
   Grenzen und der Schrittweite */
#include <stdio.h>
main()
{
int i;
int lower,upper,step;
float fahr,celsius;
i=0;
while (i != 2) {
    printf("Bitte die Grenzen fuer die Berechnung in \
    der Form \"untere - obere\" angeben\n");
    i=scanf("%d - %d",&lower,&upper);
    if (i != 2 || upper<=lower) {
        printf("\n Falsche Eingabe \07\n");
        i = 0;
    }
}
i=0;
while (i != 1) {
    printf("Bitte die Schrittweite eingeben: ");
    i=scanf("%d",&step);
    if (i != 1 || step <= 0) {
        printf("\n Falsche Eingabe \07\n");
        i = 0;
    }
}
fahr = lower;
while (fahr <= upper) {
    celsius = (5.0/9.0) * (fahr-32.0);
    printf ("%4.0f %6.1f\n",fahr,celsius);
    fahr = fahr + step;
    }
}

Erläuterungen zu diesem Programm:

- wir haben hier das gleiche Programm wie in Beispiel P3-3.C, allerdings werden hier einige Daten interaktiv eingelesen

- das Einlesen wird von der Funktion scanf bewerkstelligt

- sie hat die gleiche Formatsteuerung wie printf

- die Parameter müssen aber Adressen sein (Warum?)

- & ist der Adressoperator, Ergebnis ist die Adresse des Objekts

- Funktionswert von scanf ist die Anzahl erfolgreich eingelesener Parameter

- alle Angaben in den Anführungsstrichen von scanf, die nicht zu Formatangaben gehören, müssen genauso eingegeben werden

- Strings dürfen über das Zeilenende hinausgehen, wenn unmittelbar vor dem Zeilenende ein \ steht

- \" gibt " aus

- \07 gibt das ASCII-Zeichen mit dem Oktalcode 07 (=BELL) aus

zurück zum Inhaltsverzeichnis