Inhalt des Kurses zurück weiter

C Kurs Tag 6: Die Parameter von 'main'

Nun arbeiten wir ein wenig mit Zeigern und Zeichenketten. In der folgenden Zeile definieren wir eine globale Zeichenkette.

const char Nichts[] = "<NIL>";

Da keine explizite Länge zwischen den beiden eckigen Klammern steht, setzt der Compiler die Länge der angegeben Konstante ein. In Unserem Falle sind das 6 Zeichen. Wieso 6? Nun ein Zeichen wird für die Markierung des Endes der Zeichenkette benötigt. Diese Zeichen hat den ASCII-Code 0, deshalb spricht man auch von NULL-Terminierten Zeichenketten. Um Sonderzeichen in eine Zeichenkette einzufügen, muß man den 'backslash' den zurückfallenden Strich benutzen. Wir haben ihn ja schon bei 'printf' kennengelernt. Hier ein paar Beispiele

\0 Ende einer Zeichekette
\n newline = Zeilenvorschub, Zum Anfang einer neuen Zeile
\r return = Wagenrücklauf, Zurück zum Anfang der Zeile
\t tab = eine Tabulatorposition vorwärts.
\b backspace = das letzte Zeichen löschen (bei der Ausgabe).
\033 escape = ein Steuerzeichen bei der Bildschirmausgabe.
\0x1b escape = Heaxdezimal 1B gleich Oktal 33

Wir können unsere globale Zeichenkette auch so definieren:

const char Nichts[ 6 ] = "<NIL>\0";

Nun benutzen wir ein Makro für eine komplexere Konstante:

#define NIL ( (char *)0L )

Damit definieren wir eine Konstante mit dem Wert 0. Diese Konstante wird durch '(char *)' als Zeigerkonstante auf den Typ 'char' definiert. Diese Darstellung stellt einen nicht gültigen Zeiger dar. Wir benutzen sie um eine Zeiger zu Prüfen und so eine Referenzierung auf die Adresse 0 zu verhindern. Ein solcher Fall würde zu folgendem schweren Fehler führen:

ATARI, MAC Bus Error

UNIX Segmentation fault, core dumped

AMIGA Guru-Meditation

Bei der Definition von Zeigern gibt es eine Besonderheit zu berücksichtigen: Der Stern '*' gehört immer zum Namen der Variable, nicht zur Beschreibung des Typs. Dazu ein typisches Beispiel:

char * a, b;

Hier glaubt man leicht, es seien zwei Zeiger vom Typ 'char *' definiert. Die Varaible 'b' ist aber vom Typ 'char'. Besser schreibt man daher:

char *a, b;

Man beachte auch den Unterschied folgender Definitionen:

char Text[] = "Inhalt";

char *Zeiger = "Inhalt";

Bei der Ausgabe mit 'printf' liefern beide Namen den passenden String. Die Speicher der Strings sind aber anders aufgebaut. Der Name 'Text' ist die Adresse des Speicherplatzes, an der der Compiler den String gespeichert hat. Dieser liegt im allgemeinen im ROM, er ist nicht schreibbar. Der Name 'Zeiger' ist eine Varaiable die mit der Adresse des Speicherplatzes initialisiert wird. Der Inhalt des Zeigers liegt hier ebenfalls im ROM. Der Zeiger selbst kann allerdings zur Laufzeit des Programms beliebig geändert werden.

Text[]

+-----+-----+-----+-----+-----+-----+-----+

| 'I' | 'n' | 'h' | 'a' | 'l' | 't' | 0 |

+-----+-----+-----+-----+-----+-----+-----+

Zeiger

+-----+-----+-----+-----+

| Adresse von Text |

+-----+-----+-----+-----+

Merke: Beim Zugriff auf den Inhalt gibt es keinen Unterschied zwischen Zeiger und Array. Die Ausdrücke '*(ptr + 7)' und 'prt[ 7 ]' sind gleich.

Der Funktion 'main' werden immer Parameter übergeben. Der erste Parameter ist die Anzahl der Elemente des folgenden Feldes. Der zweite Parameter ist ein Zeiger auf ein Feld von Zeigern auf Zeichenketten (Typ: const char **argv, oder const char *argv[]). Der Eintrag mit dem Index 0 enthält den Zeiger auf den Programmnamen. Wenn keine Parameter übegeben werden ist die Anzahl = 1; Für jeden übergebenen Parameter gibt es eine Zeiger. Die Struktur kann man sich folgendermaßen vorstellen.

char Name[]

+-----+-----+-----+-----+-----+-----+-----+-----+-----+

| 'A' | 'R' | 'G' | 'S' | '.' | 'E' | 'X' | 'E' | 0 |

+-----+-----+-----+-----+-----+-----+-----+-----+-----+

char Param_1[]

+-----+-----+-----+-----+-----+-----+

| 'T' | 'E' | 'S' | 'T' | '1' | 0 |

+-----+-----+-----+-----+-----+-----+

char Param_2[]

+-----+-----+-----+-----+-----+-----+-----+-----+

| 'P' | 'A' | 'R' | 'A' | 'M' | '_' | '2' | 0 |

+-----+-----+-----+-----+-----+-----+-----+-----+

char *Zeigerfeld[]

+-----+-----+-----+-----+

| Adresse von Name |

+-----+-----+-----+-----+

| Adresse von Param_1 |

+-----+-----+-----+-----+

| Adresse von Param_2 |

+-----+-----+-----+-----+

| NIL |

+-----+-----+-----+-----+

char **argv

+-----+-----+-----+-----+

| Adresse von Zeigerfeld|

+-----+-----+-----+-----+

Hier unser Programm:

Download der Datei "args1.c"


/*

ARGS.C

Version 1

09.03.92

Ausgeben der uebergebenen Argumente.

Tool Austesten von Scrips oder Batch-Dateien.

*/

#include <stdio.h>

#include <stdlib.h>

#define NIL ( (char *)0L )

const char Nichts[] = "<NIL>";

const char *pruefe_argument( const char *argument )

/*

Unterprogramm zum Pruefen eines Strings

Prueft voher auf Gueltigkeit des Zeigers

Wenn der Zeiger nicht gueltig ist wird

ein Zeiger auf den Text '<NIL>'zurueckgegeben

*/

{

if ( argument == NIL )

argument = Nichts;

return ( argument );

}

int main (

int anzahl_der_argumente,

const char *feld_der_argumente[]

)

{

int index;

if ( anzahl_der_argumente <= 0 ) {

printf( " Unmoeglicher Fehler, Anzahl <= 0\n" );

exit( 1 );

};

/* Der Parameter im Feld 0 ist der Programm-Name */

printf( " Programm-Name: \"%s\"\n",

pruefe_argument( feld_der_argumente[ 0 ] )

);

/* dann folgen die Parameter */

for ( index = 1; index < anzahl_der_argumente; index ++ ) {
printf( " %2d. Parameter: \"%s\"\n", index,

pruefe_argument( feld_der_argumente[ index ] )

);

};

return 0;

}

/* ENDE DER DATEI */