22.4 <stdlib.h>
 
In der Headerdatei <stdlib.h> befinden sich außer den Funktionen zum Allokieren von Speicherplatz noch weitere nützliche.
22.4.1 Programmbeendigung – exit(), _exit(), atexit() und abort()
 
Zur normalen Beendigung eines Programms können Sie außer return folgende Funktion verwenden:
void exit(int status);
Laut ANSI C-Standard ist es gleich, ob ein Programm mit der Funktion exit() oder return beendet wird – mit dem Unterschied, dass über exit() von einer beliebigen Position des Programms aus beendet werden kann. Bei return gelingt dies nur in der main()-Funktion. Der Ablauf von exit() lässt sich so erklären: Bei Programmbeendigung mit exit() werden zuvor alle gefüllten Puffer geleert, alle geöffneten Dateien geschlossen und alle temporären Dateien, die mit der Funktion tmpfile() angelegt wurden, gelöscht. Anschließend wird die Routine _exit() aufgerufen, und das Programm beendet sich.
Auch bei exit() gilt Gleiches mit dem Rückgabewert als Parameter wie schon beim Beenden der main()-Funktion mittels return. Ein Rückgabewert von 0 bedeutet, dass ein Programm ordentlich beendet wurde – ein Wert ungleich 0 hingegen sagt aus, dass etwas nicht ordnungsgemäß abgeschlossen wurde. Da dies, wie schon in Abschnitt 11.7 erwähnt, nicht unbedingt so implementiert sein muss, ist man auch hier mit den Standard-C Makros EXIT_SUCCESS (für eine erfolgreiche Beendigung) und EXIT_FAILURE (bei einem Fehler) auf der sicheren Seite als Parameter für exit().
Theoretisch kann die Funktion _exit auch gleich aufgerufen werden. Dies entspricht allerdings nicht dem ANSI C-Standard. Hier die Syntax:
#include <unistd.h> /* unter Linux/UNIX */
#include <stdlib.h> /* unter MS-DOS */
void _exit(int status);
Damit werden die oben genannten »Aufräumarbeiten« nicht vorgenommen.
Eine weitere Funktion für Beendigungsroutinen in der Headerdatei <stdlib.h> ist die Funktion atexit(). Die Syntax:
#include <stdlib.h>
int atexit(void (*funktion) (void));
Mit atexit() wird ein so genannter Funktionshandler eingerichtet. Alle Funktionen, die in atexit() angegeben sind, werden in einer Funktionsliste eingetragen und bei Beendigung des Programms in umgekehrter Reihenfolge ausgeführt, also nach dem LIFO-Prinzip (Last In First Out). Laut ANSI C können insgesamt 32 solcher Funktionen verwendet werden. Hierzu ein Beispiel:
/* atexit1.c */
#include <stdio.h>
#include <stdlib.h>
void funktion1(void) {
printf("Die Funktion funktion1 wurde aufgerufen\n");
}
void funktion2(void) {
printf("Die Funktion funktion2 wurde aufgerufen\n");
}
int main(void) {
atexit(funktion1);
atexit(funktion2);
printf("Wir beenden unser Programm\n");
exit(EXIT_FAILURE);
printf("Dies wird nicht mehr ausgegeben\n");
return EXIT_SUCCESS;
}
Solch ein Beispiel macht natürlich wenig Sinn. Sie können atexit() beispielsweise verwenden, um Log-Dateien zu schreiben, etwa wenn der User das Programm beendet, oder wenn ein Programm mit einem Fehler beendet wurde. Oder Sie können noch diverse Aufräumarbeiten durchführen, wie dies im folgenden Beispiel geschieht:
/* atexit2.c */
#include <stdio.h>
#include <stdlib.h>
char *memPtr;
void free_malloc(void) {
/* Wurde überhaupt Speicher reserviert? */
if(memPtr == NULL)
printf("Kein Speicher war reserviert!!!\n");
else {
free(memPtr);
printf("Speicher wurde freigegeben!!\n");
}
}
int main(void) {
memPtr =(char *) malloc(10000);
if(memPtr==NULL)
printf("Konnte keinen Speicher reservieren\n");
if(atexit (free_malloc) != 0)
printf("Konnte Funktionshandler nicht einrichten\n");
/* Nach vielen Zeilen Code beenden wir das Programm */
printf("Ein Fehler – Programm wird beendet – \n");
exit(EXIT_FAILURE);
printf("Wird nicht mehr ausgegeben\n");
return EXIT_SUCCESS;
}
Die nächste Funktion zur Beendigung oder in diesem Fall besser, zur abnormalen Beendigung eines Programms, ist die Funktion abort(). Die Syntax:
#include <stdlib.h>
void abort(void);
Diese Funktion bewirkt – wie der Name schon sagt – eine abnormale Programmbeendigung. abort() schickt dem aufrufenden Prozess das Signal SIGABRT. Dieses Signal sollte niemals ignoriert werden. Hier ein Mini-Beispiel dazu:
/* abort.c */
#include <stdio.h>
#include <stdlib.h>
int main(void) {
abort();
return EXIT_SUCCESS;
}
Das Programm wird mit folgender Fehlermeldung beendet:
Abnormal Programm termination
Hier wurde die Fehlerausgabe über stderr realisiert. Im Gegensatz zur Funktion exit() gibt es bei der Funktion abort() keine Vorgaben, ob der Ausgabepuffer geleert oder die temporären Dateien automatisch gelöscht werden. Somit ist diese Funktion nicht für Programme geeignet, die auf mehreren Systemen laufen müssen. Ebenso werden nach einem abort()-Aufruf die Funktionen, die mit atexit() eingerichtet wurden, nicht mehr ausgeführt.
POSIX.1 hingegen schreibt vor, dass zumindest alle noch offenen Standard-E-/A-Streams mit fclose() ordentlich geschlossen werden müssen.
22.4.2 Konvertieren von Strings in numerische Werte
 
