Die Programmargumente in argv
sind stets Strings, oftmals möchte man diese aber als numerische Werte betrachten. Im Folgenden wollen wir uns deshalb mit Funktionen beschäftigen, die eine entsprechende Konvertierung verlässlich ermöglichen.
Warum ist die Verwendung der Funktionen atol
/atoi
/atof
zu diesem Zweck problematich? Ziehen Sie auch die Man-Pages heran.
Bei diesen Funktionen ist es nicht möglich, Fehler (z.B. invalide Zeichen) zu erkennen — im Fehlerfall geben diese Funktionen 0
zurück, was auch eine korrekte Eingabe sein kann.
Betrachten Sie nun die Funktionen strtol
/strtoul
/strtod
, welche die Parameter const char* nptr
und char** endptr
entgegen nehmen. Welche Bedeutung haben diese?
nptr
ist der String, der konvertiert werden soll.
endptr
ist ein Ausgabeparameter. An das Ziel des Pointers wird ein Pointer auf den ersten char
in nptr
gesetzt, der nicht konvertiert werden konnte. (Wenn endptr == NULL
, wird nichts geschrieben.)
Beispiel:
const char* str = "123x9";
char* endptr; // uninitialized, value set by strtol
long res = strtol(str, &endptr, /*base=*/10);
// result of conversion until first invalid character
assert(res == 123);
// endptr points to the first invalid character, 'x'.
assert(endptr == str + 3);
Überlegen Sie sich, wie Sie folgende Fehlerfälle erkennen können:
Der String enthält für eine Zahl ungültige Zeichen.
Wenn endptr
nicht auf das \0
-Terminal zeigt oder auf den Anfang des Strings (der String könnte gar keine Zahl enthalten), war die Konvertierung nicht gänzlich erfolgreich.
Die im String enthaltene Zahl passt nicht in den Wertebereich des Ziel-Datentyps.
In diesem Fall wird errno
auf ERANGE
gesetzt. Da errno
im Erfolgsfall nicht gesetzt wird, muss vor der Konvertierung errno = 0
gesetzt werden.
Passen Sie folgendes C-Programm so an, dass die Paramter in argv
der Form <double>,<double>
mittels strtod
in zwei double
-Werte aufgeteilt wird. Nutzen Sie endptr
, um den Beginn des zweiten Wertes zu finden. Falls ein Parameter fehlerhaft ist, soll error
ausgegeben werden und mit dem nächsten Argument fortgefahren werden.
#include <math.h>
#include <stdio.h>
int main(int argc, char** argv) {
for (int i = 1; i < argc; i++) {
double x = 0, y = 0; // TODO: parse from argv[i]
printf("%f\n", pow(x, y));
}
return 0;
}
Beispielaufruf:
$ ./strtonum 2,4 2,2e10 1x5,4 3, 2 "3, 4" .5,1e400 0x1.8p4,2
16.000000
inf
error
error
error
81.000000
error
576.000000
#include <errno.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char** argv) {
for (int i = 1; i < argc; i++) {
char *endx, *endy;
errno = 0;
double x = strtod(argv[i], &endx);
if (endx == argv[i] || *endx != ',' || errno == ERANGE) {
error:
puts("error");
continue;
}
double y = strtod(endx + 1, &endy);
if (endy == endx + 1 || *endy != '\0' || errno == ERANGE)
goto error;
printf("%f\n", pow(x, y));
}
return 0;
}