FAQ:Bibliotheksfunktionen

[ FAQ in de.comp.lang.c ]


Diese FAQ bezieht sich in ihrer Gänze auf den inzwischen nicht mehr aktuellen ISO-C Standard 9899:1990, vielfach auch als C90 bezeichnet. Der seit Dezember 1999 existierende neue ISO 9899:1999 Standard (oder auch C99) wird nicht berücksichtigt.


[ Inhalt ][ Index ][ ZurÜck ][ Weiter ]


Frage 12.1: Warum setzt strncpy nicht immer ein '\0' an das Ende des Ziel-Strings?

Antwort: strncpy wurde ursprünglich entwickelt, um eine inzwischen veraltete Datenstruktur, nämlich einen String mit fester Länge, der nicht unbedingt mit '\0' abgeschlossen sein muß, zu verarbeiten. strncpy ist zugestandenermaßen ein bißchen schwierig in anderen Zusammenhängen zu benutzen, weil man oft ein '\0' per Hand an den Zielstring anhängen muß.


Frage 12.2: Ich versuche, ein Feld von Strings unter Verwendung von strcmp als Vergleichsfunktion mit qsort zu sortieren, aber es funktioniert nicht.

Antwort: Mit einem "Feld von Strings" ist vermutlich ein "Feld von Zeigern auf char" gemeint. Die Argumente für die Vergleichsfunktion von qsort sind Zeiger auf die Objekte, die sortiert werden sollen, in diesem Fall Zeiger auf Zeiger, die auf char zeigen. (strcmp akzeptiert allerdings nur einfache Zeiger auf char.)

Die Argumente der Vergleichsfunktion werden als "generische Zeiger" bezeichnet, const void * oder char *. Sie müssen wieder in das konvertiert werden, was sie "wirklich sind" (char **) und dereferenziert, damit sie char * liefern, die sinnvoll verglichen werden können. Man könnte eine Vergleichsfunktion folgendermaßen schreiben:

	    int pstrcmp(p1, p2) /* vergleicht Strings mittels Zeigern */
	    char *p1, *p2;      /* const void * für ANSI C */
	    {
	return strcmp(*(char **)p1, *(char **)p2);
	    }

Man beachte bei der Diskussion in K&R II Abschn. 5.11 S. 119-20, dass dort nicht die Standard Bibliothek qsort diskutiert wird.


Frage 12.3: Jetzt versuche ich ein Feld von Strukturen mit qsort zu sortieren. Meine Vergleichsfunktion nimmt Zeiger auf Strukturen, aber der Compiler beschwert sich, dass die Funktion vom falschen Typ für qsort ist. Wie kann ich den Funktionszeiger umwandeln, um diese Warnung abzuschalten?

Antwort: Die Umwandlung muß in der Vergleichsfunktion stattfinden, welche so deklariert sein muß, dass sie "generische Zeiger" (const void * oder char *) akzeptiert, wie oben bei Frage 12.2 diskutiert. Der Code könnte folgendermaßen aussehen:

	    int mystructcmp(p1, p2)
	    char *p1, *p2;          /* const void * für ANSI C */
	    {
	struct mystruct *sp1 = (struct mystruct *)p1;
	struct mystruct *sp2 = (struct mystruct *)p2;
	/* jetzt vergleiche sp1->whatever und sp2-> ... */
	    }

(Wenn man andererseits Zeiger auf Strukturen sortiert, dann benötigt man einen Umweg, wie bei Frage 12.2: sp1 = *(struct mystruct **)p1 .)


Frage 12.4: Wie kann ich Zahlen in Strings umwandeln (das Gegenteil zu atoi)? Gibt es eine itoa Funktion?

Antwort: Man kann dafür einfach sprintf benutzen. (Man muß irgendwo den Platz für das Ergebnis reservieren, siehe Fragen 3.1 und 3.2. Keine Sorge, dass sprintf Overkill wäre und möglicherweise Laufzeit oder Speicherplatz verschwendet. Es funktioniert in der Praxis recht gut.)

Referenzen: K&R I Abschn. 3.6 S. 60; K&R II Abschn. 3.6 S. 64.


Frage 12.5: Wie kann ich das aktuelle Datum oder die Tageszeit in einem C Programm ermitteln?