Müssen Sie einen String in einen numerischen Wert konvertieren, gibt es hierfür in der Headerdatei <stdlib.h> gleich mehrere Funktionen. Einen String in einen int-Wert umwandeln können Sie mit der Funktion:
int atoi(char *string);
Ein String kann in einen long int-Wert mit der Funktion
long int atol(char *string);
umgewandelt werden, und soll ein double-Wert aus einem String werden, ist diese Funktion verfügbar:
double atof(char *string);
Es soll ein Programm geschrieben werden, das z.B. folgende Eingabe von der Kommandozeile verarbeiten kann:
typen 5 5.55 A 255555 3E234
Die Ausgabe sollte dann so aussehen:
 Hier klicken, um das Bild zu Vergrößern
Abbildung 22.1
Konvertieren von Strings in numerische Werte
Hierzu der Quellcode und die Funktionen atof() und atol():
/* string2val1.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <float.h>
#include <limits.h>
int main(int argc, char **argv) {
if(argc==1) {
printf("Keine Zahlen zum Auswerten vorhanden!\n");
return EXIT_FAILURE;
}
while(*++argv) {
if(strchr(*argv,'.') || strchr(*argv,'e') ||
strchr(*argv,'E')) {
if(((atof(*argv)) <= FLT_MAX)&&
((atof(*argv)) >= FLT_MIN)) {
printf("\n%s ist ein float-Wert\n", *argv);
printf("Maximaler float-Wert:%f\n", FLT_MAX);
printf("Kleinster pos. float-Wert : %f\n" , FLT_MIN);
}
else if(((atof(*argv)) <= DBL_MAX)&&
((atof(*argv)) >= DBL_MIN)) {
printf("\n%s ist ein double-Wert\n", *argv);
printf("Max. double-Wert:%f\n", DBL_MAX);
printf("Kleinster pos. double-Wert : %f\n", DBL_MIN);
}
}
else if(((atol(*argv)) < SHRT_MAX)&&
((atol(*argv))>SHRT_MIN) && (atol(*argv) != 0)) {
printf("\n%s ist ein short int-Wert\n",*argv);
printf("Maximaler short int-Wert: %d\n",SHRT_MAX);
printf("Kleinster short int-Wert: %d\n",SHRT_MIN);
}
else if(((atol(*argv)) < LONG_MAX) &&
((atol(*argv)) > LONG_MIN) && (atol(*argv) != 0)) {
printf("\n%s ist ein long-Wert\n",*argv);
printf("Maximaler long-Wert : %ld\n",LONG_MAX);
printf("Kleinster long-Wert : %ld\n",LONG_MIN);
}
else
printf("\nUnbekannter Typ (%s)!\n",*argv);
}
return EXIT_SUCCESS;
}
Es wurde hier nicht auf alle Datentypen geprüft, und anderweitig ist das Programm auch nicht wasserdicht. Aber dies würde den Rahmen dieses Kapitels sprengen. Hier wurden außerdem die (ANSI C-) Konstanten aus den Headerdateien <float.h> und <limits.h> verwendet, damit das Programm auch auf jedem System läuft. Egal, welche Grenzen gesetzt sind.
22.4.3 Bessere Alternative – Konvertieren von Strings in numerische Werte
 
Sicherlich ist Ihnen an der Methode (im Listing string2va1.c) mit atof() bzw. atol() aufgefallen, dass diese Funktionen recht unflexibel sind und vor allem das Manko haben, keinen Fehler bei der Eingabe feststellen zu können. Eine gerne gestellte Frage lautet nämlich, wie man auf die Richtigkeit der Eingabe eines Datentyps prüfen könne. Und genau diese »bessere« Alternative stellt Ihnen die Standard-Bibliothek mit den Funktionen strtod() und strtol() zur Verfügung. Beide Funktionen sind ebenfalls in der Headerdatei <stdlib.h> enthalten. Zuerst die Funktion strtod():
double strtod(const char *string, char **endptr);
strtod() konvertiert einen String in einen double-Wert. strtod() bricht die Analyse beim ersten Zeichen ab, das nicht mehr als Teil eines double-Werts interpretiert werden kann. Solange der Parameter endptr nicht NULL ist, wird *endptr von strtod() auf das Zeichen innerhalb von string gesetzt, durch das die Analyse abgebrochen wurde (*endptr=&abbruch_zeichen).
long strtol(const char *string, char **endptr, int basis);
strtol() konvertiert einen String in einen long-Wert. basis legt das Zahlensystem fest, in das die Zahl umgewandelt werden soll (Basis = 8 ist Oktalzahl, Basis = 16 (0–9,A-F) ist eine Hexadezimalzahl, Basis = 10 ist das Dezimalsystem). Für basis sind Werte von 2 bis 36 möglich. Für endptr können Sie den NULL-Zeiger angeben. Falls kein NULL-Zeiger angegeben wird, zeigt endptr auf den Rest des long-Werts (sollte einer übrig bleiben). Für diese Funktion gibt es auch den unsigned-Bruder mit derselben Bedeutung:
unsigned long stroul(const char *string,
char **end_ptr,int basis);
Im Falle eines Fehlers liefern all diese Funktionen 0 zurück. Wird der Wertebereich des zu konvertierenden Typs unter- bzw- überschritten (bei long sind dies LONG_MIN bzw. LONG_MAX), wird errno auf ERANGE gesetzt. Somit können Sie mit ziemlicher Sicherheit davon ausgehen, wenn der Rückgabewert der Funktionen nicht 0, der end_ptr gleich NULL und die Fehlervariable errno nicht ERANGE ist, dass die von Ihnen eingegebene Zahl richtig ist (100%-ige Garantie gibt es aber nicht).
Hier ein kurzes Beispiel, welches den gleichwertigen Fall von atol() und strtol() demonstrieren soll:
/* string2val2.c */
#include <stdio.h>
#include <stdlib.h>
int main(void) {
char string1[] = "256Vorrat";
char string2[]= "128Benoetigt";
long zahl1, zahl2;
zahl1 = atol(string1);
zahl2 = strtol(string2, NULL, 10);
printf("zahl1: %ld; zahl2: %ld\n", zahl1, zahl2);
return EXIT_SUCCESS;
}
Hierbei wird »korrekterweise« einmal die Zahl 256 und einmal 128 ausgegeben. Beide Funktionen konvertieren also bis zum ersten Zeichen, was nicht mehr zum Datentypen gehört. Was aber, wenn eine derartige Eingabe überprüft werden soll, denn eigentlich sind ja beide Strings keine »korrekten« Zahlen, sondern nur Strings, die eben Zahlen beinhalten bzw. welche mit Zahlen beginnen. Eben hier ist atol() am Ende. Mit strtol() hingegen haben Sie hierbei noch den zweiten Parameter, der Ihnen dabei helfen wird.
Daher soll hier ein Beispiel erstellt werden, welches jeweils zweimal die Eingabe eines Strings erfordert und überprüft, ob es sich dabei um einen »echten« long Wert handelt (strtol()) und noch eine Funktion hat, welche überprüft, ob sich der String korrekt in einen double-Wert konvertieren lässt (mit strtod()).
/* check_input.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#define CHARS 20
void chomp(char *str) {
size_t p=strlen(str);
/* '\n' mit '\0' überschreiben */
str[p-1]='\0';
}
void is_long(char *str) {
static long val;
char *stop_ptr = NULL;
val = strtoul(str, &stop_ptr, 10);
if(errno == ERANGE) {
printf("Werteüber- bzw. Unterlauf!!!\n");
exit(EXIT_FAILURE);
}
if(!val) {
printf("Wert konnte nicht umgewandelt werden\n");
exit(EXIT_FAILURE);
}
if(*stop_ptr != NULL) {
printf("Kein korrekter long-Wert: %s\n", str);
printf("Fehler der Umwandlung ab Pos.: %s\n", stop_ptr);
printf("Umgewandelt ---> %ld\n", val);
}
else
printf("Yeah! Korrekter long-Wert : %ld\n", val);
}
void is_double(char *str) {
static double val;
char *stop_ptr = NULL;
val = strtod(str, &stop_ptr);
if(errno == ERANGE) {
printf("Werteüber- bzw. Unterlauf!!!\n");
exit(EXIT_FAILURE);
}
if(!val) {
printf("Wert konnte nicht umgewandelt werden\n");
exit(EXIT_FAILURE);
}
if(*stop_ptr != NULL) {
printf("Kein korrekter double-Wert: %s\n", str);
printf("Fehler der Umwandlung ab Pos.: %s\n", stop_ptr);
printf("Umgewandelt ---> %lf\n", val);
}
else
printf("Yeah! Korrekter double-Wert : %lf\n", val);
}
int main(void) {
char val[CHARS];
/* Testen eines long-Wertes */
printf("Bitte geben Sie eine long-Wert ein : ");
fgets(val, CHARS, stdin);
chomp(val);
is_long(val);
/* Gleiches nochmals mit einem double-Wert */
printf("Bitte geben Sie eine double-Wert ein : ");
fgets(val, CHARS, stdin);
chomp(val);
is_double(val);
return EXIT_SUCCESS;
}
Sofern Sie jetzt hierbei auf andere Typen wie bspw. int überprüfen wollen, müssen Sie dazu die Limit-Konstanten der Headerdatei <limits.h> (bspw. INT_MIN oder INT_MAX) verwenden und mit dem long-konvertieren Wert vergleichen.
Hinweis Sofern Ihr Compiler den ISO C99-Standard versteht, finden Sie hierbei noch weitere solcher sehr nützlichen Funktionen mit strtoll() (string to long long), strtoimax() (string to int max), strtof() (string to float) und strtold (string to long double). Mehr dazu entnehmen Sie dann der Dokumentation Ihres Compilers (bspw. Manual-Page).
|
Eine häufige Frage lautet: Wo ist itoa(), oder wie kann ich einen Integerwert in einen String konvertieren? itoa() ist keine ANSI C-Standardfunktion und daher hängt es vom Compiler ab, ob diese Funktion vorhanden ist oder nicht. Sollten Sie aber portabel bleiben müssen, macht diese Funktion ohnehin keinen Sinn. Also, basteln Sie sich diese Funktion selbst zusammen:
/* my_itoa.c */
#include <stdio.h>
#include <stdlib.h>
char *my_itoa(int wert, int laenge) {
char *ret =(char *) malloc(laenge+1 * sizeof(char));
int i;
for(i =0; i < laenge; i++) {
ret[laenge-i-1] = (wert % 10) + 48;
wert = wert / 10;
}
ret[laenge]='\0';
return ret;
}
int main(void) {
printf("%s\n", my_itoa(1234,4));
printf("%s\n", my_itoa(5432,6));
return EXIT_SUCCESS;
}
Falls für die Länge zu viele Zahlen angegeben wurden, werden diese mit voranstehenden Nullen gefüllt.
22.4.4 Zufallszahlen
 
