# integer/Zahlentaste mit ansi Wert vergleichen C++



## Puepue (26. Januar 2010)

Hallo Zusammen,
ich habe ein Problem, das relativ schwer zu erklären ist. Aaalsooo...
Wenn ich mit getch() (oder getche etc.) eine Zahltaste abfange, dann kommt ja der ANSI-Code raus.Bei Taste 3 ist das ja z.B. 51.
Die 3 kann ich mir ausgeben lassen, in dem ich das ganze in ein Char caste, ist klar - allerdings kann ich die so entstandene "3" ja nicht mit einer integer-3 vergleichen.

Beispiel: 


```
// Wenn Taste gedrückt wurde
if (kbhit())
{
    eingloesung = getch();   // Da sollte jetzt z.b. 51 drin stehn
    int zahl1 = 1;
    int zahl2 = 2;
    int loesung = zahl1+zahl2;
    int e = (char)eingloesung;

    if ( e == loesung )    // GEHT NICHT
    {
       //richtig
    }
}
```

Wie kann ich jetzt also testen ob die eingegebene Zahl == loesung ist ?

PS: Windows XP und Visual C++


----------



## bingo88 (26. Januar 2010)

atoi ist dein Freund. Gibt es auch andersherum: itoa


----------



## Puepue (26. Januar 2010)

Hmmmm.. also irgendwie klappt das noch nicht so ganz, mit dem Fehler:
error C2664: 'atoi': Konvertierung des Parameters 1 von 'const char' in 'const char *' nicht möglich


```
if (kbhit())
			{	
				
				eingloesung = getch();
				const char eing = (char)eingloesung;
				int zahl1 = 1;
				int zahl2 = 2;
				int i;
				int loesung = zahl1+zahl2;

				i = atoi (eing);

...
```


----------



## bingo88 (26. Januar 2010)

Ja, da war ich was flott: Der erwartet ja auch nen String als Argument 

Für nur ein Zeichen kannst du auch das machen:

```
char toChar(int i)
{
    return (char)(i + '0'); // Kanst auch +48 machen -> ASCII für 0
}
```

Klappt aber nur für Zahlen von 0 bis 9, sonst kommt eher Müll dabei raus...

Andersrum geht's natürlich auch:

```
int toInt(char c)
{
    return (c-'0'); // oder -48
}
```


----------



## Puepue (26. Januar 2010)

Hey, Super das hat jetzt geklappt..

.. und mir ist aufgefallen dass ich auch die eingabe einer mehrstelligen Zahl möglich machen muss.. na super =/


Gibt es getch() auch für mehre Tasten nacheinander? also dass ich statt 3 auch 33 eingeben könnte ?


----------



## bingo88 (26. Januar 2010)

Da ist dann atoi dein Freund ;o)
Ist das ne Konsolenanwendung oder Win32 GUI?
Bei ner Konsolenanwendung kannst du dir mal scanf (C) bzw. cin (C++) oder getline() ansehen. Du solltest dir aber direkt die "sicheren" Versionen ansehen, bei denen du eine Puffergröße angeben kannst. Ohne diese maximal zulässige Größe liest die Funktion nämlich bis zum Erreichen eines Trennzeichens/Zeilenvorschubs. Und das kann ggf. deinen Puffer überlaufen lassen!


```
#include <iostream>
using namespace std;

int main(int argc, char *argv[])
{
    char input[25]; // 24 Zeichen + 0-Terminator ('\n')

    cin.getline(input, 25); // siehe [URL="http://www.cplusplus.com/reference/iostream/istream/getline/"]hier[/URL]

    int zahl = atoi(input);
    cout << zahl << endl;

    return 0;
}
```


----------



## Puepue (26. Januar 2010)

