Hallo Leute,
Folgendes Probelem: Ich habe ein Array data[3] vom Typ char. Nun will
ich überprüfen, ob data[0] gleich '0' oder '1' ist.
Erste Ansatz:
1
if(data[0]=='0'||data[0]=='1')do()
Das funktioniert auch soweit.
Nun ist mein Dataarray ein bischen größer und möchte überprüfen, ob alle
Zeichen '0' oder '1' sind. Die Abfrage würde riesig lang werden. GIbt es
eine Möglichkeit, dies kompakter zu schreiben?
Versucht habe ich schon das:
1
if(data[0]==('0'||'1'))do()
Was aber logischerweise nicht funktioneren kann, da der Inhalt von
data[0] auf 0 oder 1 überprüft wird, und nicht '0' oder '1'.
Bei 0 oder 1 sind ja alle Bits bis auf das LSb null. Wenn du das LSb auf
null setzt weißt du dass die Zahl 0 oder 1 war wenn dann die gesamte
Zahl 0 ist.
Max H. schrieb:> Das Wäre eine Möglichkeit:if(!(data[0]&0xFE))Bei 0 oder 1 sind ja> alle Bits bis auf das LSb null. Wenn du das LSb auf> null setzt weißt du dass die Zahl 0 oder 1 war wenn dann die gesamte> Zahl 0 ist.
Das macht etwas völlig anderes.
Solange nur Zahlen oder Buchstaben vorkommen:
1
if((data[0]-'2')<0)
Allerdings wird da definitiv ein Kommentar nötig was das soll :-)
Christopher B. schrieb:> Das macht etwas völlig anderes.
Nein:
0b00000000
&0b11111110
=0b00000000 --> False
!False=True (also True wenn die Zahl 0 war)
0b00000001
&0b11111110
=0b00000000 --> False
!False=True (also True wenn die Zahl 1 war)
0b00100101
&0b11111110
=0b00100100 --> True
!True=False (also False wenn 1≠Zahl≠0 war)
Das Dritte kann man so für jede Zahl ungleich 0 und ungleich 1 machen.
Max H. schrieb:> Christopher B. schrieb:>> Das macht etwas völlig anderes.> Nein:>> 0b00000000> &0b11111110> =0b00000000 --> False>> !False=True (also True wenn die Zahl 0 war)>> 0b00000001> &0b11111110> =0b00000000 --> False>> !False=True (also True wenn die Zahl 1 war)>> 0b00100101> &0b11111110> =0b00100100 --> True>> !True=False (also False wenn 1≠Zahl≠0 war)>> Das Dritte kann man so für jede Zahl ungleich 0 und ungleich 1 machen.
Es geht abe nich um 0 oder 1, sonder um '0' oder '1' also 48 oder 49,
oder auch 0x30 oder 0x31. Trotzdem danke für den Ansatz.
Habe jetzt folgende Überprüfung benutzt:
Ahnungsloser schrieb:> Es geht abe nich um 0 oder 1, sonder um '0' oder '1' also 48 oder 49,> oder auch 0x30 oder 0x31.
Das habe ich leider erst zu spät gesehen :-(
Max H. schrieb:> Ahnungsloser schrieb:>> Es geht abe nich um 0 oder 1, sonder um '0' oder '1' also 48 oder 49,>> oder auch 0x30 oder 0x31.> Das habe ich leider erst zu spät gesehen :-(
Kein Problem. So habe ich mich selber nochmal ein bischen intensiver
damit beschäftig, statt einfach nur den Code zu kopieren. Habe also
deswegen mehr gelernt.
Danke für den Ansatzt trotzdem.
Der übliche Weg ist, von Anfang bis Ende über alle Elemente des Arrays
zu iterieren. Also eine Schleife zu verwenden, z.B. eine for-Schleife.
Bei vier Elementen kann man vielleicht noch ohne Schleife auskommen,
würde es dann aber auch so hinschreiben, dass für den Menschen sofort
ersichtlich ist was hier passiert:
Ahnungsloser schrieb:> if((data[0] & 0xFE)== 0x30 && (data[1]& 0xFE)== 0x30 && (data[2]&> 0xFE)== 0x30 && (data[3]& 0xFE)== 0x30)
Das geht natürlich meistens, ist aber etwas pfuschig, weil ein
bestimmter Zeichencode (ASCII) vorausgesetzt wird.
Wenn du schon am Pfuschen bist, kannst du auch gleich Folgendes
versuchen:
1
if((*(uint32_t*)data&0xFEFEFEFE)==0x30303030)...
was zumindest auf Prozessoren mit Wortbreite >8 schneller sein dürfte.
Juhu, unlesbarer Code ^^
Warum stopfst du deine Abfrage nicht in eine Funktion und rufst die auf?
Das ist auf jeden fall deutlich lesbarer, als das vorher und das gedöns
mit den Hex ziffern. Wenn es dann in der Laufzeit probleme macht, kannst
du die Funktion immer noch verwursten (inline, wilde hex hacks u.s.w.)
std::cout<<"Einer der Einträge ist weder 0 noch 1.";
13
}
14
}
Die Überprüfung geht so in 1 Zeile. Hat den Vorteil dass man:
* Die Größe des Arrays ändern kann ohne die Überprüfung anpassen zu
müssen (geht automatisch)
* Den Typ von "data" ändern kann zu einem Standard(-kompatiblen)
Container wie std::vector oder std::list ohne die Überprüfung anpassen
zu müssen
nicht"Gast" schrieb:> Wenn schon C++ dann auf jeden Fall mit einem gescheiten Container.>
Ja. Wollte demonstrieren dass es auch mit klassischen C Arrays
funktioniert.
> Wenn du dein Array auf dem Heap anlegst, geht deine Methode nicht mehr
Doch, klar. all_of schert sich nicht darum, wo seine Daten liegen.
> Doch, klar. all_of schert sich nicht darum, wo seine Daten liegen.
Er hat gemeint, wenn du die Länge des Arrays zu dem Zeitpunkt nicht
kennst und nur einen Zeiger auf das erste Element hast.
Evtl. auch mal std::array anschauen, wenn du die Länge vorher kennst ;)
nicht"Gast" schrieb:> all_of nicht, aber std::begin und std::end kümmerst.>> Probiers mal aus.
Menno, ich geh jetzt ins Bett.
Den Rechtschreibfehler ignorieren und der Haken ist warscheinlich vor
Allem std::end. (VS meckert aber beides an. Keine Ahnung, was der gcc
macht, aber woher soll er zur Laufzeit die Größe vom C Array bekommen?)
@nicht"Gast":
Es darf auch std::begin nicht mit einem Zeiger funktionieren, weil das
Template so deklariert ist:
> template <class C> auto begin(C& c) -> decltype(c.begin());> template <class T, size_t N> T* begin(T (&array)[N]);
std::cout<<"Einer der Einträge ist weder 0 noch 1.";
22
}
23
}
Kleiner Umweg über PutThisOnHeap um die Typinformation zu erhalten.
Anders wirds dank C-Legacy-Zeug (type dacay) hässlich.
nocheinGast schrieb:> Er hat gemeint, wenn du die Länge des Arrays zu dem Zeitpunkt nicht> kennst und nur einen Zeiger auf das erste Element hast.
AHA, das ist aber was GANZ anderes! Aber man kann die Länge auch von
Heap-Arrays zur Compilezeit kennen, s.o.
Sollte man die Länge gar nicht zur Kompilezeit kennen und will C-Arrays
verwenden, ist das natürlich auch kein Problem:
std::cout<<"Einer der Einträge ist weder 0 noch 1.";
18
}
19
}
Dann verwendet man kein std::begin/end (was ja die Typinformationen
verwendet) sondern macht einfach Pointer-Arithmetik.
PS: Im 1. Post #include <iterator> vergessen...
Oh Mann,
was du da treibst ist ein typischer Fall von: ich weiss genau, was er
meint, kann aber nicht zugeben, dass meine Lösung so nicht geht.
übrigens ist ein unique_ptr kein typisches C-Array ;)
PS: falls das in den falschen Hals geraten sein sollte (so scheint es
mir grade). Der Focus meiner Antwort liegt auf: Wenn C++ dann bitte auch
in einem vernünftigen Container und nicht plain auf irgend welchen C
Arrays. Ich wollte deinen Post nicht schlecht reden, sondern nur auf
einen Stolperstein hinweisen.
PPS: dein letzter Post ist echt fieser Code, dem ich hoffentlich so nie
begegnen werde ;)
nicht"Gast" schrieb:> was du da treibst ist ein typischer Fall von: ich weiss genau, was er> meint, kann aber nicht zugeben, dass meine Lösung so nicht geht.nicht"Gast" schrieb:> all_of nicht, aber std::begin und std::end kümmerst.>> Probiers mal aus.
Naja, wenn einer so kommt und so tut als hätte ich keine Ahnung wovon
ich rede, darf ich auch pingelig sein. Eigentlich muss man das als
Programmierer immer sein, insbesondere bei der Speicherverwaltung in
C++...
nicht"Gast" schrieb:> übrigens ist ein unique_ptr kein typisches C-Array ;)
unique_ptr ist ein Smart-Pointer, der auf ein typisches C-Array zeigt.
Mit .get() erhält man den "normalen" Pointer. unique_ptr wird verwendet
um Speicherlecks zu vermeiden - egal wie die main() zurückkehrt, per
return oder Exception, das Array wird immer freigegeben.
nicht"Gast" schrieb:> Der Focus meiner Antwort liegt auf: Wenn C++ dann bitte auch> in einem vernünftigen Container und nicht plain auf irgend welchen C> Arrays.
Ja das ist schon richtig. Ich wollte meinen 1. Post nicht noch durch
Verwendung eines anderen Containers zusätzlich verkomplizieren. Und
manchmal hat man leider auch keine Wahl.
nicht"Gast" schrieb:> PPS: dein letzter Post ist echt fieser Code, dem ich hoffentlich so nie> begegnen werde ;)
Ja der erste ist etwas komisch. Wenn man std::array verwendet erhält
dieses die Typinformation und man spart sich das struct. Der 2. Code ist
eigentlich ganz normal...
nicht"Gast" schrieb:> packst du die Daten hier nicht doch wieder auf den Stack?
Nö. Genau genommen packt dieses struct das Array "data" auf den
"automatic storage", also dahin wo auch immer das struct landet. In
diesem Fall:
1
structPutThisOnHeap{
2
constchardata[3];
3
PutThisOnHeap():data{'0','1','1'}{}
4
};
5
6
intmain(){
7
PutThisOnHeap*obj=newPutThisOnHeap();
8
// delete vergessen ...
9
}
landet das struct eindeutig auf dem free store ("Heap"), und damit auch
das enthaltene "data" Array. Wenn die main() zurückkehrt ist das struct
immer noch da (weil es eben nicht auf dem Stack liegt) und wir haben
ein Memory Leak.
In diesem Fall hingegen
1
structPutThisOnHeap{
2
constchardata[3];
3
PutThisOnHeap():data{'0','1','1'}{}
4
};
5
6
intmain(){
7
PutThisOnHeapobj;
8
}
Ist das komplette struct auf dem Stack und wird bei der Rückkehr der
main() gelöscht, inklusive dem "data" Array.