Die Funktion
int rand(void);
liefert eine Pseudo-Zufallszahl im Bereich 0 bis RAND_MAX zurück. Beispielsweise mit:
/* zufall1.c */
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int zufallszahl, i;
for(i = 0; i < 5; i++)
printf("Die Zufallszahl lautet %d\n", zufallszahl=rand());
return EXIT_SUCCESS;
}
Bei Ausführung des Listings werden fünf verschiedene Zufallszahlen zwischen 0 und RAND_MAX ausgegeben. Aber spätestens, wenn das Programm jetzt ein zweites Mal gestartet wird, merken Sie, dass sich diese Zufallszahlen immer wiederholen. Das Problem an der Funktion rand() ist, dass diese immer denselben Startpunkt zur Berechnung der Zufallszahl benutzt. Anders dagegen die Funktion
void srand(unsigned int startwert);
Hiermit kann der Startpunkt für die Zufallszahl selbst bestimmt werden. Ein Beispiel:
/* zufall2.c */
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int zufallszahl, i, startpunkt;
printf("Geben Sie irgendeine Zahl ein : ");
scanf("%d",&startpunkt);
srand(startpunkt);
for(i = 0; i < 5; i++)
printf("Die Zufallszahl lautet %d\n", zufallszahl=rand());
return EXIT_SUCCESS;
}
Jetzt wollen Sie aber sicher nicht andauernd einen Startwert für den Zufallsgenerator eingeben. Zum einen ist dies umständlich, und zum anderen bekommen Sie wieder dieselbe Zahl zurück, sollte zweimal der gleiche Wert eingegeben werden. Was eignet sich also besser als die Funktion time() für den Startwert. Und wie gehen Sie vor, falls eine Zufallszahl im Bereich zwischen 1 und 10 benötigt wird? Hier eignet sich der Modulo-Operator bestens. Ein entsprechendes Beispiel:
/* zufall3.c */
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(void) {
int zufallszahl, i;
srand(time(NULL));
for(i = 0; i < 5; i++)
printf("Zufallszahl lautet %d\n", zufallszahl=rand()%10+1);
return EXIT_SUCCESS;
}
Jetzt erhalten Sie schon etwas bessere Zufallszahlen im Bereich zwischen 1–10.
22.4.5 Absolutwerte, Quotient und Rest von Divisionen
 
