Guten Morgen ich mache in den Ferien ein kleines Projekt mit einem
Atmega in C.
Nach der Eingabe wird der String in ein Char-Array gelegt.
Nun suche ich nach einer Lösung wie ich einen Wert aus einem Char-Array
am besten überprüfe, ob es sich um eine gültige Hex-Zahl handelt.
beste Grüße
Ben
Du machst eine Schleife die alle chars durchgeht.
Dann überprüfst du, ob der char 0-9, a-f, A-F ist. Wenn nicht, ist es
keine hex-zahl
Optional/gesteigerter Schwierigkeitsgrad: eine 0x am Anfang erkennen :-)
für beiden Zeichen überprüfen, ob sie erlaubt sind, z.B. so:
bool valid_hex(const char *p)
{
for (int i = 0; i < 2; i++)
{
if (!strchr("0123456789AaBbCcDdEeFf", *p++))
return false;
}
return true;
}
benny 15 schrieb:> Nach der Eingabe wird der String in ein Char-Array gelegt.
Mach die Prüfung doch einfach schon während der Eingabe. Dann weißt du
anschleissend, dass nur gültige Ziechen im Puffer sind....
Vielen Dank noch einmal.
funktioniert alles 1A
habe folgende Funktion geschrieben die eine 0 zurückgibt wenn alles
übereinstimmt und ein zahl größer 0 wenn etwas nicht übereinstimmt.
char Hex_Compare (char c[])
{
size_t str_len_i = strlen(c);
while (isxdigit(c[str_len_i-1]))
{
str_len_i--;
}
return str_len_i;
}
Beste Grüße
Ben
autsch so greifst du aber erheblich außerhalb der grenzen des arrays
zu wenns blöd kommt!
Ich werde wohl nie verstehen wieso man immer versuch auf Krampf alles
mit einer While-Schleife und abstrusen Abbruchbedingungen zu arbeiten
wenn man über ein Menge bekannter Größe iterieren will.
Nebenbei bemerkt ist der Rückgabetyp falsch! size_t != char, und wenn du
0 zurückgeben willst falls alles geklappt hat tu das doch anstatt
implizit darauf zu vertrauen dass eine Variable schon 0 sein wird (wie
gesagt wenns blöd läuft hat sie irgendeinen Wert...).
1
size_tHex_Compare(charc[]){
2
size_tlen=strlen(c);
3
for(size_ti=0;i<len;i--){
4
if(!isxdigit(c[i]){
5
returni;
6
}
7
}
8
return0;
9
}
Auf diese Weise erhälst du:
0: Alles hat geklappt, sonst: Position des ersten fehlerhaften Zeichens
im String, du greifst nicht über die Stringgrenzen hinaus und man sieht
auf den ersten Blick was geschieht.
Hallo Läubi,
Ich entschuldige meine While ich bin noch recht neu in der
Programmierung. Das mit dem Char != size_t war lediglich ein
schreibfehler sonst würde ja die funktion bei mir nicht laufen.
Nun hab ich aber ein Frage zu der For Schleife
Okay:
i wird 0 : verstanden
i < len : Abbruchbedingung verstanden
i -- : verstehe ich NULL !
Wenn ich richtig liege wende ich im ersten Schleifendurchlauf
"isxdigit(c[i]" im Feld 0 des Arrays an. Im nächsten wäre ich bei -1 im
array wie geht das ?
Und würde ich nicht, wenn im ersten durchlauf ein falsches Zeichen wäre,
sofort die Aktuelle 0 von i zurückgeben und somit das Ergebnis
verfälschen?
Beste Grüße
Ben
Theoretisch muss ich doch am sinnvollsten i mit 1 zu definieren. Weil
egal ob i-- oder i++ bietet mir der erste Durchlauf keine Sicherheit.
Wäre das erste zeichen kein Hexwert hätte ich ein return i; was in dem
Fall ein return 0; wäre. Und dann würde ja die Funktionen falsche werte
liefern.
Ben
Nur so nebenbei und ohne Gewähr:
benny 15 schrieb:> Im nächsten wäre ich bei -1 im array
Nicht unbedingt, das hängt davon ab ob size_t vorzeichenbehaftet oder
-los ist. Im zweiten Fall würde i nach
1
i=0;i--;
die größtmögliche Zahl enthalten die in size_t gespeichert werden kann
(also z.B. 65535 bei 16 Bit).
benny 15 schrieb:> Theoretisch muss ich doch am sinnvollsten i mit 1 zu definieren. Weil> egal ob i-- oder i++ bietet mir der erste Durchlauf keine Sicherheit.>> Wäre das erste zeichen kein Hexwert hätte ich ein return i; was in dem> Fall ein return 0; wäre. Und dann würde ja die Funktionen falsche werte> liefern.
Gut gesehen! i mit 1 zu initialisieren ist aber keine Lösung weil dann
das erste Zeichen nicht geprüft wird. By the way, ich bekomme den Code
oben sowieso nicht durch den GCC, irgendwelche Syntaxfehler (und das
size_t in der for-Schleife will er auch nicht aber das ist wohl eine
Einstellungssache).
Eine Möglichkeit (nicht besonders elegant finde ich):
1
signedintHex_Compare(charc[])
2
{
3
size_tlen=strlen(c);
4
size_ti;
5
for(i=0;i<len;i++)
6
{
7
if(!isxdigit(c[i]))
8
returni;
9
}
10
return-1;
11
}
Alternativ bei einem ungültigen Zeichen immer 1 zurückgeben (und 0 bei
einem gültigen), dann verliert man aber die Information an welcher
Stelle das Problem ist. (Was man durch einen Pointer auf einen int als
zweiten Parameter lösen könnte aber das ist hässlich.)
logisch gemeint ist i++, sorry für die Verwirrung.
benny 15 schrieb:> Und würde ich nicht, wenn im ersten durchlauf ein falsches Zeichen wäre,> sofort die Aktuelle 0 von i zurückgeben und somit das Ergebnis> verfälschen?
Korrekt habe ich nicht bedacht. Das beste wäre vermutlich folgendermaßen
abzuwandeln:
1
intHex_Compare(charc[]){
2
size_tlen=strlen(c);
3
for(size_ti=0;i<len;i++){
4
if(!isxdigit(c[i]){
5
return1;
6
}
7
}
8
return0;
9
}
Dann erhält man nur die Info ob es geklappt hat oder nicht, sollte aber
ausreichen.
Phantomix Ximotnahp schrieb:> Herrje...>> Ungetestet aber sollte so funktionieren:
In deinem Code sind gleich mehrere Probleme
> char is_hex(char* input);>
char ist ein denkbar ungeeigneter Returnwert.
Gewöhn dir folgende Sicht der Dinge an
char benuzt du immer dann, wenn du Textverarbeitung
machst. Also Einzelzeichen oder Strings
singned char benutzt du immer dann, wenn du einen kleinen
Integer brauchst. In diesem Fall mit Vorzeichen
unsigned char benutzt du ebenfalls immer dann, wenn du einen
kleinen Integer benötigst, diesmal aber ohne
Vorzeichen.
Das heißt: char alleine, also ohne signed oder unsigned, nimmst du
ausschliesslich nur dann her, wenn du Textverarbeitung machst. In allen
anderen Fällen, überlässt du es nicht dem Compiler ob er einen char als
signed oder unsigned ansiehst, sondern du bist da explizit.
Auch wenn ein char alleine auch nur entweder signed oder unsigned sein
kann, ist es doch besser, man arbeitet konzeptionell mit 3 verschiedenen
Datentypen
char
signed char
unsigned char
der erste wird ausschliesslich für Textverarbeitung benutzt (un nur
dafür), die anderen beiden für Rechnen oder Logik-Sachen.
> char is_hex(char* input)> {> char c;> if((input[0] == '0') && (input[1] == 'x'))> input += 2;>> for(; c = *input; input++)> {> if((c >= '0') && (c <= '9')) continue;> c |= 0x20;> if((c >= 'a') && (c <= 'f')) continue;> return 0;
Du hast auf die Grossbuchstaben vergessen.
Und genau aus diesem Grunde ist es besser, die vordefinierte Funktion
isxdigit zu benutzen. Auch aus einem anderen Grunde ist das besser,
wobei ich zugeben muss, dass dieser Grund heutzutage kaum mehr eine
Rolle spielt: Wer garantiert dir, dass die Buchstaben hintereinander
kommen? Der C-Standard garantiert dir das nämlich nicht.
Hihi, schön, mal als schlechtes Beispiel zu dienen :D
Der Code ist absichtlich wie mit der Axt geschrieben...
>> char is_hex(char* input);>>> char ist ein denkbar ungeeigneter Returnwert.
Wo du Recht hast. Normalerweise nehm ich uint8_t, aber wollt jetzt nicht
noch mit includes ankommen. Für den Fall "is_hex" mit Rückgabewert
0=false, 1=true funktioniert sowohl signed als auch unsigned char. Egal
wie man es bei der Auswertung betrachtet. Trotzdem danke für den Einwand
:-)
>>> char is_hex(char* input)>> {>> char c;>> if((input[0] == '0') && (input[1] == 'x'))>> input += 2;>>>> for(; c = *input; input++)>> {>> if((c >= '0') && (c <= '9')) continue;>> c |= 0x20;>> if((c >= 'a') && (c <= 'f')) continue;>> return 0;>> Du hast auf die Grossbuchstaben vergessen.
Nein hab ich nicht. Großbuchstaben handle ich über c |= 0x20; ab.
Dadurch wird A-F -> a-f.
> Und genau aus diesem Grunde ist es besser, die vordefinierte Funktion> isxdigit zu benutzen. Auch aus einem anderen Grunde ist das besser,> wobei ich zugeben muss, dass dieser Grund heutzutage kaum mehr eine> Rolle spielt: Wer garantiert dir, dass die Buchstaben hintereinander> kommen? Der C-Standard garantiert dir das nämlich nicht.
Der Ansi und Ascii-Standard definiert das, und um den gehts ja bei der
String-Auswertung :-)
wollte nur zeigen, dass man so ein Problem auch effizient "zu fuß"
angehen kann, wenn man will
Phantomix Ximotnahp schrieb:> Nein hab ich nicht. Großbuchstaben handle ich über c |= 0x20; ab.> Dadurch wird A-F -> a-f.
Uuuu
schlechter Stil. Ganz schlechter Stil.
> Der Ansi und Ascii-Standard definiert das,
Der ASCII Standard ist uninteressant.
Hier geht es um C. Und C schreibt nicht vor, welcher Zeichensatz zu
verwenden ist. Schon mal auf einem IBM Grossrechner älterer Bauart
programmiert? Dort gibt es nämlich kein ASCII, dort gibt es EBCDIC.
Und wenn man sein C richtig schreibt, und nur das benutzt, was einem
garantiert wird (zb. das die Character '0' bis '9' in dieser Reihenfolge
aufsteigende Codes haben müssen, aber alle anderen Character können frei
in den Codetabellen angeordnet sein) dann kann man Code problemlos von
einer Maschine auf die andere portieren UND gleichzeitig effizient sein.
> Hier geht es um C. Und C schreibt nicht vor, welcher Zeichensatz zu> verwenden ist. Schon mal auf einem IBM Grossrechner älterer Bauart> programmiert? Dort gibt es nämlich kein ASCII, dort gibt es EBCDIC.> Und wenn man sein C richtig schreibt, und nur das benutzt, was einem> garantiert wird (zb. das die Character '0' bis '9' in dieser Reihenfolge> aufsteigende Codes haben müssen, aber alle anderen Character können frei> in den Codetabellen angeordnet sein) dann kann man Code problemlos von> einer Maschine auf die andere portieren UND gleichzeitig effizient sein.
Und wieder hast du Recht. Und ich hab mit meinem Code das erreicht was
ich erreichen wollte: Eine funktionierende Variante präsentieren, die
mit der Axt programmiert wurde :-) Wenn ich auf Arbeit über solchen Code
meines Vorgängers stolper[n würde], gäb es erstmal einen derben Fluch,
dann würd ichs neu machen...
Phantomix Ximotnahp schrieb:> ich erreichen wollte: Eine funktionierende Variante präsentieren,
Na, dann ruf deine Funktion mal so auf
is_hex( "" );
> meines Vorgängers stolper[n würde], gäb es erstmal einen derben Fluch,> dann würd ichs neu machen...
:-)
Kenn ich. Ich fluch jeden Tag.
ein leerer string liefert 1 zurück. weiß ich auch. man könnte das jetzt
noch extra abfangen je nach Zweck
Anders ausgedrückt: ein leerer String ist ein valider 0-Bit-Hexwert.
Phantomix Ximotnahp schrieb:> ein leerer string liefert 1 zurück.
Ein leerer String generiert vor allen Dingen hier
>> if((input[0] == '0') && (input[1] == 'x'))
eine Access Violation.
Komm, geschenkt. Du hast selbst gesagt, das ist mit der groben Axt
gemacht.
Karl Heinz Buchegger schrieb:> Ein leerer String generiert vor allen Dingen hier>>> if((input[0] == '0') && (input[1] == 'x'))> eine Access Violation.
sch...eibenkleister, du hast Recht. Dann eben jetzt die Deluxe-Version
mit uint8_t, Null-String-ist-falsch, A-F
Karl Heinz Buchegger schrieb:>> Nein hab ich nicht. Großbuchstaben handle ich über c |= 0x20; ab.>> Dadurch wird A-F -> a-f.>> Uuuu> schlechter Stil. Ganz schlechter Stil.
Ja, aber auch nur, weil es nicht entsprechend dokumentiert wurde. Hin
und wieder muss man halt mit Bits frunzeln, wenn es den Code schneller
und kleiner macht und es auf Schnelligkeit und Größe ankommt.
Was eher schlechter Programmierstil ist, ist ein if-Statement inklusive
bedingter Anweisung in eine Zeile zu packen. Hier empfehle ich
grundsätzlich die 4+ Zeilen-Variante mit jeweils einer eigenen Zeile für
"{" und "}".
Den Ausdruck "c = *input" würde ich in ((c = *input) != 0)
umformulieren, da das aus Compiler-Sicht auf das Gleiche hinauskommt,
aber sofort ins Auge sticht, was es bedeuten soll und dass es Absicht
und nicht etwa ein Programmierfehler ist.
Die Verwendung von "continue" möchte ich auch mal als zumindest
problematisch betrachten. Es erinnert ein wenig an goto. Lieber ein if()
mehr und den Rest einrücken.
Um auch noch etwas nettes zu sagen, möchte ich die Leerzeichen vor und
nach Operatoren positiv anmerken!