Das Problem an cin und getline ist, dass ich nicht auf eine Eingabe von Enter warten kann, weil ich in einer Schleife ein Zeichen von links nach rechts über den Bildschirm laufen lasse, quasi als Zeitleiste. Wenn ich dann auf Enter warte, geht die Schleife ja nicht weiter und man hat ewig Zeit, um Die Lösung einzugeben...
Evtl. sowas wie cin, nur das es automatisch nach x millisekunden abbricht aber ich glaube sowas gibts nicht.. kann das also sein, dass es garnicht lösbar ist ?

Ist eine Win32 Konsolenanwendung in C++, es geht quasi darum in gewisser Zeit eine Rechenaufgabe zu lösen


----------



## bingo88 (26. Januar 2010)

Okay, das macht die Sache natürlich direkt komplizierter 

Was mir jetzt spontan dazu einfällt wäre:
1. Nen Puffer für Zeichen anlegen
2. Mit Hilfe einer Art Timer z. B. für drei Sekunden alle Eingaben aufzeichnen (also in den Puffer einlesen mit getchar)
3. Nach Ablauf der Zeit (oder wenn return gedrückt wurde) den Puffer verarbeiten (wichtig: der Puffer muss mit '\0' initialisiert werden)

Vielleicht hilft dir auch dieser Artikel hier.

Gruß,
bingo


----------



## Puepue (27. Januar 2010)

ka ich komm nicht weiter
es müsste einfach eine eingabe geben die nach x sekunden abbricht, die mehrere zeichen erlaubt


----------



## bingo88 (28. Januar 2010)

So, jetzt hab ich dir mal eben was gebastelt 

Hier die main.cpp:

```
#include <iostream>

#include <iostream>
#include <time.h>
#include "CharBuffer.h"
#include <conio.h>
#include <windows.h>

using namespace std;

int main(int argc, char *argv[])
{
    int seconds = 5;
    time_t currTime = time(NULL);

    CharBuffer cb(10);

    try {
        while ((currTime + seconds) != time(NULL)) {
            if (_kbhit())
            {
                int c = _getch();

                // Enter-Taste
                if (c == '\r')
                {
                    break;
                }
                else if (c == '\b')
                {
                    // Backspace -> letztes Zeichen entfernen
                    cb.pop();
                    // Keine Ahnung, ob das besser geht.
                    // Normalerweise mache ich so einen Konsolenkram net.
                    _putch('\b');
                    _putch(' ');
                    _putch('\b');
                }

                if (c < '0' || c > '9')
                {
                    // Nur Zahlen von 0 bis 9 zulassen.
                    continue;
                }

                // Zahl anzeigen
                _putch(c);
                // Zahl im Puffer sichern
                cb.push(c);
            }

            // 10ms warten (keine 100% CPU Last erzeugen!)
            Sleep(10);
        }
    } catch (int e)
    {
        if (e == BUFFER_OVERFLOW)
        {
            cout << endl << "Buffer Overflow" << endl;
        }
    }

    _putch('\n');
    //_putch('\r');
    cout << cb << endl;

    char *buff = cb.getBuffer(); // wird automatisch geflusht
    int zahl = atoi(buff);
    delete[] buff; // WICHTIG!!!

    cout << zahl << endl;

    return 0;
}
```
Hier die CharBuffer.h:

```
#ifndef CHARBUFFER_H_
#define CHARBUFFER_H_

#include <iostream>

#define BUFFER_OVERFLOW -1

class CharBuffer
{
public:
    CharBuffer(unsigned int maxSize);
    CharBuffer(const CharBuffer &c);
    virtual ~CharBuffer();
    
    void push(char c);
    char pop();
    void clear();
    char *getBuffer(bool flush = true);
    
    bool isEmpty() const
    {
        return (m_size > 0);
    }
    
    unsigned int size() const
    {
        return m_size;
    }
    
    CharBuffer& operator =(const CharBuffer &c);
    
private:
    char *m_pBuffer;
    unsigned int m_maxSize;
    unsigned int m_size;

    friend std::ostream& operator <<(std::ostream& out, const CharBuffer &c);
};

std::ostream& operator <<(std::ostream& out, const CharBuffer &c);

#endif /* CHARBUFFER_H_ */
```
Und zu gutewr letzt die entsprechende CharBuffer.cpp:

```
#include "CharBuffer.h"

// Erzeugt einen neuen CharBuffer mit der angegebenen maximalen
// Länge (inlusive Nullterminator).
CharBuffer::CharBuffer(unsigned int maxSize) :
m_maxSize(maxSize), m_size(0)
{
    m_pBuffer = new char[m_maxSize];

    // mit Null-Zeichen initialsieren
    for (unsigned int i = 0; i < m_maxSize; ++i)
    {
        m_pBuffer[i] = '\0';
    }
}

// Kopiert einen CharBuffer.
CharBuffer::CharBuffer(const CharBuffer &c) :
m_maxSize(c.m_maxSize), m_size(c.m_size)
{
    m_pBuffer = new char[m_maxSize];

    for (unsigned int i = 0; i < m_size; ++i)
    {
        m_pBuffer[i] = c.m_pBuffer[i];
    }
}

// Gibt alle Ressourcen wieder frei.
CharBuffer::~CharBuffer()
{
    delete[] m_pBuffer;
}

// Leert den Puffer.
void CharBuffer::clear()
{
    for (unsigned int i = 0; i < m_maxSize; ++i)
    {
        m_pBuffer[i] = '\0';
    }

    m_size = 0;
}

// Ruft den String dieses Buffers ab. Dies ist ein neues Objekt,
// muss also mit delete[] freigemacht werden! Optional kann der
// Puffer geleert werden (flush = true).
char *CharBuffer::getBuffer(bool flush)
{
    char *out = new char[m_size];

    // Puffer kopieren
    for (unsigned int i = 0; i < m_size; ++i)
    {
        out[i] = m_pBuffer[i];
    }

    // Puffer leeren?
    if (flush)
    {
        clear();
    }

    return out;
}

// Zeichen auf den Stack legen.
void CharBuffer::push(char c)
{
    if (m_size == m_maxSize - 1)
    {
        throw BUFFER_OVERFLOW;
    }

    m_pBuffer[m_size] = c;
    ++m_size;
}

// Zeichen vom Stack nehmen (Backspace).
char CharBuffer::pop()
{
    char c = '\0';

    if (m_size > 0)
    {
        c = m_pBuffer[--m_size];
        m_pBuffer[m_size] = '\0';
    }

    return c;
}

// Zuweisungsoperator.
CharBuffer& CharBuffer::operator =(const CharBuffer &c)
{
    if (this != &c)
    {
        delete[] m_pBuffer;
        m_size = c.m_size;
        m_maxSize = c.m_maxSize;

        m_pBuffer = new char[m_maxSize];

        for (unsigned int i = 0; i < m_size; ++i)
        {
            m_pBuffer[i] = c.m_pBuffer[i];
        }
    }

    return *this;
}

// Stack ausgeben.
std::ostream& operator <<(std::ostream& out, const CharBuffer &c)
{
    out << c.m_pBuffer;

    return out;
}
```
Sollte irgendwas unklar sein, kannst du dich gerne wieder melden 

Nochwas zur Erklärung: CharBuffer ist ein simpler Stack fester Länge (der wird auch nicht dynamisch länger, sondern ist irgendwann halt voll und dann fliegt dir ne Exception um die Ohren). Hab's kurz getestet, funktioniert anscheinend sogar ;o)


----------



## AchtBit (28. Januar 2010)

So wie ích das sehe wolltest du eine nummerischen Vergleich auf eine Zeichenkette anwenden.

Bin jetzt nicht so drin in C++ aber es sollte eigenlich auch einen Funktion zum String Vergleich geben.