Um Absolutwerte von Ganzzahlen zu ermitteln, können zwei Funktionen verwendet werden:
long int labs(long int zahl);
int abs(int zahl);
So erhalten Sie den Absolutwert zum ganzzahligen Argument zahl. Das Beispiel:
/* absolut.c */
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int zahl = 5;
printf("%d\n", abs(zahl-20));
return EXIT_SUCCESS;
}
Wird der Quotient und der Rest einer Division benötigt, können folgende Funktionen verwendet werden:
div_t div(int zaehler, int nenner);
ldiv_t ldiv(long int zaehler, long int nenner);
div_t und ldiv_t sind Strukturtypen mit folgendem Inhalt:
typedef struct{
int quot; /* quotient */
int rem; /* remainder */
} div_t;
... bzw. ...
typedef struct{
long int quot; /* quotient */
long int rem; /* remainder */
} ldiv_t;
Damit berechnen Sie zaehler/nenner. Der Rest des Werts steht in rem, falls die Rechnung ungenau ist, und der Quotient befindet sich in quot. Ein Beispiel:
/* division.c */
#include <stdio.h>
#include <stdlib.h>
int main(void) {
div_t x = div(10,3);
printf("10 div 3 = %d Rest %d\n", x.quot, x.rem);
return EXIT_SUCCESS;
}
Diese Funktion macht im Prinzip nichts anderes, als Folgendes zu berechnen:
quot = zaehler / nenner;
rem = zaehler % nenner;
22.4.6 Suchen und Sortieren – qsort() und bsearch()
 
