18.2 Die Argumentliste am Anfang oder Ende kennzeichnen 

Diese vier Makros werden Sie jetzt anwenden. Es soll eine Funktion geschrieben werden, die eine variable Anzahl von Argumenten erhält. Die Argumente (Ganzzahlen) werden dabei alle zu einer Summe addiert. Hier sehen Sie das Listing:
/* vargs1.c */ #include <stdio.h> #include <stdlib.h> #include <stdarg.h> int add(int zahlen, ...) { va_list zeiger; int zahl; va_start(zeiger,zahlen); do { zahl = va_arg(zeiger,int); zahlen += zahl; } while(zahl != 0); va_end(zeiger); return zahlen; } int main(void) { int erg; printf("%d\n",add(11,12,13,0)); printf("%d\n",add(99,66,33,22,11,0)); erg = add(10, 13, 11, 0) + add(9, 8, 11, 0); printf("%d\n",erg); return EXIT_SUCCESS; }
Der Aufruf der Funktion erfolgt mit:
printf("%d\n",add(11,12,13,0));
Hier wird die Funktion add() mit den Argumenten 11, 12, 13 und 0 aufgerufen. Die Zahl 0 am Ende stellt die Abbruchbedingung dar. Zunächst wird der Argumentzeiger angelegt, mit dem die Liste der optionalen Argumente durchlaufen wird:
va_list zeiger;
Der Argumentzeiger erhält jetzt mithilfe des Makros va_start() die Position des ersten optionalen Arguments:
va_start(zeiger,zahlen);
Ohne diesen Aufruf wäre kein Zugriff auf die weiteren optionalen Argumente möglich. Man könnte auch sagen, der Datentyp zeiger verweist auf die Anfangsadresse der ersten Zahl in der Argumentliste. Anschließend wird in der do while-Schleife der Wert zurückgeliefert, auf den der Argumentzeiger gerade verweist.
zahl=va_arg(zeiger,int);
In diesem Beispiel ist dies die Zahl 12. Diese Zahl wird zu dem ersten Wert von zahlen (11) addiert. Außerdem wird nach dem Aufruf von va_arg() der Argumentzeiger auf das nachfolgende Argument gesetzt.
Ist die Bedingung der Schleife wahr (zahl != 0), fährt das Programm mit zahl=va_arg(zeiger,int), genauer gesagt dem nächsten Wert (13), fort und addiert diesen wieder mit zahlen. Beim nächsten Durchgang ist die while-Bedingung unwahr (zahl==0), und die Liste wird beendet mit:
va_end(zeiger);
Anhand des ersten Funktionsaufrufs können Sie sich dies grafisch so vorstellen:
Abbildung 18.1 Zugriff einzelner Werte bei einer variablen Argumentliste
Jetzt soll das Programm so umgeschrieben werden, dass mit einer bestimmten Anzahl von Argumenten gearbeitet wird:
/* vargs2.c */ #include <stdio.h> #include <stdlib.h> #include <stdarg.h> void print_zahlen(int anzahl, ...) { va_list zeiger; int zahl; int i; printf("Es werden %d Zahlen ausgegeben\n",anzahl); va_start(zeiger,anzahl); for(i = 1; i <= anzahl; i++) { zahl=va_arg(zeiger,int); printf("%d\t",zahl); } printf("\n"); va_end(zeiger); } int main(void) { print_zahlen(4,3,2,4,7); print_zahlen(6,11,22,33,44,55,66); return EXIT_SUCCESS; }
Das Programm ist ähnlich aufgebaut wie im Beispiel zuvor, nur dass hier als Abbruchbedingung das erste Argument verwendet wurde. In dem Funktionsaufruf
print_zahlen(6, 11, 22, 33, 44, 55, 66);
wird durch das erste Argument gekennzeichnet, dass die Funktion mit 6 Argumenten vom Typ int aufgerufen wird. Dies ist auch die Abbruchbedingung für die for-Schleife in der Funktion print_zahlen().
Diese Makros sind natürlich noch deutlich vielseitiger, als Beispiel sei die Funktion strcat() zum Anhängen eines Strings an einen anderen genannt. Häufig würden Sie sicherlich gern mehrere Strings auf einmal an einen anderen hängen. Dabei mussten Sie bislang immer mehrere strcat()-Aufrufe ausführen. Mit dem eben gezeigten Beispiel kann dies jetzt in einem Schritt realisiert werden:
strxcat(3, string, string1, string2);
Hiermit werden die beiden Strings string1 und string2 an den String string gehängt. Die Anzahl der Strings wird am Anfang der Argumentliste gekennzeichnet. Hierzu das Listing:
/* strxcat.c */ #include <stdio.h> #include <stdarg.h> #include <string.h> #include <stdlib.h> #define MAX 50 void strxcat(int n_strings, ...) { va_list zeiger; char *quelle, *ziel, *p; va_start(zeiger,n_strings); /* nun auf den Zielstring */ ziel = va_arg(zeiger,char *); p = ziel; /* am Ende vom Zielstring */ ziel+=strlen(ziel); if( (ziel-p) > MAX) { printf("!!!Maximale Anzahl an Zeichen ueberschritten!!!\n"); return; } while(--n_strings > 0) { /* Quelle einlesen */ quelle = va_arg(zeiger, char *); /* jetzt Zeichen für Zeichen an ziel */ while(*quelle) { *ziel++ = *quelle++; if( (ziel-p) > MAX) { printf("!Maximale Anzahl an Zeichen ueberschritten!\n"); exit(EXIT_FAILURE); } } } *ziel = '\0'; } int main(void) { char string[MAX] = "Test : "; char string2[] = " Und"; strxcat(3, string, "hallo " , "welt"); printf("%s\n",string); strxcat(5, string, string2, " noch", " ein", " Test"); printf("%s\n",string); /*Und nun ein Fehler mit Absicht*/ strxcat(4, string , " Ueberlauf", " von", " MAX"); printf("%s\n",string); return EXIT_SUCCESS; }
Abbildung 18.2 Mehrere Strings auf einmal aneinanderhängen
Hier wurde auch eine Sicherung eingebaut, um sich vor sogenannten Pufferüberläufen zu schützen.
Ihre Meinung
Wie hat Ihnen das Openbook gefallen? Wir freuen uns immer über Ihre Rückmeldung. Schreiben Sie uns gerne Ihr Feedback als E-Mail an kommunikation@rheinwerk-verlag.de.