Antwort: Man benutze einfach die Funktionen time, ctime, und/oder localtime. (Diese Funktionen gibt es bereits seit Jahren und sie gehören zum ANSI Standard.) Hier ist ein einfaches Beispiel:

	#include <stdio.h>
	#include <time.h>

	main()
	{
		time_t now = time((time_t *)NULL);
		printf("It's %.24s.\n", ctime(&now));
		return 0;
	}

Referenzen: ANSI Abschn. 4.12 .


Frage 12.6: Ich weiß, dass die Bibliotheksfunktion localtime ein time_t in eine Struktur tm aufteilt, und dass ctime ein time_t in einen druckbaren String umwandelt. Wie kann ich die entgegengesetzte Operation, d.h. die Umwandlung einer Struktur tm oder eines Strings in ein time_t, realisieren?

Antwort: ANSI C spezifiziert eine Bibliotheksfunktion, mktime, die eine Struktur tm in ein time_t umwandelt. Verschiedene Public Domain Versionen dieser Funktion sind verfügbar, falls ein Compiler das noch nicht unterstützen sollte.

Die Umwandlung eines Strings in ein time_t ist schwieriger, wegen der großen Vielfältigkeit von Datums- und Zeitformaten, die dabei berücksichtigt werden sollte. Manche Systeme stellen eine Funktion strptime zur Verfügung; eine andere beliebte Funktion ist partime (weit verbreitet mit dem RCS Paket), aber diese werden wahrscheinlich nicht standardisiert werden.

Referenzen: K&R II Abschn. B10 S. 256; H&S Abschn. 20.4 S. 361; ANSI Abschn. 4.12.2.3 .


Frage 12.7: Wie kann ich n Tage zu einem Datum addieren? Wie kann ich die Differenz zwischen zwei Daten bestimmen?

Antwort: Die ANSI/ISO Standard C Funktionen mktime und difftime liefern eine gewisse Hilfe für beide Probleme. mktime() akzeptiert nicht-normalisierte Daten, so dass es einfach ist, eine gefüllte Struktur tm zu nehmen, etwas zu dem Element tm_mday zu addieren bzw. davon zu subtrahieren und anschließend mktime() aufzurufen um Jahr, Monat und Tag wieder zu normalisieren (und in einen time_t Wert umzuwandeln). difftime() berechnet die Differenz in Sekunden zwischen zwei time_t Werten; mktime() kann benutzt werden, um die time_t Werte für zwei zu subtrahierende Daten zu ermitteln. (Man beachte jedoch, dass diese Lösungen nur für Daten funktionieren, die in dem Bereich liegen, der mit time_t Werten dargestellt werden kann, und dass nicht alle Tage 86400 Sekunden lang sind.) Siehe auch Frage 12.6 und 17.28.

Referenzen: K&R II Abschn. B10 S. 256; H&S Abschn. 20.4, 20.5 S. 361-362; ANSI Abschn. 4.12.2.2, 4.12.2.3 .


Frage 12.8: Ich brauche einen Zufallszahlengenerator.

Antwort: Die Standard C Bibliothek hat einen: rand(). Die Implementation ist nicht auf jedem System perfekt, aber einen besseren zu schreiben ist nicht unbedingt einfach.

Referenzen: ANSI Abschn. 4.10.2.1 S. 154; Knuth Band 2 Kap. 3 S. 1-177.


Frage 12.9: Wie kann ich zufällige ganze Zahlen in einem bestimmten Bereich erzeugen?

Antwort: Der übliche Weg,

	rand() % N

(wobei N natürlich der Bereich ist) ist dürftig, weil die unteren Bits von vielen Zufallszahlengeneratoren genau genommen nicht zufällig sind. (Siehe Frage 12.11.) Eine bessere Methode ist folgende

	(int)((double)rand() / ((double)RAND_MAX + 1) * N)

Wenn man Bedenken wegen der Benutzung von Gleitkommazahlen hat, dann kann man folgendes versuchen

	rand() / (RAND_MAX / N + 1)

Beide Methoden erfordern unverkennbar die Kenntnis von RAND_MAX (was ANSI in <stdlib.h> definiert) und setzen voraus, dass N viel kleiner ist als RAND_MAX.