Mit der Funktion qsort() kann ein Array der Wahl nach beliebigen Kriterien sortiert werden. Die qsort()-Funktion basiert auf dem Quicksort-Algorithmus von C.A.R. Hoare. Die Syntax von qsort(), ausführlich dokumentiert:
void qsort(
void *array, // Anfangsadresse des Vektors
size_t n, // Anzahl der Elemente zum Sortieren
size_t size, // Größe des Datentyps, der sortiert wird
// Jetzt folgt die Vergleichsfunktion
int (*vergleich_func)(const void*, const void*) );
Die Bedeutungen der einzelnen Parameter dürften klar sein – bis auf die Vergleichsfunktion. Diese müssen Sie selbst implementieren. Hierzu ein einfaches Beispiel mit der Funktion qsort():
/* qsort.c */
#include <stdio.h>
#include <stdlib.h>
/* Vergleichsfunktion */
int cmp(const void *ptr1, const void *ptr2) {
if( *(int *)ptr1 < *(int *)ptr2 )
return –1;
else if( *(int *)ptr1 > *(int *)ptr2 )
return 1;
else
return 0; /* Beide Elemente sind gleich */
}
int main(void) {
int wert[] = { 2, 5, 2, 7, 6, 4, 2 };
int i;
printf("Daten vor dem Sortieren\n");
for(i = 0; i < sizeof(wert)/sizeof(int); i++)
printf("%d\t", wert[i]);
printf("\n");
/* Jetzt sortieren mit qsort() */
qsort(wert, sizeof(wert)/sizeof(int), sizeof(int), cmp);
printf("Daten nach dem Sortieren mit qsort()\n");
for(i = 0; i < sizeof(wert)/sizeof(int); i++)
printf("%d\t", wert[i]);
printf("\n");
return EXIT_SUCCESS;
}
Das Listing sortiert das unsortierte Integer-Feld wert, die Ausgabe des Programms bestätigt dies.
Wollen Sie ein Element wieder in Ihrem sortierten Vektor finden, dann können Sie die Funktion bsearch() verwenden. bsearch steht für »binäre Suche« und sucht die Elemente, indem die Suche mit dem mittleren Bereich eines Arrays begonnen wird, und fährt je nach Resultat mit der Suche auf der linken oder rechten Hälfte fort. Genaueres dazu erfahren Sie in Kapitel 24, Algorithmen. Wird ein entsprechendes Element gefunden, liefert diese Funktion die Adresse zurück. Wird kein entsprechendes Element gefunden, dann wird der NULL-Zeiger zurückgegeben. Hier die Syntax:
void *bsearch(
const void *key, // gesuchte Elemente
const void *array, // Anfangsadresse der Tabelle zum Suchen
size_t n, // Anzahl der Elemente
size_t size, // Elementgröße
// Jetzt folgt die Vergleichsfunktion
int (*vergleich_func)(const void*, const void*) );
Die Syntax ist also der Funktion qsort() recht ähnlich. Zur Abwechslung soll aber hier nach einem String in einer Stringtabelle gesucht werden, welche Sie zuvor noch mit qsort() sortieren.
/* bsearch.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* Anzahl der Strings */
#define MAX 5
/* Vergleichsfunktion für zwei Strings */
int cmp_str(const void *s1, const void *s2) {
return (strcmp(*(char **)s1, *(char **)s2));
}
int main(void) {
char *daten[MAX], puffer[80], *ptr, *key_ptr, **key_ptrptr;
int count;
/* Wörter eingeben */
printf("Geben Sie %d Wörter ein\n", MAX);
for (count = 0; count < MAX; count++) {
printf("Wort %d: ", count+1);
fgets(puffer, 80, stdin);
/* Speicher für das Wort Numer count reservieren */
daten[count] = (char *) malloc(strlen(puffer)+1);
strcpy(daten[count], strtok(puffer,"\n") );
}
/* Die einzelnen Wörter sortieren */
qsort(daten, MAX, sizeof(daten[0]), cmp_str);
/* Sortierte Daten ausgeben */
for (count = 0; count < MAX; count++)
printf("\nWort %d: %s", count+1, daten[count]);
/* Jetzt nach einem Wort suchen */
printf("\n\nNach welchem Wort wollen Sie suchen: ");
fgets(puffer, 80, stdin);
/* Zur Suche übergeben Sie zuerst den puffer an key,
* danach benötigen Sie einen weiteren Zeiger, der
* auf diesen Such-Schlüssel zeigt
*/
key_ptr = strtok(puffer, "\n");
key_ptrptr = &key_ptr;
/* Der Zeiger ptr bekommt die Adresse des Suchergebnisses */
ptr =(char *) bsearch(key_ptrptr, daten, MAX,
sizeof(daten[0]), cmp_str);
if(NULL == ptr)
printf("Kein Ergebnis stimmt mit %s überein\n", puffer);
else
printf("%s wurde gefunden\n", puffer);
return EXIT_SUCCESS;
}
 22.4.7 system()
 
