|
7 Zeiger und Vektoren
7.1 Vektoren
7.1.1 Eindimensionale Vektoren
7.1.2 Zeichenketten
7.1.3 Mehrdimensionale Vektoren
7.2 Zeiger
7.2.1 Zeiger und Adressen
7.2.2 Zeiger und Vektoren
7.2.3 Zeigerarithmetik
7.2.4 Zeiger auf Funktionen
7.3 Anwendungen
7.3.1 Vektoren von Zeigern und Zeiger auf Zeiger
7.3.2 Zeiger und mehrdimenisonale Vektoren
7.3.3 Argumente der Kommandozeile
7.1 Vektoren
7.1.1 Eindimensionale Vektoren
Zur Zusammenfassung mehrerer Objekte gleichen Typs zu einer Einheit
verwendet man Vektoren, oft auch als Felder (arrays) bezeichnet.
Sie bilden eine lineare Anordnung ihrer Grundobjekte im Speicher.
Sie werden durch die Verwendung von eckigen Klammern ([])
nach dem Variablennamen erzeugt. Innerhalb der Klammern wird die
Größe des Vektors (Feldes) in Anzahl Elementen des
definierten Typs angegeben:
char s; /* 1 Zeichen */
char sf[20]; /* 20 Zeichen */
int i; /* 1 ganze Zahl */
int iff[100]; /* 100 ganze Zahlen (= 400 Bytes bei 32 Bit) */
double f; /* 1 Fließkommazahl */
double ff[100]; /* 100 Fließkommazahlen (= 800 Bytes) */
|
Der Zugriff auf die einzelnen Vektorelemente erfolgt durch Angabe
des Vektornamens gefolgt vom Index in eckigen Klammern:
int j = 5, k;
sf[8] = 'a';
sf[j] = sf[19];
k = iff[j];
|
Das 1.Element hat immer den festgelegten Index 0,
das N-te den Index N-1. Vektorelemente können
L-Werte sein, Vektornamen alleine nicht, da sie feste Adressen
(nämlich die Adresse des 1. Vektorelementes) darstellen. Als dafür
zu große Einheit können Vektoren nicht in der
Speicherklasse register sein. Vektoren in der Speicherklassse
auto können nicht initialisiert werden,
dies ist nur bei Vektoren in den Speicherklassen static
und extern möglich. Werden diese nicht initialisiert,
so haben alle Elemente den Wert 0. Die Initialisierungswerte werden
nach einem Gleichheitszeichen in geschweiften Klammern angegeben.
Nicht initialisierte Elemente erhalten ebenfalls den Wert 0.
Beispiele für Vektorinitialisierungen:
static int iff[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
static int jf[5] = { 0, 1, 3}; /* restl. Elemente = 0 */
static int kf[] = { 1, 3, 5, 7, 11, 13}; /* Laenge aus Anzahl */
/* Init-Elemente */
|
Nachfolgend einige Beispiele für Vektorverarbeitung:
/* Feld mit der Summe der natuerlichen Zahlen bis zu
diesem Feldelement belegen */
#define MAX 100
int sum[MAX], i, j;
for (i = 0, j = 0; i < MAX; i++) {
j = j + i + 1;
sum[i] = j;
}
|
/* nochmals unter Auslassung des 1.Elementes */
#define MAX 101
int sum[MAX], i, j;
for (i = 1,j = 0; i < MAX; i++) {
j = j + i;
sum[i] = j;
}
|
/* Feld mit den Quadratzahlen belegen, 1.Version */
#define MAX 100
int mul[MAX], i;
for (i = 0; i < MAX; i++)
mul[i] = (i + 1) * (i + 1);
|
/* Feld mit den Quadratzahlen belegen, 2.Version */
#define MAX 100
int mul[MAX], i, j;
for (i = 0, j = 1; i < MAX; i++, j++) {
mul[i] = j * j;
|
7.1.2 Zeichenketten
Zeichenketten sind eindimensionale Vektoren oder Felder von Zeichen.
Sie zeichnen sich durch einige Besonderheiten aus:
Sie können auch in der Speicherklasse auto initialisiert werden.
Als Zeichenkette müssen sie mit '\0' abgeschlossen sein.
Dies läßt sich aber auch automatisch mit Hilfe der
vereinfachten Initialisierung erreichen:
char s[] = { 's', 't', 'r', 'i', 'n', 'g', '\0'};
char s[] = "string"; /* \0 intern angehaengt */
char s[10] = "string"; /* restl. Elemente mit 0 init. */
|
Ansonsten werden Zeichenketten wie normale Vektoren behandelt.
Insbesondere ist der Zugriff auf Vektorelemente, d.h. auf einzelne
Zeichen in einer Zeichenkette gleich:
char s = "string";
s[0] hat den Wert 's'
s[3] hat den Wert 'i'
s[6] hat den Wert '\0'
|
7.1.3 Mehrdimensionale Vektoren
Mehrdimenisonale Vektoren werden durch 2 oder mehr Paare eckiger
Klammern nach dem Objektnamen definiert (Dabei stehen zwischen
den Klammern keine Kommata.). Ein 2-dimensionaler Vektor ist ein
Vektor, dessen Komponenten Vektoren sind, für höhere
Dimensionen gilt Entsprechendes. Die Angabe der Elementanzahl
der ersten Dimension kann (in Funktionen) fehlen, die der anderen
Dimensionen nicht, da sonst die Indexberechnung nicht richtig
arbeiten kann.
/* Deklaration extern oder in der aufrufenden Funktion */
int md[5][10];
funct(md, 5);
/* in der Funktion, anzahl gibt die Groesse der 1. Dimension an */
void funct(int mdf[][10], anzahl)
{
int i, j;
for (i = 0; i < anzahl; i++)
for (j = 0; j < 10; j++)
mdf[i][j] = i + j;
}
|
Die gleiche Vektorbelegung wie mit diesem kurzen Programm kann
man auch durch Initialisierung erreichen. Diese müßte
dann wie folgt aussehen:
static int md[5][10] = {
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 },
{ 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 },
{ 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 },
{ 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 }
};
|
Die Angaben für die 2. (und weitere) Dimension werden also
jeweils in eigene geschweifte Klammern geschrieben. Innerhalb
der geschweiften Klammern gilt wiederum, daß evtl. nicht
initialisierte Elemente auf 0 gesetzt werden. Man kann die inneren
geschweiften Klammern auch weglassen, dann wird der ganze Vektor
Element für Element initialisiert.
Beispielprogramm p7-1.c
/*
* p7-1.c
* Beispielprogramm 1, Abschnitt 7
*/
static int day_tab[2][13] = {
{ 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
{ 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
};
/* Tag im Jahr aus Monat und Tag bestimmen */
int day_of_year(int year, int month, int day)
{
int i, leap;
leap = year % 4 == 0 && year % 100 != 0 || year % 400 == 0;
for (i = 1; i < month; i++)
day += day_tab[leap][i];
return (day);
} /* day_of_year() */
/* Monat und Tag aus Tag im Jahr */
void month_day(int year, int yearday, int *pmonth, int *pday)
{
int i, leap;
leap = year % 4 == 0 && year % 100 != 0 || year % 400 == 0;
for (i = 1; yearday > day_tab[leap][i]; i++)
yearday -= day_tab[leap][i];
*pmonth = i;
*pday = yearday;
} /* month_day() */
|
7.2 Zeiger
7.2.1 Zeiger und Adressen
Vektoren werden über ihre Anfangsadresse angesprochen und
auch mittels dieser Anfangsadresse an Funktionen übergeben.
Die Anfangsadresse eines Vektors steht fest, ist also eine
Konstante. Im Gegensatz dazu ist ein Zeiger eine
Variable, die die Adresse eines (beliebigen) anderen Objektes
enthält. Man kann auf dieses Objekt indirekt über einen
Zeiger zugreifen.
Die Adresse eines Objektes erhält man durch Anwendung des
Adreßoperators &. & kann auf Variablen
und Vektorelemente angewendet werden, nicht aber auf Vektornamen
selbst (Warum? Ein Vektorname hat keine Adresse, er ist
eine Adresse!). Ebenso haben natürlich Variablen in der Speicherklasse
register keine Adressen.
Beispiele für die Anwendung des Adreßoperators und
das Speichern der Adresse in einem Zeiger:
px = &x; /* px erhält als Wert die Adresse von x */
pf = &f[5]; /* pf erhält als Wert die Adresse des
6. Elementes von f */
|
Der Zugriff auf ein Objekt, dessen Adresse in einer Variablen
(einem Zeiger) steht, geschieht mittels des Operators *
(Inhalt von):
y = *px /* y erhält den Wert des Objektes, dessen
Adresse in px steht */
px = &x;
y = *px; /* y = x; */
|
Zeiger zeigen immer auf Objekte eines bestimmten Typs. Sie müssen
daher deklariert werden. Auch in der Zeigerdefinition wird der
Operator * verwendet. Zeigerdefinitionen kann man als Muster
verstehen:
int *pk; /* pk ist Zeiger auf int */
char *zs; /* zs ist Zeiger auf char */
int x, y, *px;
px = &x; /* Adressen */
y = *px; /* Werte */
|
Die Kombination *Zeiger kann in Ausdrücken überall
dort auftreten, wo auch das Objekt, auf das der Zeiger zeigt,
selbst stehen könnte:
y = *px + 10;
y = *px + *px;
printf("%d\n", *px);
*px = 0;
py = px; /* falls py auch Zeiger auf int */
|
Bei der Verwendung des Operators * muß man die Operatorrangfolge
und -assoziativität genau beachten. Dies erscheint zunächst
etwas schwierig, da dieser Operator ungewohnt ist. Hier einige
Beispiele mit dem * Operator und anderen Operatoren:
y = *px + 1; /* Inhalt von px plus 1 */
y = *(px+1); /* Inhalt der Adresse px+1 */
*px += 1; /* Inhalt von px = Inhalt von px plus 1 */
(*px)++; /* Inhalt von px inkrementieren */
*px++; /* wie *(px++); (Assoziativität)
Inhalt der Adresse px; px = px plus 1*/
*++px; /* Inhalt der Adresse px+1; px = px plus 1 */
|
Zeiger haben nur dann sinnvolle Werte, wenn sie die Adresse eines
Objektes oder 0 enthalten. Für den Zeigerwert 0 ist garantiert,
daß er nirgends hinzeigt (NULL bzw. NIL(in PASCAL)).
Beispielprogramm p7-2.c
/*
* p7-2.c
* Beispielprogramm 2, Abschnitt 7
* Vertauschen von Parametern
*/
#include <stdio.h>
void no_swap(int, int);
void do_swap(int *, int *);
void main(void)
{
int i, j;
i = 5; j = 10;
printf("i=%2d j=%2d\n", i, j);
no_swap(i, j);
printf("i=%2d j=%2d\n", i, j);
do_swap(&i, &j);
printf("i=%2d j=%2d\n", i, j);
} /* main() */
/* Funktioniert nicht, da Werte uebergeben werden */
void no_swap(int x, int y)
{
int temp;
temp = x;
x = y;
y = temp;
} /* no_swap() */
/* Funktioniert, da Adressen uebergeben werden */
void do_swap(int *px, int *py)
{
int temp;
temp = *px;
*px = *py;
*py = temp;
} /* do_swap() */
|
7.2.2 Zeiger und Vektoren
Zeiger und Vektoren hängen sehr eng zusammen. Das sieht man
schon daran, daß ein Vektorname genau wie ein Zeiger auch
eine Adresse ist (allerdings eine Adreßkonstante). Als Konsequenz
aus dem engen Zusammenhang zwischen Vektoren und Zeigern ergibt
sich die für den Anfänger zunächst etwas verwirrende
Tatsache, daß alle Operationen mit Vektorindizes auch mit
Zeigern formuliert werden können. Dies ist meist effizienter,
aber für Anfänger schwerer zu verstehen. Ausgehend von
den Definitionen und Anweisungen:
int a[10]; /* int Vektor mit 10 Elementen */
int *pa, y; /* Zeiger auf int Objekte */
pa = &a[0]; /* pa hat Adresse 1. Vektorelement */
pa = a; /* pa hat ebenfalls Adresse 1. Element */
y = *pa; /* y = 1. Element von Vektor a */
|
sind die folgenden Angaben äquivalent:
a[i] *(a+i) /* i + 1tes Element des Vektors a */
&a[i] (a+i) /* Adresse des i + 1ten Elementes */
pa[i] *(pa+i)
|
Statt Vektorname und Indexausdruck kann immer auch ein Zeiger
mit Abstand stehen. Als Konsequenz aus Vektorname (= Adresskonstante)
und Zeiger (= Adressvariable) ergeben sich folgende erlaubten und
nicht erlaubten Zusweisungen:
pa = a; /* erlaubt */ a = pa; /* falsch */
pa++; /* erlaubt */ a++; /* falsch */
|
Beispielprogramm p7-3.c
/*
* p7-3.c
* Beispielprogramm 3, Abschnitt 7
* Laenge einer Zeichenkette ermitteln
*/
/* 1. Version mit Vektoren */
int strlen1(char s[])
{
int n;
for (n = 0; s[n] != '\0'; n++)
n++;
return(n);
} /* strlen1() */
/* 2. Version mit Zeiger */
int strlen2(char *s)
{
int n;
for (n = 0; *s != '\0'; s++)
n++;
return(n);
} /* strlen2() */
|
7.2.3 Zeigerarithmetik
Mit Zeigern können bestimmte arithmetische Operationen und
Vergleiche durchgeführt werden. Es sind natürlich nur
die Operationen erlaubt, die zu sinnvollen Ergebnissen führen.
Zu Zeigern dürfen ganzzahlige Werte addiert und es dürfen
ganzzahlige Werte subtrahiert werden. Zeiger dürfen in- und
dekrementiert werden und sie dürfen voneinander subtrahiert
werden (Dies ist i.a. nur sinnvoll, wenn beide Zeiger auf Elemente
des gleichen Objektes, z.B. einen Vektor, zeigen.).
Man kann Zeiger mittels der Operatoren >, >=,
<, <=, != und == miteinander vergleichen.
Wie bei der Zeigersubtraktion ist das aber i.a. nur dann sinnvoll,
wenn beide Zeiger auf Elemente des gleichen Vektors zeigen.
Eine Ausnahme bildet hier der Zeigerwert NULL, der sog. NULL-Pointer,
der i.a. einen ungültigen Zeigerwert bezeichnet.
Alle anderen denkbaren arithmetischen und logischen Operationen
(Addition von 2 Zeigern, Multiplikation, Division, Shifts oder
Verwendung von logischen Operatoren, sowie Addition und Subtraktion
von float oder double Werten) sind mit Zeigern nicht
erlaubt.
Wie funktioniert nun aber die Zeigerarithmetik? Sei p ein Zeiger
und n eine ganze Zahl, dann bezeichnet p + n das n-te Objekt
im Anschluß an das Objekt, auf das p gerade zeigt. Es wird
also nicht der Wert n zu p direkt addiert, sondern n wird vorher
mit der Typlänge des Typs, auf den p zeigt, multipliziert.
Dieser Typ wird aus der Deklaration von p bestimmt.
Beispielprogramm p7-4.c
/*
* p7-4.c
* Beispielprogramm 4, Abschnitt 7
* Laenge einer Zeichenkette ermitteln
*/
int strlen(char *s)
{
char *p = s;
while (*p != '\0')
p++;
return(p - s);
} /* strlen() */
|
Beispielprogramm p7-5.c
/*
* p7-5.c
* Beispielprogramm 5, Abschnitt 7
* Einfache Speicherverwaltung
*/
#define NULL 0 /* Zeigerwert fuer Fehleranzeige */
#define ALLOCSIZE 1000 /* verfuegbarer Platz */
static char allocbuf[ALLOSIZE];
static char *allocp = allocbuf; /* naechste freie Position */
/* liefert Zeiger auf Platz fuer n Zeichen */
char *alloc(int n)
{
if (allocp + n <= allocbuf + ALLOCSIZE) { /* reicht */
allocp += n;
return (allocp - n); /* alter Zeiger */
}
else /* nicht genug Platz */
return (NULL);
} /* alloc() */
/* Speicher ab p freigeben */
void free(char *p)
{
if (p >= allocbuf && p <= allocbuf + ALLOCSIZE)
allocp = p;
} /* free() */
|
Beispielprogramm p7-6.c
/*
* p7-6.c
* Beispielprogramm 6, Abschnitt 7
* 4 Versionen einer Stringkopierfunktion
*/
/* 1. t nach s kopieren Version mit Vektoren */
void strcpy1(char s[],char t[])
{
int i;
i = 0;
while ((s[i] = t[i]) != '\0')
i++;
} /* strcpy1() */
/* 2. t nach s kopieren, 1. Version mit Zeigern */
void strcpy(char *s, char *t)
{
while ((*s = *t) != '\0') {
s++;
t++;
}
} /* strcpy2() */
/* 3. t nach s kopieren, 2. Version mit Zeigern */
void strcpy3(char *s, char *t)
{
while ((*s++ = *t++) != '\0')
;
} /* strcpy3() */
/* 4. t nach s kopieren, 3. Version mit Zeigern */
void strcpy(char *s, char *t)
{
while (*s++ = *t++)
;
} /* strcpy4() */
|
Beispielprogramm p7-7.c
/*
* p7-7.c
* Beispielprogramm 7, Abschnitt 7
* 2 Versionen einer Stringvergleichsfunktion
* liefert 0, wenn Strings gleich sind
*/
/* 1. Version mit Vektoren */
int strcmp1(char s[], char t[])
{
int i;
i = 0;
while (s[i] == t[i])
if (s[i++] == '\0')
return (0);
return (s[i] - t[i]);
} /* strcmp1() */
/* 2. Version mit Zeigern */
void strcmp2(char *s, char *t)
{
for ( ; *s == *t; s++, t++)
if (*s == '\0')
return (0);
return (*s - *t);
} /* strcmp2() */
|
7.2.4 Zeiger auf Funktionen
In C ist eine Funktion keine Variable, sondern der Funktionsname
ist (wie ein Vektorname) eine Adreßkonstante. Es können
daher Zeiger auf Funktionen definiert werden, die man dann wie
Variablen verwenden kann. Damit wird es möglich, Funktionen
an Funktionen zu übergeben.
Ein Zeiger auf eine Funktion wird so vereinbart:
(*Funktionsname)() /* Zeiger auf eine Funktion */
|
Im Gegensatz zu:
*Funktionsname() /* Funktion, die einen Zeigerwert liefert */
|
Die Möglichkeit und der Gebrauch von Zeigern auf Funktionen
wird am besten an einem Beispiel klar:
/* in der aufrufenden Funktion */
int iv[];
char *sv[];
int strcmp(), numcmp(), swap(), turn();
sort(iv, numcmp, swap); /* sortiere mittels der Funktionen */
/* numcmp und swap */
sort(sv, strcmp, swap); /* sortiere mittels der Funktionen */
/* strcmp und swap */
sort(iv, numcmp, turn); /* sortiere mittels der Funktionen */
/* numcmp und turn */
/* in der gerufenen Funktion */
sort(void v[], int (*comp)(), int (*exch)())
{
int j, gap;
...
if ((*comp)(v[j], v[j+gap]) <= 0)
break;
(*exch)(&v[j], &[j+gap]);
...
} /* sort() */
|
7.3 Anwendungen
7.3.1 Vektoren von Zeigern und Zeiger auf Zeiger
Genauso wie man Vektoren aus den Grunddatentypen (char, int, float
und double) bilden kann, kann man dies auch mit Zeigern tun. Ein
Vektor von Zeigern wird so definiert:
gelesen von rechts nach links (wegen des Vorranges von []):
Vektor von Zeigern. Dagegen ist
ein Zeiger auf einen Vektor.
Zeiger auf Zeiger sind eine äquivalente Formulierung für
Vektoren von Zeigern
int *iff[]; /* sind äquivalent, da iff die
int **iff; Adresse des Vektors enthält */
|
Das folgende Beispiel zeigt, wie man einen Vektor von Zeigern
initialisieren kann:
Beispielprogramm p7-8.c
/*
* p7-8.c
* Beispielprogramm 8, Abschnitt 7
* Name des Monats n liefern
*/
char *month_name(int n)
{
static char *name[] = { /* Vektor von Zeigern */
"falscher Monat", /* String ist ein char-Vektor */
"Januar", /* und daher durch seine */
"Februar", /* Anfangsadresse charakterisiert */
"Maerz",
"April",
"Mai",
"Juni",
"Juli",
"August",
"September",
"Oktober",
"November",
"Dezember"
};
return ((n < 1 || n > 12) ? name[0] : name[n]);
} /* month_name() */
|
Beispielprogramm p7-9.c
/*
* p7-9.c
* Beispielprogramm 9, Abschnitt 7
* Programm zum Einlesen, alphabetischen Sortieren
* und Ausgeben von Eingabezeilen
*/
#include <stdio.h>
#define NULL 0
#define LINES 100 /* maximale Anzahl Zeilen */
void main(void)
{
char *lineptr[LINES]; /* Zeiger auf Textzeilen */
int nlines; /* Anzahl gelesener Zeilen */
if ((nlines = readlines(lineptr, LINES)) >= 0) {
sort(lineptr, nlines);
writelines(lineptr, nlines);
}
else
printf ("input too big to sort\n");
} /* main() */
#define MAXLEN 1000 /* Maximallaenge einer Zeile */
/* Zeile einlesen */
int getline(char line[], int lim)
{
int c, i;
i = 0;
while (--lim > 0 && (c = getchar()) != EOF && c != '\n')
s[i++] = c;
if (c == '\n')
s[i++] = c;
s[i] = '\0';
return(i);
} /* getline() */
/* Eingabezeilen einlesen um sie zu sortieren */
int readlines(char *lineptr[], int maxlines)
{
int len, nlines;
char *p, *malloc(), line[MAXLEN];
nlines = 0;
while ((len = getline(line, MAXLEN)) > 0)
if (nlines >= maxlines)
return(-1);
else if ((p = malloc(len)) == NULL)
return(-1);
else {
line[len - 1] = '\0'; /* Zeilentrenner entfernen */
strcpy(p, line);
lineptr[nlines++] = p;
}
return(nlines);
} /* readlines() */
/* Zeilen ausgeben */
void writelines(char *lineptr[], int nlines)
{
int i;
for (i = 0; i < nlines; i++)
printf("%s\n", lineptr[i]);
} /* writelines() */
/* Zeichenketten v[0],...,[n-1] in aufsteigender Reihen- */
/* folge sortieren, es werden die Zeichenketten */
/* verglichen und ihre Zeiger entsprechend sortiert */
sort(char *v[], int n)
{
int gap, i, j;
char *temp;
for (gap = n/2; gap > 0; gap /= 2)
for (i = gap; i < n; i++)
for (j = i - gap; j >= 0; j -= gap) {
if (strcmp(v[j], v[j + gap]) <= 0)
break;
temp = v[j];
v[j] = v[j + gap];
v[j + gap] = temp;
}
} /* sort() */
|
7.3.2 Zeiger und mehrdimensionale Vektoren
Ein mehrdimensionaler Vektor ist ja ein Vektor, dessen Elemente
selbst wieder Vektoren sind (siehe Abschnitt 7.1.3). Man kann
solche Vektoren auch mit Zeigern realisieren. Betrachten wir dazu
folgendes Beispiel:
int md[10][10]; /* 2 dimensionaler Vektor mit insgesamt
100 int-Elementen */
int *mp[10]; /* Vektor mit 10 Zeigern auf int-Objekte */
|
Die Ausdrücke
sind beide möglich und bezeichnen das gleiche Element.
md ist ein Vektor mit 10 Elementen, die selbst wiederum
Vektoren mit je 10 int Elementen sind. Insgesamt enthält
md also 100 Elemente, für die auch der Speicherplatz
bereitgestellt wird.
mp ist ein Vektor mit 10 Elementen, die Zeiger auf int
Objekte sind (Speziell könnten diese natürlich auch
auf je einen int Vektor mit je 10 Elementen zeigen.).
Im Falle von mp wurden aber nur 10 Speicherplätze für
die Zeiger angelegt, die noch nicht initialisiert sind. Im Vergleich
zu md wird hier für das gleiche Feld insgesamt mehr
Speicherplatz und evtl. eine Initialisierung benötigt. Dafür
hat man aber 2 Vorteile:
- wegen einfacherer Adressierung (meist) schnellere Programmausführung
- Zeiger können auf verschieden lange Vektoren zeigen (höhere
Dimensionen der Vektoren haben immer eine feste Länge)
7.3.3 Argumente der Kommandozeile
Bisher haben wir die Funktion main als parameterlos behandelt.
Im allgemeinen hat diese Funktion aber 2 Parameter argc
und argv, die Angaben über die Kommandoparameter beim
Programmaufruf enthalten.
argc ist ein int Parameter und enthält die
Anzahl der Paramter der Kommandozeile einschließlich des
Programmaufrufes selbst (hat also immer mindestens den Wert 1).
argv ist ein Vektor mit Zeigern auf Zeichenketten.
Diese Zeichenketten enthalten die Aufrufparameter der Kommandozeile,
wobei der 1. Parameter der Programmaufruf selbst
ist. Letztes Argument ist die Vektorkomponente argv[argc - 1].
Beispiel:
# Programmaufruf auf Betriebssystemebene
$ echo Hier ist Echo!
# Werte von argc und argv im aufgerufenen Programm
argc = 4
argv[0] = "echo"
argv[1] = "Hier"
argv[2] = "ist"
argv[3] = "Echo!"
|
Beispielprogramm p7-10.c
/*
* p7-10.c
* Beispielprogramm 10, Abschnitt 7
* 3 Versionen des echo-Programms
*/
/* Echo der Aufrufargumente 1.Version */
void main1(int argc, char *argv[])
{
int i;
for (i = 1; i < argc; i++)
printf("%s%c", argv[i], (i < argc - 1) ? ' ' : '\n');
} /* main1() */
/* Echo der Aufrufargumente 2.Version */
void main2(int argc, char *argv[])
{
while (--argc > 0)
printf("%s%c", *++argv, (argc > 1) ? ' ' : '\n');
} /* main2() */
/* Echo der Aufrufargumente 3.Version */
void main3(int argc, char *argv[])
{
while (--argc > 0)
printf((argc > 1) ? "%s " : "%s\n", *++argv);
} /* main3() */
|
Beispielprogramm p7-11.c
/*
* p7-11.c
* Beispielprogramm 11, Abschnitt 7
* Programm zum Finden von Zeilen, die ein anzugebendes
* Suchmuster enthalten bzw. nicht enthalten
* Aufruf: find [-n] [-x] suchmuster
*/
#include <stdio.h>
#define MAXLINE 1000
int getline(char [], int);
int index(char [], char []);
void main(int argc, char *argv[])
{
char line[MAXLINE], *s;
long lineno = 0;
int except = 0, number = 0;
while (--argc > 0 && (*++argv)[0] == '-')
for (s = argv[0]+1; *s != '\0'; s++)
switch (*s) {
case 'x':
except = 1;
break;
case 'n':
number = 1;
break;
default:
printf("find: illegal option %c\n",*s);
argc = 0;
break;
}
if (argc != 1)
printf("Usage: find [-x] [-n] pattern\n");
else
while (getline(line, MAXLINE) > 0) {
lineno++;
if ((index(line, *argv) >= 0) != except) {
if (number)
printf("%ld: ",lineno);
printf("%s",line);
}
}
} /* main() */
/* Zeile in s ablegen, Laenge liefern */
int getline(char s[], int lim)
{
int c, i;
i = 0;
while (--lim > 0 && (c = getchar()) != EOF && c != '\n')
s[i++] = c;
if (c == '\n')
s[i++] = c;
s[i] = '\0';
return(i);
} /* getline() */
/* Position von t in s liefern, -1 falls nicht da */
int index (char s[], char t[])
{
int i, j, k;
for (i = 0; s[i] != '\0'; i++) {
for (j = i, k = 0; t[k] != '\0' && s[j] == t[k]; j++, k++)
;
if (t[k] == '\0')
return(i);
}
return(-1);
} /* index() */
|
zurück zum Inhaltsverzeichnis
|
|