Frage 12.10: Jedes mal, wenn ich mein Programm starte, bekomme ich die gleiche Zahlenfolge von rand() geliefert.

Antwort: Man kann srand() aufrufen, um den Pseudo-Zufallszahlengenerator mit einem zufälligeren Startwert zu initialisieren. Beliebte Startwerte sind die Tageszeit, oder die Zeit, die vergangen ist, bevor der Benutzer eine Taste betätigt hat (allerdings ist der Zeitpunkt einer Tastenbetätigung kaum portabel zu bestimmen; siehe Frage 16.10).

Referenzen: ANSI Abschn. 4.10.2.2 S. 154.


Frage 12.11: Ich brauche einen zufälligen wahr/falsch Wert. Deshalb habe ich rand() % 2 benutzt, erhalte aber nur abwechselnd 0, 1, 0, 1, 0...

Antwort: Einfache Pseudo-Zufallszahlengeneratoren (wie die, die unglücklicherweise mit manchen Systemen geliefert werden) sind in den unteren Bits nicht sehr zufällig. Man sollte versuchen, die oberen Bits zu benutzen. Siehe Frage 12.9.


Frage 12.12: Ich versuche ein altes Programm zu portieren. Warum bekomme ich "undefined external" Fehlermeldungen für index(), rindex(), bcopy(), bcmp() und bzero()?

Antwort: Diese Funktionen sind unterschiedlich veraltet. Stattdessen sollten folgende Funktionen benutzt werden:

	index()  :                   strchr()
	rindex() :                   strrchr()
	bcmp()   :                   memcmp()
	bzero()  :                   memset() mit zweitem Argument 0

Statt bcopy() wird memmove() nach dem Vertauschen des ersten und zweiten Arguments benutzt (siehe auch Frage 5.15).


Frage 12.13: Ich bekomme ständig Fehlermeldungen wegen undefinierter Bibliotheksfunktionen, obwohl ich alle Headerfiles richtig eingebunden habe.

Antwort: In manchen Fällen (insbesondere, wenn es sich um nicht standardisierte Funktionen handelt) muß man explizit die richtigen Bibliotheken angeben, die beim Linken des Programms durchsucht werden sollen. Siehe auch Frage 15.2.


Frage 12.14: Ich bekomme immer Errors wegen undefinierter Bibliotheks-Funktionen, obwohl ich -l zur Anforderung der Bibliotheken während des Linkens benutze.

Antwort: Viele Linker führen nur einen Lauf über die Liste der angegebenen Objektdateien und Bibliotheken aus und extrahieren aus den Bibliotheken nur die Module, die den Referenzen entsprechen, die bis dahin undefiniert waren. Deshalb ist die Reihenfolge, in der die Bibliotheken aufgelistet werden hinsichtlich der Objektdateien (und auch untereinander) wichtig; üblicherweise läßt man die Bibliotheken zuletzt durchsuchen. (z.B. unter UNIX gibt man die -l Schalter am Ende der Kommandozeile an.)


Frage 12.15: Ich brauche Quellcode zur Auswertung regulärer Ausdrücke.

Antwort: Man sollte sich die regexp Bibliothek (wird mit vielen UNIX Systemen geliefert) ansehen, oder sich Henry Spencer's regexp Paket von cs.toronto.edu in pub/regexp.shar.Z beschaffen (siehe auch Frage 17.12).


Frage 12.16: Wie kann ich die Kommandozeile in durch Whitespaces getrennte Argumente aufteilen, wie die Parameter argc und argv von main()?

Antwort: Die meisten Systeme haben eine Funktion namens strtok, allerdings kann es schwer zu benutzen sein und es kann sein, dass es nicht das tut, was man gern hätte (z.B. Quoting).

Referenzen: ANSI Abschn. 4.11.5.8; K&R II Abschn. B3 S. 250; H&S Abschn. 15.7; PCS S. 178.

[ Inhalt ][ Index ][ ZurÜck ][ Weiter ]


[ FAQ Logo ]   © 1997-2004 Jochen Schoof (joscho@bigfoot.de)
Diese Version wurde am 14. März 2004 erzeugt. Sie wird zukünftig nicht weiter gepflegt.