Um aus einem lauffähigen Programm ein anderes Programm zu starten, steht Ihnen die Funktion system() zur Verfügung. Die Syntax:
#include <stdlib.h>
int system(const char *kommandozeile);
Beim Ausführen der Funktion system() übergeben Sie den String kommandozeile an den Kommandozeilenprozessor. Konnte der Aufruf erfolgreich ausgeführt werden, gibt die Funktion einen Wert ungleich 0 zurück, ansonsten –1. Für den String kommandozeile können Sie alles angeben, was auch in der Kommandozeile erlaubt ist.
Um zu testen, ob auf Ihrem System der Kommandozeilenprozessor überhaupt zur Verfügung steht, müssen Sie die Funktion system() mit dem NULL-Zeiger aufrufen:
if(system(NULL) == 0) {
// Kommandoprozessor steht nicht zur Verfügung
}
else {
// Kommandozeilenprozessor ist bereit
}
Wird dabei ein Wert ungleich Null zurückgegeben, können Sie die Funktion system() ohne Bedenken verwenden.
Hinweis Wenn Sie sich mit der Linux-Systemprogrammierung ein wenig auskennen, dürfte Ihnen das Verhalten der Funktion system() bekannt vorkommen. Mit der Funktion system() werden fork(), exec() und waitpid() praktisch auf einmal aufgerufen.
|
Zum Abschluss ein einfaches Beispiel zur Funktion system(). Auf jedem System gibt es einen Kommandozeilenbefehl, mit dem sich das vollständige Verzeichnis auflisten lässt. Unter Linux/UNIX ist dies ls und unter Windows/MS-DOS das Kommando dir. Im folgenden Listing soll dieses Kommando auf dem jeweiligen System mithilfe der Funktion system() ausgeführt werden. Hier das Listing:
/* list_dir.c */
#include <stdio.h>
#include <stdlib.h>
#ifdef __unix__
#define KOMMANDO system("ls -C")
#else
#define KOMMANDO system("dir /w")
#endif
int main(void) {
if( system(NULL) == 0) {
fprintf(stderr,"Kein Kommandoprozessor vorhanden ...\n");
return EXIT_FAILURE;
}
else
KOMMANDO;
return EXIT_SUCCESS;
}
Achtung Vermeiden Sie den system()-Funktionsaufruf, mit dem sich der Anwender einen eigenen String zusammenbasteln kann. Böse Anwender könnten dabei so manchen gefährlichen Konsolenbefehl ausführen lassen.
|
Nicht besprochen in diesem Abschnitt wurde die Funktion der Headerdatei <stdlib.h>, mit der Sie Vielbyte-Zeichen bearbeiten können, da diese recht selten benötigt wird.
Die Funktion getenv(), mit der Sie Umgebungsvariablen auslesen können, wird in Kapitel 26, CGI mit C, besprochen.
|