Hallo,
ich würde gerne Strings überprüfen, ob sie eine Zahl sind.
So ein String kann z.B. so aussehen: "234.331"
Ich habe folgende Funktion geschrieben:
1
uint8_tis_number(char*string){
2
3
uint8_ti=0;
4
5
while(i<sizeof(string)){
6
7
if(!isdigit(string[i])){
8
9
if(string[i]=='.'){break;}
10
if(string[i]=='\0'){return1;}
11
12
return0;//String ist keine Zahl
13
}
14
15
i++;
16
17
}
18
19
return1;
20
}
Was haltet ihr davon? Gibt es eine geschicktere Möglichkeit dies
umzusetzen?
Gruß Mike
Mike schrieb:> Was haltet ihr davon?
Nicht viel.
Voller Fehler.
> Gibt es eine geschicktere Möglichkeit dies> umzusetzen?
Machs erst mal richtig, ehe du dich um Eleganz und Geschwindigkeit
sorgst.
>uint8_t is_number( char* string){> while(i < sizeof(string) ){
Woher soll sizeof hier wissen wie groß der String ist?
sizeof vom Pointer wird 2 oder sowas sein.
strlen ist da wohl die bessere Wahl.
die Funktion strchr durchsucht einen String nach dem Vorkommen von einem
Zeichen und gibt einen Zeiger auf das Zeichen zurück, andernfalls 0.
Du könntest also schreiben:
if strchr(string,'.')
{
/* String enthält punkt*/
}
else
{
/* String enthält keinen punkt*/
}
mfg Ingo
In einer Funktion bearbeitet man Strings am Besten, indem man direkt den
Pointer hochzählt und so von einem Zeichen zum nächsten kommt. Dies
macht man solange, bis man auf das String-abschliessende '\0' Zeichen
stösst. Die Sichtweise über Arrays und einem demenstprechenden Index ist
zwar naheliegend, verkompliziert die Dinge aber oft nur. Abgesehen davon
ist es ineffizient, weil man vorher die Stringlänge feststellen muss und
das geht in der Funktion nur über strlen. strlen muss aber selbst das
Array durchgehen und die Zeichen bis zum \0 character zählen, d.h. man
hat 2 Durchläufe durch den String: Einmal um die Länge festzustellen und
das 2te mal um dann die tatsächliche Arbeit zu machen.
1
uint8_tis_number(constchar*string)
2
{
3
if(*string=='+'||*string=='-')
4
string++;
5
6
while(*string&&(isdigit(*string)||*string=='.'))
7
string++;
8
9
return*string=='\0';
10
}
Der Code berücksichtigt nicht, dass es nur einen Dezimalpunkt in einer
Zahl geben darf.
> if( string[i] == '.' ){ break;}
Da würde ich
if( string[i] == '.' ){ continue;}
machen. Das i++ ist dann aber an der falschen Stelle
bzw die dauernde Abfrage auf string[i] falsch;)
string[i] temporär in Variable, dann wirds einfacher.
Danke für die Tipps.
@Karl heinz Buchegger:
Deinen Code verstehe ich nicht ganz
[c]
if( *string == '+' || *string == '-' )
string++;
[\c]
OK. Wenn das erste Zeichen ein Vorzeichen ist, geht es weiter.
[c]
while( *string && ( isdigit( *string ) || *string == '.' ) )
string++;
[\c]
Solange das Zeichen eine Zahl oder ein Punkt ist, geht es weiter.
Nun verstehe ich aber den Return-Wert nicht.
Was bekomme ich den zurück wenn es eine Zahl ist bzw. wenn es keine Zahl
ist?
Mike schrieb:> Solange das Zeichen eine Zahl oder ein Punkt ist, geht es weiter.>> Nun verstehe ich aber den Return-Wert nicht.
Die Idee des Codes ist Folgende:
Solange den Pointer hochzählen, solange Zeichen vorgefunden werden, die
eine Zahl bilden können.
Aus der while Schleife fällt man daher in 2 Fällen raus
* wenn das Ende des Strings vorgefunden wurden
* wenn ein Zeichen vorgefunden wurde, welches nicht zu einer Zahl
gehören kann.
Kommt der Code daher aus der while Schleife raus, stellt sich nur die
Frage: Sind wir am Ende des Strings? Wenn ja, dann waren im String nur
Zeichen, die eine Zahl bilden können. Ansonsten wäre die while Schleife
ja schon vorher beendet worden und strign zeigt nicht auf das
String-Ende, sondern auf dieses nicht dazugehörende Zeichen.
Und genau das wird hier geprüft
1
return*string=='\0';
zurückgegeben wird das Ergebnis des Vergleichs, ob string auf das
string-abschliessende '\0' Zeichen zeigt.
Genau genommen ist das hier
1
while(*string&&(isdigit(*string)||*string=='.'))
ein wenig doppelt gemoppelt
1
while(isdigit(*string)||*string=='.')
würde es auch tun, denn '\0' ist weder ein Digit, noch ist es '.' und
führt daher ebenfalls von ganz von alleine zum Abbruch der Schleife.
> So ein String kann z.B. so aussehen: "234.331"
Auch so 99999999999999999999999.88888888888888888 ?
Werd dir also erst mal klar, was du willst.
double-Zahlen ?
In irgendwas musst du die Ziffernfolge doch wandeln.
Und genau das definiert, was als Ziffernfolge akzeptiert wird.
Wenn du Nachkommastellen willst, also ein double.
char *end;
double x;
x=strtod(string,&end)
if(*string!='\0'&&*end=='\0') dann war es eine Zahl und nicht mehr als
eine Zahl und x ist ihr Wert.
Billige Lösung : wenn alle Zeichen im Bereich 48-57 (ASCII dezimal)
liegen, ist es eine Zahl (Ganzzahl ohne Vorzeichen).
Vorteil : braucht keine fette String Library.
Ohforf Sake schrieb:> Billige Lösung : wenn alle Zeichen im Bereich 48-57 (ASCII dezimal)> liegen,
Oder - ohne ASCII-Abhängigkeit, dafür mit besserer Lesbarkeit - im
Bereich '0' bis '9'.
> ist es eine Zahl (Ganzzahl ohne Vorzeichen).>> Vorteil : braucht keine fette String Library.
Hast du dir mal angeschaut, was die Funktion isdigit macht und wie
"fett" die tatsächlich ist?
Rolf Magnus schrieb:> Oder - ohne ASCII-Abhängigkeit, dafür mit besserer Lesbarkeit - im> Bereich '0' bis '9'.
Und wer garantiert dir, dass die Ziffer-Zeichen in dem verwendeten
Zeichensatz direkt aufeinanderfolgend, ohne Lücken (bzw. anderen
Zeichen) dazwischen, und mit '0' an niedrigster und '9' an höchster
Stelle sind?
Zugegeben, in der Praxis ist das selbst bei EBCDIC der Fall, aber
schon mit dem vordergründig ähnlichen "im Bereich 'a' bis 'z' ->
Kleinbuchstabe" fällst du bei EBCDIC auf die Nase...
Andreas
Andreas Ferber schrieb:> Und wer garantiert dir, dass die Ziffer-Zeichen in dem verwendeten> Zeichensatz direkt aufeinanderfolgend, ohne Lücken (bzw. anderen> Zeichen) dazwischen, und mit '0' an niedrigster und '9' an höchster> Stelle sind?
ISO-9899.
Rolf Magnus schrieb:> ISO-9899.
OK, überzeugt. Die Passage war mir wohl bisher durch die Lappen
gegangen.
Dennoch der Vollständigkeit halber: es gibt (bzw. gab) durchaus auch
Zeichenkodierungen, bei denen die Ziffern nicht aufeinanderfolgend
sind. Diverse Beispiele gibt es hier:
http://www.science.uva.nl/museum/DWcodes.html
Auf einem (hypothetischen) Computersystem mit einer solchen Kodierung
dürfte eine standardkonforme C-Implementierung dann allerdings einige
Verrenkungen vor allem im IO-Bereich mit sich bringen.
Andreas
PS: nicht so hypothetisch: http://en.wikipedia.org/wiki/IBM_7030_Stretch
Andreas Ferber schrieb:> Auf einem (hypothetischen) Computersystem mit einer solchen Kodierung> dürfte eine standardkonforme C-Implementierung dann allerdings einige> Verrenkungen vor allem im IO-Bereich mit sich bringen.
Dafür gibt es ja dann die Unterscheidung zwischen Text- und Binary-Modus
in Streams. Da muß man halt beim Lesen und Schreiben umkodieren, so wie
es unter Windows auch schon mit den Zeilenenden gemacht wird. So groß
wären diese Verrenkungen also eigentlich gar nicht.
Rolf Magnus schrieb:> Andreas Ferber schrieb:>> Auf einem (hypothetischen) Computersystem mit einer solchen Kodierung>> dürfte eine standardkonforme C-Implementierung dann allerdings einige>> Verrenkungen vor allem im IO-Bereich mit sich bringen.>> Dafür gibt es ja dann die Unterscheidung zwischen Text- und Binary-Modus> in Streams. Da muß man halt beim Lesen und Schreiben umkodieren, so wie> es unter Windows auch schon mit den Zeilenenden gemacht wird. So groß> wären diese Verrenkungen also eigentlich gar nicht.
Na ja, schon.
Das geht ja auch noch weiter.
Die Zusicherung im Standard enthält ja zb auch, dass
'0' < '1'
true ergeben muss. Mit einer wilden Codetabelle könnte das alles dann
ausarten :-)
Jörg Wunsch schrieb:> Insbesondere hat er sich die Aufgabenstellung ganz offensichtlich> nicht angeschaut. Vermutlich nur die Überschrift gelesen...
Stimmt nicht. Die Sache mit dem".", der ja auch erlaubt ist, hab ich
weggelassen, weils zu einfach ist.
Wenn man die Sache etwas weniger präzise lösen will, könnte man den
ganzen Bereich von "." bis "9" als Ziffer betrachten - wenn der "/"
nicht stört.
Rolf Magnus schrieb:> Dafür gibt es ja dann die Unterscheidung zwischen Text- und Binary-Modus> in Streams. Da muß man halt beim Lesen und Schreiben umkodieren, so wie> es unter Windows auch schon mit den Zeilenenden gemacht wird. So groß> wären diese Verrenkungen also eigentlich gar nicht.
Jein. Streng gesehen dürfte das passen. Aber nimm z.B. Dateinamen. Die
Regeln für selbige sind implementation defined, von daher könnte man
Ziffern hier einfach verbieten, es dürften aber die meisten Anwender
erstmal davon ausgehen, dass Ziffern in Dateinamen erlaubt sind, und
dass diese dann auch in anderen, nicht in C geschriebenen, Programmen
als Ziffern auftauchen. Auch die Portabilität von vielen Programmen
dürfte auf eine harte Probe gestellt werden, wenn man Ziffern im
Dateinamen verbieten würde.
Deshalb müsste in der Praxis z.B. auch bei fopen() umkodiert werden, was
man sich bei \n eher schenken kann, da in letzterem Fall nach meiner
Erfahrung die meisten Leute eher überrascht sind, dass Newlines im
Dateinamen auf manchen Systemen überhaupt erlaubt sind, respektive
Newlines eben sowieso vom System verboten werden.
Andreas
Ohforf Sake schrieb:> Stimmt nicht. Die Sache mit dem".", der ja auch erlaubt ist, hab ich> weggelassen, weils zu einfach ist.So einfach isses eben auch wieder nicht. Beispielsweise ist ja
0.0.0.0 keine gültige Zahl im Sinne des OP.