Forum: Compiler & IDEs Vergleich vom Char kombinieren(If-Abfrage)


von Ahnungsloser (Gast)


Lesenswert?

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'.

von Peter II (Gast)


Lesenswert?

Ahnungsloser schrieb:
> Die Abfrage würde riesig lang werden. GIbt es
> eine Möglichkeit, dies kompakter zu schreiben?

eine schleife programmieren.

von Max H. (hartl192)


Lesenswert?

Das Wäre eine Möglichkeit:
1
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.

: Bearbeitet durch User
von Christopher B. (chrimbo) Benutzerseite


Lesenswert?

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 :-)

: Bearbeitet durch User
von Max H. (hartl192)


Lesenswert?

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.

: Bearbeitet durch User
von Ahnungsloser (Gast)


Lesenswert?

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:
1
if((data[0] & 0xFE)== 0x30 && (data[1]& 0xFE)== 0x30 && (data[2]& 0xFE)== 0x30 && (data[3]& 0xFE)== 0x30)
Kürzer habe ich nicht hinbekommen.

von Max H. (hartl192)


Lesenswert?

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 :-(

von Ahnungsloser (Gast)


Lesenswert?

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.

von Mark B. (markbrandis)


Lesenswert?

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:

1
if ( (data[0] & 0xFE) == 0x30 && 
2
     (data[1] & 0xFE) == 0x30 && 
3
     (data[2] & 0xFE) == 0x30 && 
4
     (data[3] & 0xFE) == 0x30)

"Zeilenquetscher" müssen echt nicht sein... ;-)

: Bearbeitet durch User
von Yalu X. (yalu) (Moderator)


Lesenswert?

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.

: Bearbeitet durch Moderator
von nicht"Gast" (Gast)


Lesenswert?

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.)
1
bool hasOnlyAsciiZeroesAndOnes(const char &dataToCheck, size_t arraySize)
2
{
3
    for (int i=0; i<arraySize; i++){
4
        if ( dataToCheck[i] != '0' || dataToCheck[i] != '1' ){
5
            return false;
6
        }
7
    }
8
    return true;
9
}
10
11
int main(){
12
13
   // nichtstuendersourcecodehier
14
15
   if ( hasOnlyAsciiZeroesAndOnes( data, 4) ){
16
          tuWas();
17
   }
18
    
19
}

PS: Der Code ist nur so daher getippt und garantiert nicht frei von 
Fehlern. Soll ja auch nur verdeutlichen, was ich meine.

Grüße

von nicht"Gast" (Gast)


Lesenswert?

und schon ist es passiert.

muss natürlich
1
bool hasOnlyAsciiZeroesAndOnes(const char *dataToCheck, size_t arraySize)
2
{
3
    for (int i=0; i<arraySize; i++){
4
        if ( dataToCheck[i] != '0' && dataToCheck[i] != '1' ){
5
            return false;
6
        }
7
    }
8
    return true;
9
}

heißen

von Dr. Sommer (Gast)


Lesenswert?

1
#include <iostream>
2
#include <algorithm>
3
4
int main() {
5
  // Array anlegen
6
  char data [] = { '0', '1', '1' };
7
  // Überprüfung
8
  if (std::all_of (std::begin(data), std::end(data), [](char x) { return x == '0' || x == '1'; })) {
9
  // Ergebnis anzeigen
10
    std::cout << "Alle 0 oder 1.\n";
11
  } else {
12
    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

von nicht"Gast" (Gast)


Lesenswert?

Wenn schon C++ dann auf jeden Fall mit einem gescheiten Container.

Wenn du dein Array auf dem Heap anlegst, geht deine Methode nicht mehr.

von Dr. Sommer (Gast)


Lesenswert?

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.

von nocheinGast (Gast)


Lesenswert?

> 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 ;)

von nicht"Gast" (Gast)


Lesenswert?

all_of nicht, aber std::begin und std::end kümmerst.

Probiers mal aus.

von nicht"Gast" (Gast)


Lesenswert?

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?)

von nocheinGast (Gast)


Lesenswert?

@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]);

von Dr. Sommer (Gast)


Lesenswert?

nicht"Gast" schrieb:
> all_of nicht, aber std::begin und std::end kümmerst.
>
> Probiers mal aus.
Ja, funktioniert:
1
#include <iostream>
2
#include <algorithm>
3
#include <memory>
4
#include <iterator>
5
6
struct PutThisOnHeap {
7
  const char data [3];
8
  PutThisOnHeap () : data { '0', '1', '1' } {}
9
};
10
11
int main() {
12
  // Array auf dem Free Store ("Heap") anlegen
13
  std::unique_ptr<PutThisOnHeap> array (new PutThisOnHeap);
14
  auto& data = array->data;
15
  
16
  // Überprüfung
17
  if (std::all_of (std::begin(data), std::end(data), [](char x) { return x == '0' || x == '1'; })) {
18
  // Ergebnis anzeigen
19
    std::cout << "Alle 0 oder 1.\n";
20
  } else {
21
    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:
1
#include <iostream>
2
#include <algorithm>
3
#include <memory>
4
5
int main() {
6
  // Array auf dem Free Store ("Heap") anlegen
7
  std::unique_ptr<char []> data (new char [3] { '0', '1', '1' });
8
  // Laufzeit-bekannte Größe angeben
9
  size_t len = 3;
10
  
11
  
12
  // Überprüfung
13
  if (std::all_of (data.get (), data.get ()+3, [](char x) { return x == '0' || x == '1'; })) {
14
  // Ergebnis anzeigen
15
    std::cout << "Alle 0 oder 1.\n";
16
  } else {
17
    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...

von nicht"Gast" (Gast)


Lesenswert?

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 ;)

von nicht"Gast" (Gast)


Lesenswert?

Zusatz

aus mir spricht in dem Fall die Unwissenheit.
1
struct PutThisOnHeap {
2
  const char data [3];
3
  PutThisOnHeap () : data { '0', '1', '1' } {}
4
};

packst du die Daten hier nicht doch wieder auf den Stack?

von Dr. Sommer (Gast)


Lesenswert?

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
struct PutThisOnHeap {
2
  const char data [3];
3
  PutThisOnHeap () : data { '0', '1', '1' } {}
4
};
5
6
int main () {
7
  PutThisOnHeap* obj = new PutThisOnHeap ();
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
struct PutThisOnHeap {
2
  const char data [3];
3
  PutThisOnHeap () : data { '0', '1', '1' } {}
4
};
5
6
int main () {
7
  PutThisOnHeap obj;
8
}
Ist das komplette struct auf dem Stack und wird bei der Rückkehr der 
main() gelöscht, inklusive dem "data" Array.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.