Was sicher bei C++ auch geht ist wenn du 2 reguläre Ausdrücke vergleichst. Damit kannst alle Var Typen für bedingte Vergleiche einsetzten


----------



## bingo88 (28. Januar 2010)

AchtBit schrieb:


> So wie ích das sehe wolltest du eine nummerischen Vergleich auf eine Zeichenkette anwenden.
> 
> Bin jetzt nicht so drin in C++ aber es sollte eigenlich auch einen Funktion zum String Vergleich geben.
> 
> Was sicher bei C++ auch geht ist wenn du 2 reguläre Ausdrücke vergleichst. Damit kannst alle Var Typen für bedingte Vergleiche einsetzten


Du sollst aber nur eine bestimmte Zeit lang Zeit haben, deine Eingabe zu tätigen. Cin und Konsorten sind aber blockierende Funktionen, also muss man das ersteinmal umgehen.
Du kannst dann aber auch nen Stringvergleich über meine CharBuffer-Klasse laufen lassen (man könnte sogar den entsprechenden Operator überladen^^).


----------



## bingo88 (28. Januar 2010)

Ich hab's nochmal etwas verändert. Statt bei vollem Puffer eine Exception zu werfen, werden weitere Eingaben einfach ignoriert.

main.cpp:

```
#include <iostream>

#include <iostream>
#include <time.h>
#include "CharBuffer.h"
#include <conio.h>
#include <windows.h>

using namespace std;

int main(int argc, char *argv[])
{
    int seconds = 5;
    time_t currTime = time(NULL);

    CharBuffer cb(10);

    while ((currTime + seconds) != time(NULL)) {
        if (_kbhit())
        {
            int c = _getch();

            // Enter-Taste
            if (c == '\r')
            {
                break;
            }
            else if (c == '\b')
            {
                // Backspace -> letztes Zeichen entfernen
                cb.pop();
                // Keine Ahnung, ob das besser geht.
                // Normalerweise mache ich so einen Konsolenkram net.
                _putch('\b');
                _putch(' ');
                _putch('\b');
            }

            if (c < '0' || c > '9')
            {
                // Nur Zahlen von 0 bis 9 zulassen.
                continue;
            }

            // Zahl im Puffer sichern
            if (cb.push(c))
            {
                // Zahl anzeigen
                _putch(c);
            }
        }

        // 10ms warten (keine 100% CPU Last erzeugen!)
        Sleep(10);
    }

    _putch('\n');
    //_putch('\r');
    cout << cb << endl;

    char *buff = cb.getBuffer(); // wird automatisch geflusht
    int zahl = atoi(buff);
    delete[] buff; // WICHTIG!!!

    cout << zahl << endl;

    return 0;
}
```
CharBuffer.h:

```
#ifndef CHARBUFFER_H_
#define CHARBUFFER_H_

#include <iostream>

class CharBuffer
{
public:
    CharBuffer(unsigned int maxSize);
    CharBuffer(const CharBuffer &c);
    virtual ~CharBuffer();
    
    bool push(char c);
    char pop();
    void clear();
    char *getBuffer(bool flush = true);
    
    bool isEmpty() const
    {
        return (m_size > 0);
    }
    
    unsigned int size() const
    {
        return m_size;
    }
    
    CharBuffer& operator =(const CharBuffer &c);
    
private:
    char *m_pBuffer;
    unsigned int m_maxSize;
    unsigned int m_size;

    friend std::ostream& operator <<(std::ostream& out, const CharBuffer &c);
};

std::ostream& operator <<(std::ostream& out, const CharBuffer &c);

#endif /* CHARBUFFER_H_ */
```
CharBuffer.cpp:

```
#include "CharBuffer.h"

// Erzeugt einen neuen CharBuffer mit der angegebenen maximalen
// Länge (inlusive Nullterminator).
CharBuffer::CharBuffer(unsigned int maxSize) :
m_maxSize(maxSize), m_size(0)
{
    m_pBuffer = new char[m_maxSize];

    // mit Null-Zeichen initialsieren
    for (unsigned int i = 0; i < m_maxSize; ++i)
    {
        m_pBuffer[i] = '\0';
    }
}

// Kopiert einen CharBuffer.
CharBuffer::CharBuffer(const CharBuffer &c) :
m_maxSize(c.m_maxSize), m_size(c.m_size)
{
    m_pBuffer = new char[m_maxSize];

    for (unsigned int i = 0; i < m_size; ++i)
    {
        m_pBuffer[i] = c.m_pBuffer[i];
    }
}

// Gibt alle Ressourcen wieder frei.
CharBuffer::~CharBuffer()
{
    delete[] m_pBuffer;
}

// Leert den Puffer.
void CharBuffer::clear()
{
    for (unsigned int i = 0; i < m_maxSize; ++i)
    {
        m_pBuffer[i] = '\0';
    }

    m_size = 0;
}

// Ruft den String dieses Buffers ab. Dies ist ein neues Objekt,
// muss also mit delete[] freigemacht werden! Optional kann der
// Puffer geleert werden (flush = true).
char *CharBuffer::getBuffer(bool flush)
{
    char *ret = 0; // alternativ NULL

    if (m_uiSize > 0)
    {
        ret = new char[m_uiSize + 1];

        for (unsigned i = 0; i <= m_uiSize; ++i)
        {
            ret[i] = m_pBuffer[i];
        }

        if (flush)
        {
            clear();
        }
    }

    return ret;
}

// Zeichen auf den Stack legen.
// Gibt true zurück, falls noch Platz war, sonst false.
bool CharBuffer::push(char c)
{
    if (m_size == m_maxSize - 1)
    {
        return false;
    }

    m_pBuffer[m_size] = c;
    ++m_size;

    return true;
}

// Zeichen vom Stack nehmen (Backspace).
char CharBuffer::pop()
{
    char c = '\0';

    if (m_size > 0)
    {
        c = m_pBuffer[--m_size];
        m_pBuffer[m_size] = '\0';
    }

    return c;
}

// Zuweisungsoperator.
CharBuffer& CharBuffer::operator =(const CharBuffer &c)
{
    if (this != &c)
    {
        delete[] m_pBuffer;
        m_size = c.m_size;
        m_maxSize = c.m_maxSize;

        m_pBuffer = new char[m_maxSize];

        for (unsigned int i = 0; i < m_size; ++i)
        {
            m_pBuffer[i] = c.m_pBuffer[i];
        }
    }

    return *this;
}

// Stack ausgeben.
std::ostream& operator <<(std::ostream& out, const CharBuffer &c)
{
    out << c.m_pBuffer;

    return out;
}
```


----------



## Puepue (30. Januar 2010)

Funktioniert wunderbar 
Leider schaffe es nicht einen Cursor an zwei Stellen zu setzen (vermutlich ganz einfach weil es nicht geht) aber ich hab eine andere Möglichkeit gefunden das alles hübsch darzustellen 
Und ich hab mir erlaubt das "break;" rauszunehmen das dürfen wir nämlich nicht verwenden 
Echt Danke !!

Edit:
Achso hatte noch nen Cache drin da wurde ja noch was geschrieben ^^ .. der erste Code funktioniert auf jeden fall das andere les ich mir mal durch....


----------



## bingo88 (30. Januar 2010)

Freut mich, dass ich helfen konnte 

Hab noch nen kleines Fehlerchen bei getBuffer korrigiert (in meinem 2. Code-Post, im 1. ist's vermutlich noch drinnen!).


----------



## Puepue (31. Januar 2010)

Eine Frage ist jetzt noch aufgetaucht, ich eröffne dafür mal nicht direkt nen neuen Thread.. alsoo:

wenn ich ein struct anlege kann ich dazu ja mehrere Objektnamen anlegen, wie hier zum Beispiel Hildegard, Stefan, Miriam:


```
//Definition TSpieler
struct TSpieler
{
	short id;
	char vorname[50];
	char nachname[50];
	int punkte;
	int korrektBeantwortet;
	int falschBeantwortet;
}Hildegard, Stefan, Miriam;
```

Ist es möglich, das dynamisch zu machen?
Wenn ich mal 1 und mal 99 Mitspieler (5, 8, ganz egal) habe:

sowas wie 

```
for (i=0; i < mitspieler; i++)
{
     cin >> vorname;      // Beispielsweise wird eingebeben Otto, Hans, Wurst
}
```

und dann für jeden Mitspieler einen eigenen Objektnamen anfügen, dass das so aussieht:



```
//Definition TSpieler
struct TSpieler
{
	short id;
	char vorname[50];
	char nachname[50];
	int punkte;
	int korrektBeantwortet;
	int falschBeantwortet;
}Otto,Hans,Wurst;
```

damit ich dann nachher auf Otto.punkte zugreifen kann?
Natürlich wär auch sowas wie Spieler1.punkte, Spieler2.punkte  etc. okay


----------



## bingo88 (31. Januar 2010)

Schau dir mal die Klasse Vector aus der STL an. Du kannst auch eine (dynamische) Liste nutzen.

Mögliche Implementierung mit Vector (Pseudocode!):

```
Vector<*TSpieler> spieler;

für jeden Spieler
{
    daten = Spielerdaten erfassen;
    TSpieler *sp = neuer Spieler(daten);
    spieler.push_back(sp);
}

// Am Ende musst du aber alle sp-Objekte wieder löschen, also mit
// ner Schleife alle Elemente löschen (delete). Sonst gibt's Speicherlecks ;o)
```
Auf spieler kannst du dann wie auf ein Array von Zeigern (mit spieler[pos]) zugreifen. Zum Beispiel spieler[0]->id = 26;


----------



## Puepue (31. Januar 2010)

Muss ich da außer <vector> noch irgendwas einbinden? ich bekomme mit der ersten Zeile schon Probleme oder ist das auch schon Pseudocode?
(Ich fühl mich irgendwie mit jeder Frage/Antwort dümmer)

Ich hab noch nie irgendwas mit vector gemacht aber es muss auch irgendwie mit struct gehen denke ich, immerhin hat man uns gesagt wir sollen damit arbeiten


----------



## bingo88 (31. Januar 2010)

Hmm... da sind mir doch ein paar Fehlerchen unterlaufen 
Hab schon länger nicht mehr mit dem Kram zu tun gehabt...


```
#include <iostream>
#include <vector>

using namespace std;

struct TSpieler
{
	short id;
	char vorname[50];
	char nachname[50];
	int punkte;
	int korrektBeantwortet;
	int falschBeantwortet;
};

int main (int argc, char * const argv[]) {
    vector<TSpieler> spieler;
	
	TSpieler sp;

        // Beispiel
        // Das könntest du dann in ner Schleife machen
	sp.id = 0;
	spieler.push_back(sp);
		
    return 0;
}
```
Das müsste sp erstmal funktionieren. Ich bin mir nur grad nicht sicher, ob es mit Zeigern als Vector-Elementen sinnvoller wäre (die müsste man dann allerdings auch wieder löschen...).


----------



## Puepue (5. Februar 2010)

Ich mach das jetzt statisch und soll mir vectoren für das 2.Lehrjahr aufheben aber trotzdem danke


----------



## bingo88 (5. Februar 2010)

Okay, kein Problem. Dafür ist das Forum ja schließlich da 
Wenn du weiter Fragen hast, einfach melden!


----------



## Puepue (8. März 2010)

Hab ne 1 dafür bekommen!!!!!


----------



## bingo88 (9. März 2010)

Na das ist doch super!


----------

